巧用CAS解决数据并发一致性问题
来源:互联网 发布:比亚迪和特斯拉知乎 编辑:程序博客网 时间:2024/06/08 12:04
缘起:在高并发的分布式环境下,对于数据的查询与修改容易引发一致性问题,本文将分享一种非常简单但有效的优化方法。
一、业务场景
业务场景为,购买商品的过程要对余额进行查询与修改,大致的业务流程如下:
(1)从数据库查询用户现有余额 SELECT money FROM t_yue WHERE uid=$uid,不妨设查询出来的$old_money=100元
(2)业务层实施业务逻辑,比如购买一个80元的商品,并且打九折
if($old_money> 80*0.9) $new_money=$old_money-80*0.9=28
(3)将数据库中的余额进行修改 UPDAtE t_yue SET money=$new_money WHERE uid=$uid
在并发量低的情况下,这个流程没有任何问题,原有金额100元,购买了80元的九折商品(72元),剩余28元。
二、潜在的问题
在分布式环境中,如果并发量很大,这种“查询+修改”的业务很容易出现数据不一致。极限情况下,可能出现这样的异常流程:
(1)业务1和业务2同时查询余额,是100元
(2)业务1和业务2进行逻辑计算,算出各自业务的余额,假设业务1算出的余额是28元,业务2算出的余额是38元
(3)业务1对数据库中的余额先进行修改,设置成28元。
业务2对数据库中的余额后进行修改,设置成38元。
此时异常出现了,原有金额100元,业务1扣除了72元,业务2扣除了62元,最后剩余38元。
三、问题原因
高并发环境下,对同一个数据的并发读(两边都读出余额是100)与并发写(一个写回28,一个写回38)导致的数据一致性问题。
四、原因分析
业务1的写回:原有金额100,这是一个初始状态,写回金额28,理论上只有在原有金额为100的时候才允许写回成功,这一步没问题。
业务2的写回:的原有金额100,这是一个初始状态,写回金额38,理论上只有在原有金额为100的时候才允许写回成功,可实际上,这个时候数据库中的金额已经变为28了,这一步的写操作不应该成功。
五、简易解决方案
在set写回的时候,加上初始状态的条件compare,只有初始状态不变时,才允许set写回成功,这正是大家常说的“Compare And Set”(CAS),是一种常见的降低读写锁冲突,保证数据一致性的方法。
六、业务的升级
业务线使用CAS解决高并发时数据一致性问题,只需要在进行set操作时,compare一下初始值,如果初始值变换,不允许set成功。
对于上文中的业务场景,只需要将“UPDAtEt_yue SET money=$new_money WHERE uid=$uid”升级为
“UPDAtE t_yue SETmoney-=$money WHERE uid=$uid AND money=$old_money”即可。
并发操作发生时:
业务1执行 => UPDAtE t_yue SET money-=72 WHERE uid=$uid AND money=100
业务2执行 => UPDAtE t_yue SET money-=62 WHERE uid=$uid AND money=100
【这两个操作同时进行时,只能有一个执行成功】。
七、怎么判断哪个执行成功,哪个执行失败
set操作,其实无所谓成功或者失败,业务能通过affect rows得知哪个修改没有成功:
执行成功的业务,affect rows为1
执行失败的业务,affect rows为0
八、总结
高并发“查询并修改”的场景,可以用CAS(Compare and Set)的方式解决数据一致性问题。对应到业务,即在set的时候,加上初始条件的比对。
- 巧用CAS解决数据并发一致性问题
- 巧用CAS解决数据一致性问题
- 巧用CAS解决数据一致性问题
- 巧用CAS解决数据一致性问题
- 并发一致性问题
- 数据并发和一致性介绍
- 转:巧用CAS解决数据一致性问题
- 【4】Java并发编程:多线程中的缓存一致性和CAS
- 并发操作的一致性问题
- 一致性控制——解决线程间数据传递问题
- 如何解决分布式系统数据事务一致性问题
- 如何解决分布式系统数据事务一致性问题
- CAS操作实现并发的优势、以及实现一个无锁队列、怎样解决ABA 问题
- Oracle数据并发性和一致性保护
- Oracle数据并发和一致性(English)
- 数据库并发操作的一致性问题
- 数据库并发操作的一致性问题
- 并发编程cas的aba问题
- 【DOM 编程艺术】3.4 节点
- tomcat 与 nginx,apache的区别
- 表单标签2
- java网络编程--URLEncode和URLDecoder
- hibernate_检索(查询)简介
- 巧用CAS解决数据并发一致性问题
- FPGA时序分析
- 嵌入式目标检测--Fast YOLO: A Fast You Only Look Once System for Real-time Embedded Object Detection
- Failed to allocate a 38189038 byte allocation with 16777216 free bytes and 20MB until OOM
- Qt之QuaZIP(zip压缩/解压缩)
- Oracle中Merge into用法总结
- python实现简单爬虫功能
- thinkphp在Nginx下使用PATHINFO模式显示no input file specified的解决方法
- 设计模式C++实现(2)——策略模式