Redis的常用场景

2020-12-27  本文已影响0人  Lnstark

一、分布式锁

二、队列

public class RedisDelayingQueue<T> {
    static class TaskItem<T> {
        public String id;
        public T msg;
    }
    // fastjson 序列化对象中存在 generic 类型时,需要使用 TypeReference
    private Type TaskType = new TypeReference<TaskItem<T>>() { }.getType();
    private Jedis jedis;
    private String queueKey;
    public RedisDelayingQueue(Jedis jedis, String queueKey) {
        this.jedis = jedis;
        this.queueKey = queueKey;
    }
    public void delay(T msg) {
        TaskItem task = new TaskItem();
        task.id = UUID.randomUUID().toString();  // 分配唯一的 uuid
        task.msg = msg;
        String s = JSON.toJSONString(task);  // fastjson 序列化
        jedis.zadd(queueKey, System.currentTimeMillis() + 5000, s);  // 塞入延时队列 ,5s 后再试
    }
    public void loop() {
        while (!Thread.interrupted()) {
            // 只取一条
            Set values = jedis.zrangeByScore(queueKey, 0, System.currentTimeMillis(), 0, 1);
            if (values.isEmpty()) {
                try {
                    Thread.sleep(500);  // 歇会继续
                }
                catch (InterruptedException e) {
                    break;
                }
                continue;
            }
            String s = values.iterator().next();
            if (jedis.zrem(queueKey, s) > 0) {  // 抢到了
                TaskItem task = JSON.parseObject(s, TaskType);  // fastjson 反序列化
                this.handleMsg(task.msg);
            }
        }
    }
    public void handleMsg(T msg) {
        System.out.println(msg);
    }
    public static void main(String[] args) {
        Jedis jedis = new Jedis();
        RedisDelayingQueue queue = new RedisDelayingQueue<>(jedis, "q-demo");
        Thread producer = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    queue.delay("codehole" + i);
                }
            }
        };
        Thread consumer = new Thread() {
            public void run() {
                queue.loop();
            }
        };
        producer.start();
        consumer.start();
        try {
            producer.join();
            Thread.sleep(6000);
            consumer.interrupt();
            consumer.join();
        }
        catch (InterruptedException e) {
        }
    }
} 

三、HyperLogLog

HyperLogLog可以用来做一个非精确的计数。例如要统计一个页面的访问用户数,一个用户算一次。如果直接用set来存用户id的话未免太占内存。我们可以用HyperLogLog来实现,命令pfadd添加元素,命令pfcount获取计数。

四、布隆过滤器

五、GeoHash

GeoHash可以用来保存地理信息,计算距离,或者查询附近的单位。指令有geoadd、geodist(计算距离)、geopos(获取元素经纬度)、geohash (获取元素hash值),georadiusbymember(获取某元素附近的元素)、georadius(获取某点附近的元素)。

六、漏斗限流

可以用来限制用户评论等。

CL.THROTTLE user123 15 30 60 1
               ▲     ▲  ▲  ▲ ▲
               |     |  |  | └───── apply 1 token (default if omitted)
               |     |  └──┴─────── 30 tokens / 60 seconds
               |     └───────────── 15 max_burst
               └─────────────────── key "user123"

# 执行命令CL.THROTTLE user123 15 30 60 1
127.0.0.1:6379> CL.THROTTLE user123 15 30 60 1
1) (integer) 0   # 0 表示允许,1表示拒绝
2) (integer) 16  # 漏斗总容量 就是 15+1得到的。
3) (integer) 15  # 漏斗剩余空间,取得了一个所以剩下15
4) (integer) -1  # 如果拒绝了,需要多长时间后再试(漏斗有空间了,单位秒)
5) (integer) 2  # 表示多久后令牌桶中的令牌会存满(单位秒)

参考资料来源:《Redis 深度历险: 核心原理和应用实践》

上一篇 下一篇

猜你喜欢

热点阅读