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

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

一、业务场景

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

(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元

>need-to-insert-img

(2)业务1和业务2进行逻辑计算,算出各自业务的余额,假设业务1算出的余额是28元,业务2算出的余额是38元

>need-to-insert-img

(3)业务1对数据库中的余额先进行修改,设置成28元。

业务2对数据库中的余额后进行修改,设置成38元。

>need-to-insert-img

此时异常出现了,原有金额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=$uidAND money=$old_money”即可。

并发操作发生时:

业务1执行 => UPDAtE t_yueSET money=28WHERE uid=$uidAND money=100

业务2执行 => UPDAtE t_yueSET money=38WHERE uid=$uidAND money=100

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

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

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

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

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

八、总结

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

作者:沈剑

简介:58同城高级架构师,本文由原作者58沈剑授权转发

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CSDN技术头条

微软拥抱Linux,为时已晚?

今日,微软发布了一系列有关Linux的功能。首先,SQL Server支持Linux了,一周之后,微软宣布“原生的Linux二进制文件可以运行在Windows1...

2188
来自专栏花叔的专栏

小程序码生成方式变更、微信不常联系的朋友

今天不深度分析,只给大家说说微信两个不显眼的变更。 首先说的小程序API的变更,话说,今天小苏突然跟花叔说,有个东西变了,但是微信官方没有发通告。 啥呢? 可生...

3038
来自专栏数据架构之路

RDBMS变化数据设计,采集和接入大数据平台

在数据爆发式增长的时代,记录数据变化和演变,探究内在规律并运用到生产实践中,驱动业务的增长成为这个时代主旋律。本文就如何记录数据变化,处理数据变化谈谈...

62518
来自专栏PHP在线

PHP程序员的技术成长规划

原文出处: 黑夜路人 按照了解的很多PHP/LNMP程序员的发展轨迹,结合个人经验体会,抽象出很多程序员对未来的迷漫,特别对技术学习的盲目和慌乱,简单梳理了这...

3275
来自专栏用户2442861的专栏

电商搜索引擎实践(工程篇)

随着互联网数据规模的爆炸式增长, 如何从海量的历史, 实时数据中快速获取有用的信息, 变得越来越有挑战性. 一个中等的电商平台, 每天都要产生百万条原始数据,...

1682
来自专栏知晓程序

如何删除小程序缓存 / 小程序列表能同步吗 / 追剧小程序推荐 | 小程序问答 #11

不知道有多少人在用微信谈工作?每次向对方用纯文字介绍自己的时候,都觉得低效又不美观。

943
来自专栏数据和云

云端迁移 - Evernote 基于Google 云平台的架构设计和技术转型(上)

编辑手记:Evernote在短暂的时间里完成了向云端的迁移,其战果可喜可贺,然而每一次成功,都是背后的默默的努力和付出支撑起来的。在迁移的过程中,面对网络、硬件...

37211
来自专栏FreeBuf

挖洞经验 | 记一次针对Twitter(Periscope)API 的有趣挖洞经历

近期,我在Twitter的Periscope服务中发现了一个漏洞。这是一个CSRF(跨站请求伪造)漏洞,虽然这个漏洞并不算是高危漏洞,但是发现该漏洞的整个过程我...

3106
来自专栏EAWorld

微服务模式系列之九:独享数据库

译者自序: 熟悉我的朋友都知道,我很不喜欢翻译东西,因为在两种语言的思维方式之间做频繁切换对我来说是件很痛苦的事情。但是这次不一样,公司和同事的大力支持降低了我...

3256
来自专栏大数据技术学习

阿里大数据工程师讲如何用使用MaxCompute Studio 开发大数据应用

MaxCompute(原ODPS)是阿里云自主研发的分布式大数据处理平台,为用户提供了开放的编程接口和 SDK,允许用户在其强大灵活的存储和计算能力之上开发自己...

2610

扫码关注云+社区