使用 Redis 的 Lua 脚本实现原子性累加操作,避免并发竞争。代码示例: local key = KEYS[1] local delta = tonumber(ARGV[1]) local current = redis.call('GET', key) if current == false then current = 0 end current = current + delta redis.call('SET', key, current) return current
方案一:Lua脚本原子操作
Redis Lua脚本是原子执行的,可以将GET、SET操作封装到一个脚本中执行,这样即使在高并发情况下,也能保证累加操作的原子性,避免数据不一致。脚本内容如上所示,通过EVAL命令执行。
方案二:使用INCRBY命令
Redis自带的INCRBY命令就是原子累加操作,直接使用INCRBY key increment即可,无需担心并发问题,它内部已经处理好了原子性,高并发场景下性能极佳。
方案三:分布式锁优化
如果必须用GET+SET,可以结合Redisson分布式锁,先获取锁,然后GET累加SET,最后释放锁。这样能保证同一时间只有一个线程在操作key,避免脏读和丢失更新。
方案四:管道+事务
使用Redis事务MULTI/EXEC结合管道,可以批量提交GET和SET,但事务不保证原子性,还是建议用Lua或INCRBY。对于高并发,INCRBY是最优。
方案五:哨兵或集群模式下优化
在Redis Cluster中,使用HASH TAG确保累加key落在同一槽位,然后用INCRBY。性能测试显示,单机QPS可达10万+,集群更高。
方案六:Watch+Optimistic锁
使用WATCH key,MULTI,然后GETSET,EXEC。如果EXEC失败重试。这样是乐观锁,适用于读多写少场景,高并发下避免锁开销。
FAQ
Q: INCRBY和Lua脚本哪个性能更好?
A: INCRBY更快,因为是内置命令,Lua脚本稍慢但更灵活。
Q: 高并发下INCRBY会丢失数据吗?
A: 不会,Redis单线程模型保证原子性。
Q: 分布式环境下怎么处理?
A: 用Redisson客户端的原子LongAdder,或Lua脚本。
Q: 累加到亿级数值性能如何?
A: 无影响,Redis整数支持到2^63-1。