巧用CAS解决数据一致性问题

开发 开发工具
在高并发的分布式环境下,对于数据的查询与修改容易引发一致性问题,本文将分享一种非常简单但有效的优化方法。

[[177350]]

在高并发的分布式环境下,对于数据的查询与修改容易引发一致性问题,本文将分享一种非常简单但有效的优化方法。

一、业务场景

业务场景为,购买商品的过程要对余额进行查询与修改,大致的业务流程如下:

(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=$new_money WHERE uid=$uid AND money=$old_money”即可。

并发操作发生时:

业务1执行 => UPDAtE t_yue SET money=28 WHERE uid=$uid AND money=100

业务2执行 => UPDAtE t_yue SET money=38 WHERE uid=$uid AND money=100

【这两个操作同时进行时,只能有一个执行成功】。

七、怎么判断哪个执行成功,哪个执行失败

set操作,其实无所谓成功或者失败,业务能通过affect rows得知哪个修改没有成功:

执行成功的业务,affect rows为1

执行失败的业务,affect rows为0

八、总结

 

高并发“查询并修改”的场景,可以用CAS(Compare and Set)的方式解决数据一致性问题。对应到业务,即在set的时候,加上初始条件的比对。

【本文为51CTO专栏作者“58沈剑”原创稿件,转载请联系原作者】

责任编辑:赵宁宁 来源: 架构师之路
相关推荐

2022-06-21 21:47:13

数据系统

2023-08-01 07:42:33

Redis数据项目

2012-09-24 09:35:42

分布式系统

2019-05-27 09:00:00

苏宁智慧零售平台数据库

2022-05-31 08:37:59

RedisMySQL数据一致性

2024-04-11 13:45:14

Redis数据库缓存

2022-09-06 15:30:20

缓存一致性

2024-11-14 07:10:00

2022-08-11 07:55:05

数据库Mysql

2018-10-25 14:40:23

分布式数据数据不一致

2023-09-07 08:11:24

Redis管道机制

2020-09-04 06:32:08

缓存数据库接口

2023-06-29 08:00:59

redis数据MySQL

2021-12-05 21:06:27

软件

2021-10-18 10:30:59

流计算阿里云

2024-08-20 16:13:52

2009-06-18 09:18:08

Oracle检索数据数据一致性事务恢复

2023-12-01 13:51:21

数据一致性数据库

2023-05-26 07:34:50

RedisMySQL缓存

2022-02-17 21:04:27

数据库MysqlRedis
点赞
收藏

51CTO技术栈公众号