同样是高并发,QQ/微博/12306 难度一样吗?(25/31)

锁冲突视角下的高并发难度分级:QQ 几乎无冲突,微博有冲突,12306 极易死锁

即时通讯架构实践第 25 课封面:即时通讯25:同样是高并发,QQ/微博/12306 难度一样吗

锁冲突视角下的高并发难度分级:QQ 几乎无冲突,微博有冲突,12306 极易死锁

《即时通讯架构核心技术》第 25 篇:同样是高并发,QQ/微博/12306 难度一样吗。

开篇

同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,保证数据的一致性:

UPDATE t_yue SET money=$new_money
WHERE uid=$uid AND money=$old_money;

更详细的描述,详见《并发扣款,如何保证数据的一致性?》。

不能采用直接扣减的方式:

UPDATE t_yue SET money=money-$diff WHERE uid=$uid;

更详细的描述,详见《并发扣款一致性,幂等性问题》。

当然,更通用的方式,可以使用版本号来实现CAS乐观锁:

UPDATE t_yue SET money=$new_money, ver=$ver_new
WHERE uid=$uid AND ver=$ver_old;

更详细的描述,详见《并发扣款一致性优化,CAS下ABA问题》。

对于这个CAS乐观锁方案,很多朋友有疑问:当并发量高时,版本号比对会导致大量的更新失败,这个方案不适用于高并发场景吗?

究竟是不是这样呢?大家对高并发是不是有什么误解呢?今天来聊一聊这个话题。

先分析三个业务场景。

QQ

QQ的一些核心业务有:

个人:user(uid, user_info, …)

好友:user_friends(uid, friend_id, …)

加入的群:user_groups(uid, group_id, …)

群:group(gid, group_info, …)

群成员:group_members(gid, uid, …)

个人消息:msgs_user(msg_id, uid, …)

群消息:msgs_group(msg_id, gid, …)

这些信息的读写有一个特点,都会带上uid/gid/msgid属性。

例如,拉取好友列表:

select friend_id from user_friends where uid=$uid;

在用户量很大,并发量很大时,不同用户/群/消息数据的读写并没有锁冲突。

10W个用户同时读写,彼此没有锁冲突。

只有当,同一个用户,很短的时间内,有大量并发时,才可能存在锁冲突。

例如,1个用户,1秒钟读写1W次。

微博

微博的核心业务是feed流:

发消息,写操作

刷消息,读操作

微博业务显然是读多写少的,在用户刷消息时,自己feed流里的消息,是由别人发出的。

查看自己主页feed流,最朴素的实现方法是:

(1) 拉取自己关注的用户id_list;

(2) 拉取这些用户最近N条消息;

(3) 将这N*id_list条消息排序;

(4) 返回第一页消息,得到自己主页feed流;

这里不展开读扩散,写扩散,详见《读扩散?写扩散?》。

在用户量很大,并发量很大时,会有一定数据的读写锁冲突。

不像QQ,基本是读写自己的数据,微博要写自己的数据,读别人的数据。

12306

12306的核心业务是:

查票,读操作

买票,写操作

stock(id, num) // 某一列车有多少张余票

在用户量很大,并发量很大时,有极大的锁冲突。

这个业务,数据量并不大。

这类“秒杀”业务,如果不做特殊的优化,数据库很容易死锁卡死,没有任何人能买票成功。

要做什么特殊的优化呢?

收尾

QQ,微博、12306,同样是高并发业务,就数据存储锁冲突来说,各自的难度,数据不一致的概率是不同的。

你不能说,QQ不是高并发业务吧。

回到开篇,使用CAS乐观锁进行库存扣减:

UPDATE t_yue SET money=$new_money, ver=$ver_new
WHERE uid=$uid AND ver=$ver_old;

只要有uid这个过滤属性,即使10W用户同时扣款,也不容易出现数据不一致。

只有当同一个用户,同一秒钟,有大量扣减时,才有一定几率会冲撞,但也不会导致数据不一致。

有一位很可爱的水友,说万一PC端和APP端同时下单怎么办。

结论

高并发的扣款场景,可以使用CAS乐观锁,采用select&set方式进行扣款,既能够保证吞吐量,又能够保证一致性。

任何脱离业务的架构设计,都是耍流氓。

检验一下

检索练习 · QQ 为什么冲突少
用户量、并发量都很大时,QQ 的核心数据读写为什么几乎没有锁冲突?

检索练习 · 微博 feed 流
「查看自己主页 feed 流」最朴素的实现,正确的步骤顺序是?

检索练习 · 12306 难在哪
同样是高并发,12306 的架构难度为什么远大于 QQ?

检索练习 · CAS 的适用边界
「并发量高时 CAS 版本号比对会大量失败,不适用于高并发」——这个质疑成立吗?

数据量再大一个量级会怎样?好友关系到百亿级别,表怎么设计、库怎么切分?——第 26 篇,百亿关系链,好友关系架构怎么设计。

知其然,知其所以然。思路比结论更重要。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

京ICP备2025137728号-3