Redis解决并发问题
用setnx替代set命令初始化计数器,这确保了一旦A初始化计数器成功,B就不会再去初始化计数器。
1 | /** |
我们都或多或少遇到过并发问题。家人因为看电视抢遥控器,这就是一种并发;两个孩子争着玩同一个玩具,这也是并发。在每一次“双11”购物节狂欢的背后,都有一群程序员在严阵以待,这不是一位数的并发,而是成千上万级别的并发。
说了什么是并发,接下来将向大家演示如何用Redis处理一个典型的并发问题。我们选择最常见的商品抢购场景,假定我们有100件商品,参与抢购的用户有成千上万,如何确保我们的商品不被多抢了?
聪明的你应该想到了,可以用计数器来控制,每卖出一件商品,计数器加1,当计数器到达100时,我们的商品就卖完了。程序的工作流程如下图。

看起来很完美,但需要通过高并发场景的检验。我们假定有A、B两个进程同时在运行这段程序。
问题1
初始化set计数器:A、B都发现计数器尚未初始化,在A执行“计数器加1”后,B去set计数器,此时计数器的值比正确值少1。(为什么时间差那么大?这在高并发场景中是完全可能存在的)
问题2
计数器加1:A、B都读到计数器的值为99,不满足>=100,两者都抢到了商品,但最终卖掉了101件,显然超卖了。
上面的流程存在两个问题,我们需要对程序流程做一点改进,新的流程如下图。

改进1
用setnx替代set命令初始化计数器,这确保了一旦A初始化计数器成功,B就不会再去初始化计数器。
改进2
先对计数器加1,再判断计数器是否>100,如果是,说明超卖了。这确保了即使A、B同时读到计数器的值为99,都去对计数器加1,两者至少有一个得到的结果>100,不会超卖。
从以上的内容我们学习到,如何用Redis处理一个常见的并发场景,这背后还有更多的技术细节值得我们深入了解,期待在下一篇文章中与大家共同学习。