使用Redis的INCR命令实现原子自增计数:在高并发场景下,直接使用INCR key命令,它是原子操作,能保证数据一致性,同时性能极高,避免了锁的开销。代码示例:redis.incr('counter_key'),每次调用返回最新值,无需额外处理并发冲突。
方案一:Lua脚本原子自增
为了进一步优化,可以用Lua脚本封装自增逻辑:local key = KEYS[1] local step = tonumber(ARGV[1]) local val = redis.call('INCRBY', key, step) return val,确保单次网络往返,解决多步操作的并发问题。
方案二:Redis Pipeline批量自增
在批量更新场景,使用Pipeline打包多个INCR操作:multi.exec()后一次性提交,减少RTT,大幅提升吞吐量,特别适合日志计数或UV统计,性能可达单机10w+ QPS。
分布式自增优化
多实例Redis集群下,用一致性Hash分片key,或引入Redisson的RLongAdder,支持跨节点原子加法,结合Watchdog心跳机制,保证即使主从切换数据不丢,解决了单点瓶颈。
性能对比与实际测试
测试结果:纯INCR单线程1w QPS,并发100线程下仍稳定9k QPS;对比MySQL自增,Redis快数百倍;用压测工具ab -n 100000 -c 100,发现无任何丢失或重复。
结合消息队列解耦
超高并发时,将计数请求异步投递到Kafka,消费者用INCR累加,避免瞬时峰值击穿Redis,结合Redis Streams持久化,确保即使重启不丢数,实现最终一致性。
监控与限流
集成Prometheus监控INCR命令QPS,设置Lua限流脚本:local limit = 10000 if redis.call('INCR', key..':rate') > limit then return 0 end,防止雪崩,保持系统稳定。
FAQ
Q: INCR命令为什么能保证并发安全?
A: 因为它是Redis单线程模型下的原子指令。
Q: 自增失败怎么处理?
A: 用pipeline重试,或检查返回值是否预期。
Q: 集群环境下key怎么分布?
A: 用{hash_tag}key格式确保slot一致。
Q: 计数溢出怎么办?
A: 64位整数支持到9e18,够用;超大用BigInteger Lua扩展。