《并发扣款,如何保证数据的一致性?》文章的核心观点是:使用CAS乐观锁,在写回余额时加入旧余额的对比,可以在不影响吞吐量的情况下保证余额的一致性。文中有不少朋友留言询问是否可以将余额放在reids中,利用redis的事务性来扣取余额。今天,让我简单谈谈这个问题。Redis是如何实现事务性的?本质也是乐观锁。在redis客户端执行:$money=GETkey$money=$money-$diffSETkey$money并发量大的时候会遇到《并发扣款,如何保证数据的一致性?》描述的并发一致性问题。redis的WATCH和EXEC可以提供一种类似事务的机制:WATCH观察key是否发生变化。如果提交时更改了key,EXEC会返回null,表示交易失败。=GETkey$money=$money-$diffMULTISETkey$moneyEXECWATCH之后EXEC执行之前,如果key的值发生变化,EXEC会失败。为什么redis的WATCH可以保证事务性,本质上是使用了乐观锁CAS机制。大多数情况下,不同的redisclient会访问到不同的key,所以WATCH发生碰撞的概率会比较小。在秒杀的业务场景下,即使使用了WATCH,调用方仍然需要重试。画外音:《同样是高并发,QQ/微博/12306的架构难度一样吗?》提到,keyaccess会过滤uid属性,所以可以支持高并发。在CAS机制上,redis相比mysql并没有额外的优势。redis的高性能是由于redis内存访问和mysql数据存储的不同造成的。内存访问的缺点是数据“易失”,如果重启,数据可能会丢失。当然redis也可以固化数据,但是如果每次都刷盘,redis的性能会下降很多。画外音:每个工具都有自己适用的场景,不适合把缓存当作数据库使用。最后,redis使用单线程避免了物理锁,但是mysql多线程也有多线程并发的优势。旁白:各有利弊。结论:可以使用redis的事务性扣余额,但是在CAS机制上比mysql没有优势。高性能是由于其内存存储,副作用是数据丢失的风险。任何倒闭的架构设计都是耍流氓。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
