高频面试Redis之签到、限流
1、简介
面试环节,面试官往往会结合一些实际的场景,下面通过分析redis的签到、限流两个最常见的场景。
2、签到
位图,本质string,可理解为byte数组,利用 0、1 标识是否签到。节约内存空间(46字节365天)
// 按月签到 setbit key offset(偏移量,0:1号,1:2号) value(1:签到;0:未签到) setbit u:sign:1000:202101 0 1 // 1月1号签到 setbit u:sign:1000:202101 1 1 // 1月2号签到 bitcount u:sign:1000:202101 // 统计1月份签到总次数
3、滑动窗口限流
假设1分钟内,限定访问60次。使用zset的score值维护一个时间窗口,对于每次新的请求时间窗口都向前滑动一下,然后判断窗口中的元素个数,如果大于60个,则不能访问业务。member字段必须保证唯一性,可以考虑使用时间戳。
// period 时间周期,例如 60秒 // maxCount 时间周期内最大请求数 public boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) { String key = String.format("hist:%s:%s", userId, actionKey); long now = System.currentTimeMillis(); Jedis jedis = jedisPool.getResource(); jedis.zadd(key, now, now + ""); // 维护窗口,清理窗口外的数据 // zremrangeByScore --> 移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。 jedis.zremrangeByScore(key, 0, now - period * 1000); Long count = jedis.zcard(key); jedis.expire(key, period + 1); return count <= maxCount; }
3、漏斗限流
借助 redis-cell(Redis 4.0) 模块的 cl.throttle 指令实现。
// 参数解释 // 15 capacity 代表漏洞容量 // 30 60 组合选项,代表漏水速率 oprations / seconds // 该表达式代表了,漏斗初始容量为 15,即默认可以请求15次;之后受漏斗漏水速率影响,60秒内只能请求30次 cl.throttle liyanchao:reply 15 30 60
4、Lua脚本限流
Lua脚本结合incr命令:
// 10秒内访问3次 -- ./redis-cli --eval ratelimiting.lua rate.limitingl:127.0.0.1 , 10 3 -- 通过逗号来分割key和arg,注意,这个逗号必须前后要有空格 -- rate.limitingl + 1 local times = redis.call(incr,keyS[1]) -- 第一次访问的时候加上过期时间10秒(10秒过后从新计数) if times == 1 then redis.call(expire,keyS[1], ARGV[1]) end -- 注意,从redis进来的默认为字符串,lua同种数据类型只能和同种数据类型比较 if times > tonumber(ARGV[2]) then return 0 end return 1
上一篇:
Java基础知识总结(2021版)
下一篇:
判断数组是否是二叉搜索树的后序遍历序列