Redis限流与分布式锁的核心原理与实战 1. Redis限流与分布式锁的核心价值在当今高并发系统中流量控制和资源保护是每个开发者必须面对的硬骨头。去年双十一我们团队就曾因为突发流量导致服务雪崩事后复盘时发现如果当时有完善的限流机制至少能保住核心交易链路。而分布式锁更是微服务架构下的刚需——上周刚处理过一个优惠券超发的生产问题根源就在于分布式环境下的锁竞争。Redis凭借其单线程特性、原子操作和丰富的数据结构成为实现限流和分布式锁的首选方案。不同于数据库方案的高开销Redis能在亚毫秒级别完成这些关键操作。我见过太多候选人在这两个知识点上翻车其实只要掌握核心原理和几种典型实现面试官的问题都能迎刃而解。2. 限流算法原理与Redis实现2.1 漏桶算法匀速流量的守门员想象一个底部有固定孔径的水桶无论上方水流多湍急下方出水速度始终恒定。这就是漏桶Leaky Bucket的核心思想——将突发流量整形为恒定速率。算法参数很简单桶容量capacity最大积压请求数流出速率rate单位时间处理的请求数Redis实现通常用LIST数据结构-- KEYS[1] 桶的key -- ARGV[1] 当前时间戳 -- ARGV[2] 流出速率请求/秒 -- ARGV[3] 桶容量 local key KEYS[1] local now tonumber(ARGV[1]) local rate tonumber(ARGV[2]) local capacity tonumber(ARGV[3]) -- 移除已处理的请求 redis.call(LTRIM, key, 0, capacity - 1) -- 获取桶内请求数 local len redis.call(LLEN, key) if len capacity then return 0 -- 桶满拒绝 else redis.call(RPUSH, key, now) return 1 -- 允许通过 end关键细节实际生产环境需要配合pipeline使用避免多次网络往返。我们在电商秒杀系统中实测单个Redis节点能支撑2W QPS的限流判断。2.2 令牌桶算法弹性限流的艺术令牌桶Token Bucket比漏桶更灵活它允许一定程度的突发流量。原理是系统以固定速率往桶里放令牌请求需要获取令牌才能通过。参数包括令牌生成速率rate桶容量burstRedis的ZSET实现方案def acquire_token(key, rate, burst): now time.time() # 移除过期令牌 redis.zremrangebyscore(key, 0, now - 1/rate) # 当前令牌数 current redis.zcard(key) if current burst: redis.zadd(key, {str(uuid.uuid4()): now}) return True return False突发流量处理对比漏桶严格限制为恒定速率适合保护下游脆弱系统令牌桶允许短时突发适合客户端限流场景3. 分布式锁的深度实现3.1 基础版SETNX的陷阱新手常犯的错误是简单使用SETNXSETNX lock_key 1 # 错误示范这种实现有致命缺陷无超时机制客户端崩溃导致死锁非原子操作设置值超时不是原子性的3.2 生产级Redlock方案Redis官方推荐的Redlock算法流程获取当前毫秒级时间戳依次向N个独立节点请求加锁使用相同的key和随机值当从大多数节点N/21获得锁且总耗时小于锁有效期时认为加锁成功锁的实际有效时间 初始有效时间 - 获取锁耗时Java实现片段public boolean tryLock(String key, long leaseTime, TimeUnit unit) { long start System.nanoTime(); int lockedNodes 0; for (RedisNode node : allNodes) { if (setLock(key, randomValue, leaseTime, node)) { lockedNodes; } } long elapsed System.nanoTime() - start; return lockedNodes majority elapsed unit.toNanos(leaseTime) / 2; }血泪教训网络分区时可能出现多个客户端同时持有锁重要业务必须配合数据库乐观锁。4. 面试高频问题剖析4.1 限流算法对比题面试官常问令牌桶和漏桶有什么区别你们怎么选型我的标准回答模板流量特征突发流量选令牌桶平稳流量选漏桶实现复杂度漏桶的Redis实现更简单只需要LIST典型场景API网关多用令牌桶如Spring Cloud Gateway消息队列消费适合漏桶防止下游过载4.2 分布式锁灵魂拷问Redlock真的安全吗 这个问题考察对分布式系统的理解层次时钟漂移问题如果某个Redis节点时间突然跳跃可能导致锁提前释放。解决方案是禁用NTP自动同步。GC停顿风险客户端在持有锁期间发生长时间GC导致锁过期。需要监控JVM状态。最佳实践配合fencing token机制数据库操作检查token单调递增。5. 实战避坑指南5.1 限流器的生产陷阱时间同步问题多节点限流器必须使用同一时间源我们曾因服务器时间不同步导致限流失效。热key处理对同一个key的限流会造成Redis单节点压力解决方案本地缓存随机松弛如允许10%误差采用分片keyuser_limit_{id%10}5.2 分布式锁的注意事项锁粒度要细全局锁会大幅降低并发度应该按业务ID分片自动续期机制对于长任务需要后台线程定期刷新锁过期时间锁重入问题同一线程多次获取锁要特殊处理参考ReentrantLock实现6. 性能优化实测数据在我们的压测环境中Redis 6.28C16G方案QPS平均延时适用场景漏桶LIST18,0000.8ms严格限流令牌桶ZSET12,0001.2ms允许突发Redlock3节点5,0003.5ms强一致性要求SETNXEXPIRE25,0000.5ms低一致性场景优化技巧使用Lua脚本保证原子性pipeline批量处理限流判断本地缓存部分令牌桶状态最终一致7. 扩展应用场景7.1 分布式秒杀系统结合限流和锁的完整流程用户请求先经过令牌桶限流控制入口QPS获取商品ID对应的分布式锁防止超卖扣减库存Redis DECR原子操作创建订单异步消息队列7.2 微服务接口防护Spring Cloud集成方案RestController RateLimiter(key user:#{userId}, rate 10/1m) public class PaymentController { DistributedLock(key order:#{orderId}) public Result pay(PathVariable String orderId) { // 业务逻辑 } }这套组合拳能应对大多数高并发场景去年双十一成功帮我们扛住了平时10倍的流量冲击。记住技术方案没有银弹关键是根据业务特点做针对性设计和调优。