Redis并发冲突怎么破?聊聊那些解锁潜力的小技巧和思路
- 问答
- 2026-01-18 11:01:02
- 3
当很多人同时去修改Redis里的同一个数据时,麻烦就来了,想象一下,一个热门商品就剩最后一件库存,你和另一个人同时点击了“立即购买”,你们两个的请求几乎同时到达服务器,服务器去Redis里查,都看到库存是1,都觉得“有货!”,然后都执行了扣减库存的操作,结果就是,库存变成了负数,一件商品卖给了两个人,这就是典型的并发冲突,也叫“超卖”问题。
那怎么办呢?别急,有几个非常实用的小技巧和思路可以帮你化解这场“争夺战”。
第一招:加把“锁”,让操作排排队
这是最直接能想到的办法,既然大家一窝蜂上来会乱,那就让他们排队,一个一个来,在Redis里,我们可以用“分布式锁”来实现。
就是谁想修改这个库存数据,必须先拿到一把专门为这个商品准备的“钥匙”(锁),拿到钥匙的人才能进行“查询-判断-扣减”这一系列操作,操作完了再把钥匙还给Redis,后面的人发现钥匙已经被拿走了,就只能等着或者放弃。

根据Redis官方文档的建议,实现一个靠谱的分布式锁,最好使用SET命令的NX(不存在才设置)和PX(设置过期时间)选项一起用。SET lock:product_123 my_unique_value NX PX 10000,这行命令的意思是,只有名为lock:product_123的锁不存在时,我才能设置它,并且给它10秒后自动过期的保险机制,里面的my_unique_value最好是一个唯一值(比如UUID),这样在释放锁的时候可以核对一下,避免不小心把别人持有的锁给删了。
这种方法效果立竿见影,能保证强一致性,但代价是,加了锁就等于让并行操作变成了串行,可能会稍微影响一些性能,尤其是在高并发场景下,等待锁的线程会增多。
第二招:让Redis“原子”地完成任务
加锁有点像“管理”,我们能不能从“根源”上解决问题呢?答案是肯定的,那就是充分利用Redis单线程和原子操作的特性。

Redis是单线程处理命令的,这意味着它的每个命令在执行时都是不可分割的(原子性的),我们不应该把“查库存”和“减库存”这两个操作分开发给Redis,而应该用一个命令完成所有事情。
最强大的武器就是Lua脚本,你可以把一整段复杂的业务逻辑(判断库存是否大于0,如果大于0则扣减,否则返回失败)写成一个Lua脚本,然后一次性发送给Redis执行,对于Redis来说,整个脚本的执行是原子性的,在执行过程中不会被其他命令打断,这样就完美地避免了在“判断”和“扣减”之间的微小时间差里被别的请求插队。
除了Lua脚本,一些特定的Redis命令本身也能帮上忙,扣减库存可以直接用DECR或DECRBY命令,它们会原子性地将值减一或减去指定数量,虽然单纯减可能会减到负数,但我们可以结合Lua脚本先判断再减,做到万无一失。
第三招:换个思路,“乐观”地处理冲突

前面两招都比较“悲观”,默认大家会抢,所以要么加锁,要么原子操作,还有一种“乐观”的思路,它假设冲突不经常发生,但万一发生了也能妥善处理。
这有点像软件版本控制,我们可以给每个关键的数据附加一个版本号,初始库存数据是 {stock: 10, version: 1}。
- 线程A和线程B同时来读取数据,都拿到了版本号1。
- 线程A要扣减库存,它在更新时会给Redis一个命令:“只有当版本号还是1的时候,才把库存减1,并且把版本号更新为2”。
- 如果线程A成功执行了,那么数据版本就变成了2。
- 紧接着,线程B也试图用版本号1的条件去更新,这时Redis会发现当前版本号已经是2了,条件不成立,更新失败,线程B就知道在自己操作期间数据已经被别人改过了,它可以选择重新读取最新数据(版本2),然后重试自己的业务逻辑。
在Redis中,可以用WATCH命令配合事务(MULTI/EXEC)来实现这种乐观锁。WATCH会监视一个或多个键,如果在事务执行前这些键被其他客户端修改了,那么整个事务都会执行失败。
这种方法在冲突真的不频繁的场景下性能很好,因为不需要真正加锁,但如果冲突很频繁,大量请求会失败重试,性能反而可能下降。
总结一下
面对Redis并发冲突,没有一种方法是万能的,关键看你的具体场景:
- 追求强一致性,不怕轻微性能损耗:用分布式锁,简单粗暴有效。
- 追求极致性能,逻辑复杂:用Lua脚本,利用原子性从根源解决问题。
- 冲突发生概率低,想避免锁的开销:可以尝试乐观锁,失败后重试。
在实际项目中,Lua脚本和分布式锁的使用非常广泛,有时候甚至会组合使用,比如用分布式锁保证宏观业务流程,在锁内再用Lua脚本处理精细的数据操作,理解这几种思路的优缺点,就能在面对并发问题时,找到最适合自己的那把“钥匙”。
本文由凤伟才于2026-01-18发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/82997.html
