外观
一句话答案
频繁增删导致 jemalloc 内存碎片,mem_fragmentation_ratio > 1.5 需关注,Redis 4.0+ 支持自动碎片整理。
核心要点
四种限流算法对比:
1. 固定窗口(Fixed Window)
每个固定时间窗口(如每分钟)统计请求数,超过阈值拒绝
Redis 实现:
key = "rate_limit:{userId}:{minute}"
INCR key # 计数 +1
EXPIRE key 60 # 60s 后窗口过期
缺点:窗口边界问题:
0:59 发 100 个请求,1:01 发 100 个请求
这 2s 内共 200 个请求(远超限流阈值),但两个窗口各 100 个,都不超限2. 滑动窗口(Sliding Window)
以当前时间为右边界,往前推时间窗口,更准确
Redis 实现(ZSet):
key = "rate_limit:{userId}"
score = 当前时间戳(毫秒)
member = requestId(唯一)
ZADD key currentTime requestId # 记录请求
ZREMRANGEBYSCORE key 0 (currentTime - windowSize) # 删除窗口外的请求
count = ZCARD key # 统计窗口内的请求数
if count > limit: 拒绝请求
优点:无窗口边界问题,精确
缺点:内存占用较高(需存储每次请求)3. 漏桶(Leaky Bucket)
请求进入桶,桶以固定速率漏水(处理请求)
桶满则溢出(拒绝新请求)
特点:强制平滑输出(固定速率处理)
适用:有严格速率要求的输出(如消息发送、API 调用)
缺点:无法应对突发流量(固定速率,无法加速)4. 令牌桶(Token Bucket)
令牌桶以固定速率生产令牌
每个请求消耗一个令牌,没有令牌则拒绝
桶有容量上限(支持短时突发)
特点:允许突发流量(桶里有积累的令牌)
适用:允许一定突发的 API 限流
实现:Guava RateLimiter、Redisson RRateLimiter
Redis 实现(Token Bucket):
lua 脚本原子执行:
local tokens = redis.call('get', key) or capacity
local now = tonumber(ARGV[1])
local lastTime = redis.call('get', key..':time') or now
-- 根据时间差补充令牌
local newTokens = tokens + (now - lastTime) * rate
newTokens = math.min(newTokens, capacity)
if newTokens >= 1 then
redis.call('set', key, newTokens - 1)
return 1 -- 允许
else
return 0 -- 拒绝实际生产使用 Lua 脚本保证原子性:
lua
-- 固定窗口限流(Lua,原子执行)
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('incr', key))
if current == 1 then
redis.call('expire', key, ARGV[2]) -- 第一次设置过期时间
end
if current > limit then
return 0 -- 超出限制
else
return 1 -- 允许通过
end文档完
复习建议:
- 缓存三件套(Q10)是必背题,穿透/击穿/雪崩的定义、场景、解决方案要对应清晰,不能混淆
- Redisson 加锁流程(Q19)中 Lua 脚本的逻辑要能口述:先判断是否存在 → 不存在则 hset + pexpire → 存在且是自己则 hincrby(重入)→ 否则返回剩余 TTL
- 缓存一致性(Q22)要说清楚"先更新DB再删除Cache"的原因,以及为什么是"删除"而不是"更新",这是面试官最爱追问的点
- ZSet 底层(Q3)一定要说"skiplist + hashtable 双结构",一个负责有序查询,一个负责 O(1) 查 score,说出两个原因加分明显
- 集群架构(Q25-Q31)要能说清三种部署模式的选型决策,Sentinel 的 SDOWN/ODOWN 两阶段判断,Cluster 的 16384 slot + MOVED/ASK 两种重定向的区别
追问与易错
追问方向:
- 碎片率太低说明什么?
- 自动碎片整理影响?
- 什么操作容易导致碎片?
易错点:
- ❌ 碎片率高就有问题——1.0-1.5 正常
- ❌ 重启是唯一方案——4.0+ 有自动整理
💡 记忆锚点
内存碎片 = 停车场空位:频繁进出导致车位东一个西一个(碎片),明明有空位却停不下大车。碎片率(mem_fragmentation_ratio)超1.5就该整理车位了,Redis 4.0+自带代客泊车服务(自动碎片整理)。