【list】

  • 栈:lpush + lpop
  • 队列:lpush + rpop
  • 消息队列:lpush + brpop
  • 有限列表:lpush + ltrim

    【list】List部分元素过期

    在list中的每个元素用单独的kv存储,在kv上设置过期时间。list中只保存元素的key。

【set】

  • 差集:sdiff
  • 交集:sinter
  • 并集:sunion

image.png

统计

【String,BitMap】使用 bitmap 实现用户上线次数统计

基于Redis位图实现系统用户登录统计 - BNDong - 博客园
【SETBIT/GETBIT/BITCOUNT/BITOP OR】

方法一【按人统计,一人一个key】

可求每个人的登录情况
设置用户1001,2017-10-25登录:SETBIT loginLog_2017-10_client_1001 25 1
获取用户1001,2017-10-25是否登录:GETBIT loginLog_2017-10_client_1001 25
获取用户1001,2017-10月是否登录:BITCOUNT loginLog_2017-10_client_1001
获取用户1001,2017-10/9/7月是否登录:BITOP OR stat loginLog_2017-10_client_1001 loginLog_2017-09_client_1001 loginLog_2017-07_client_1001…

方法二【按天统计,一天一个key】

可求按时间统计的人数
面试官: Redis 如何存储和计算一亿用户的活跃度 - V2EX
1 0000 0000/8/1024/1024=11.92M 每天
设置用户1001,2017-10-25登录:SETBIT 2017-10-25 1001 1
获取用户1001,2017-10-25是否登录:GETBIT 2017-10-25 1001
统计某一天的所有的活跃用户数:bitcount 2017-10-25
求出了 2019-01-01 到 2019-01-05 这段时间内的活跃用户数bitop or result 2019-01-01 2019-01-02 2019-01-03 2019-01-04 2019-01-05

bitmap也可以做页面访问记录【做活动会用到】

【zset】使用 Redis 统计在线用户人数

使用 Redis 统计在线用户人数 - 笑笑别人 - 博客园
image.png
关于用 Redis 做在线人数统计 - V2EX

【HyperLogLog】大概统计页面访问

错误率0.81%
image.png

限流

【zset】简单限流

限流需求中存在一个滑动时间窗口

【zadd添加,zremrangebyscore 删除过期,zcard统计现存】
  1. public class SimpleRateLimiter {
  2. private Jedis jedis;
  3. public SimpleRateLimiter(Jedis jedis) {
  4. this.jedis = jedis;
  5. }
  6. public Boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) {
  7. String key = String.format("hist:%s:%s", userId, actionKey);
  8. long nowTs = System.currentTimeMillis();
  9. //pipeline就可以充当这种“批处理”的工具,主要是TCP连接中减少了“交互往返”的时间。
  10. Pipeline pipe = jedis.pipelined();
  11. pipe.multi();
  12. pipe.zadd(key, nowTs, "" + nowTs);
  13. //删除过期
  14. //设置过期 还用删除么?
  15. pipe.zremrangeByScore(key, 0, nowTs - period * 1000);
  16. //删除之后统计数量
  17. Response<long> count = pipe.zcard(key);
  18. //设置过期时间
  19. // 设置zset的过期时间,避免冷用户持续占用内存
  20. //过期时间应该等于时间窗口长度,多宽限出1S
  21. pipe.expire(key, period + 1);
  22. pipe.exec();
  23. pipe.close();
  24. return count.get() <= maxCount;
  25. }
  26. public static void main(String[] args) {
  27. Jedis jedis = new Jedis();
  28. SimpleRateLimiter limiter = new SimpleRateLimiter(jedis);
  29. for (int i=0;i<20;i++) {
  30. System.out.println(limiter.isActionAllowed("laoqian", "reply", 60, 5));
  31. }
  32. }
  33. }

【Redis-Cell】漏斗限流Redis-Cell

Redis 4.0 提供了一个限流 Redis 模块,它叫 redis-cell。
https://github.com/brandur/redis-cell

文章阅读量【同步数据库】

关于高并发下的阅读量,点赞量,评论量的实现方案总结 - 为何不可1995的个人空间 - OSCHINA - 中文开源技术交流社区

  1. 用缓存,定期同步
  2. 用hash,直接在hash上操作,定期同步

    分布式锁

    SET lock.foo 1 EX NX
    1. 注意要设置过期时间
    2. 解锁要验证value相等【要用lua脚本】
    image.png

    redisson

    Redisson 分布式锁实现之源码篇 → 为什么推荐用 Redisson 客户端 - 云+社区 - 腾讯云

    redisson分布式锁为什么用hash

    为了实现锁的可重入
    image.png

    续锁

    定时任务实现锁续期

    订阅

    普通情况:
    获取锁失败订阅锁channel,阻塞。锁释放会唤醒订阅线程。

意外终止,来不及发布订阅情况:
超时机制:
image.png

集群分布式锁算法RedLock

在各节点分别加锁,锁一半以上的获取锁。

问题:如果一个节点已经加锁,然后他挂了。他的slaveB被sentinel拉起当master。B中没有锁内容。怎么办。
答:延迟重启。加入锁的有效时间是30s,那就30s之后再将slave变为master。
只能通过redlock解决。

redlock问题

redlock依赖时钟,时钟回拨,一个redis提前结束,会造成两个同时持有锁。
Redis RedLock 完美的分布式锁么? - 掘金