背景
在大型系统中,热点账户更新是高并发场景下,一个典型场景。如何在高并发的情况下,实现低延迟和数据一致性,是架构师需要面临的挑战。
本文抛弃了外延的流量控制,监控等内容,主要从DB和缓存的角度来讲。
分析
高并发从字面理解,首先是解决并发的问题,并发会导致什么问题呢?
1、流量大,导致响应时间长、甚至压垮系统。
思路:分散流量、平滑流量、限制流量。
解决:流量控制、系统拆分、缓存、异步等,
2、造成数据的不一致。
思路:强一致、弱一致、最终一致。
解决:事务、锁、MQ、对账等。
方案1:数据库乐观锁
在并发量不大,比如100~1000,使用数据库乐观锁是最简单,最方便的方式。
update account set amout=amout-100 where version=10 and amount-100>0
核心:加版本号、判断账户金额不要小于0
方案2:Redis扣减,异步合并
随着并发量变大,比如<5000,单纯使用数据库乐观锁就不行了,会导致数据库宕机。比较简单的方案是,缓存扣减。所有扣减走Redis缓存,再异步到数据库中。
1、扣减日志:写扣减日志【可写文件或DB库-本地表,文件性能会更高】
2、Redis扣减:Redis账户金额扣减。
3、异步汇总:调度30秒~1分钟,同步一次数据库,更新Redis【可乐观锁或分布式锁控制】。
方案3:数据分片,异步合并
随着业务发展,并发量爆发,比如在1万,10万等,此时需要对系统进行深度改造。
1、DB拆分:账户表,拆分为N个账户表,比如1~128张表。【可能涉及分库】
2、缓存扣减:将数据分片到多个redis实例或本地服务器缓存,用于扣减。
3、异步汇总:调度30秒~1分钟,同步一次数据库,更新Redis或本地缓存。【可乐观锁或分布式锁控制】
4、中心调度:有一个调度中心,监控各分片的数据,进行扣减调度,比如表1金额不足,要实时路由到满足扣减要求的表。【需要分布式锁控制】
其它方案:MQ异步+批量扣减
1、扣减请求:Reis扣减,写MQ
2、批量扣减:消息端批量拉取扣减记录,计算金额后,一次性扣减账户记录。
关于读
上面解决了高并发写和数据一致性问题。关于用户读如何实现呢?
1、读缓存,缓存定时与DB对账同步;
2、页面允许少量延迟,提供一个刷新按钮,刷新后显示。
总结
本文介绍了高并发典型场景,热点账户扣减的常见方案,可以根据实际场景进行组合选择。
https://mp.weixin.qq.com/s/9B6j-iwDyoK6gnXs1QR8dQ