状态同步为什么这么难:消息风暴扩散系数(4/31)

好友状态推送、群友状态拉取——一个 N 决定技术选型

即时通讯架构实践第 4 课封面:即时通讯04:状态同步为什么这么难:消息风暴扩散系数

好友状态推送、群友状态拉取——一个 N 决定技术选型

《即时通讯架构核心技术》第 4 篇:状态同步为什么这么难。

有童鞋问我说,听说QQ状态同步过于复杂,微信的架构师搞不定,才取消了”在线”的概念,是这样吗?

微信”在线”的产品设计理念我不知道,做了几十年IM,可以和大家聊聊在线状态同步相关的架构设计。

QQ在线状态同步分两大类:

1. 好友状态的同步;

2. 群友状态的同步;

这两类状态同步的需求各异,前者需要实时同步,后者能够容忍延时。

任何脱离业务的架构设计都是耍流氓,这两类场景的状态同步,究竟是推送还是拉取呢?

用户的在线状态,分为:

1. 客户端状态(端,显示状态);

2. 服务端状态(云,真实状态);

两种形态。

什么是服务端状态?

服务端状态,在线online和离线offline两种,这是用户的真实在线状态。不同的状态,对于不同的业务处理流程可能不同。

例如,对于消息的处理:

1. 服务端状态在线,直接投递给用户;

2. 服务端状态离线,则存储离线消息,等用户下一次登录拉取;

如何实时更新服务端状态?

用户uid-A登录时,会修改用户的服务端状态为在线。

登录时更新服务端状态为在线

用户uid-A登出时,会修改用户的服务端状态为离线。

登出时更新服务端状态为离线

经常的,服务端会将用户的服务端状态存储在高可用的缓存集群里。

什么是客户端状态?

对好友,群友显示的在线状态,例如隐身、离线、忙碌、勿扰等,是客户端状态,这些状态是产品功能需求。我们所说的”用户状态同步”,都是指的客户端状态。

为了方便介绍,假设客户端状态也只有online和offline两种状态,与服务端状态一致,后文统一称为”用户状态”。

如何获取好友的状态?

uid-A登录时,先去数据库拉取自己的好友列表,再去缓存获取所有好友的状态。

登录时拉取好友列表与好友状态

用户uid-A的好友uid-B状态改变时(由登录、登出等动作触发),uid-A如何同步这一事件?

情况一:如果对于状态变更实时性要求不高,可以采用拉取。

uid-A向服务器轮询拉取uid-B(其实是自己的全部好友)的状态,例如每1分钟一次,其缺点是:

1. 如果uid-B的状态改变,uid-A获取不实时,可能有1分钟时延;

2. 如果uid-B的状态不改变,uid-A会有大量无效的轮询请求,非常低效;

情况二:如果对于状态变更实时性要求较高,则必须推送。

uid-B状态改变时(由登录、登出等动作触发),服务端不仅要在缓存中修改uid-B的状态,还要将这个状态改变的通知推送给uid-B的在线好友。

状态改变实时推送给在线好友

推送的优势是:实时。

缺点是:当在线好友量很大时,任何一个用户状态的改变,会扩散成N个实时通知,这个N叫做”消息风暴扩散系数”。

假设一个IM系统平均每个用户有200个好友,平均有20%的好友在线,那么消息风暴扩散系数N=40,这意味着,任何一个状态的变化会变成40个推送请求。

群友状态的一致性,和好友状态的一致性相比,复杂在哪里?可不可以采用实时推送?

群业务场景大伙也非常熟悉,你能够加入若干群(例如20个),假设平均每个群有200人,即你会有4000个群友。依然假设20%的用户在线,那么为了保证群友状态的实时性,每个用户登录,就要将自己的状态改变通知发送给20*200*20%=800个群友,N=800,意味着,任何一个状态的变化会变成800个推送请求。

如果说好友状态实时推送,消息风暴扩散系数N=40尚可以接受,那么群友状态实时推送,N=800则是灾难性的。此类业务往往采用轮询拉取的方式,获得群友的状态。

轮询拉取群友状态也会给服务器带来过大的压力,还有什么优化方式?

群友的数据量太大,虽然每个用户平均加入了20个群,但实际上并不会每次登录都进入每一个群。

不采用轮询拉取,而采用按需拉取,延时拉取的方式,在真正进入一个群时才实时拉取群友的在线状态,是既能满足用户需求(用户感觉状态是实时、一致的,但其实是进入群才拉取的),又能降低服务器压力。这是一种常见方法。

总结

状态的实时性与一致性是一个较难解决的技术问题,一般来说:

1. 好友状态同步,是采用推送的方式同步;

2. 群友状态同步,由于消息风暴扩散系数过大,一般采用拉取的方式同步;

3. 群友状态同步,还能采用按需拉取的优化方式,进一步降低服务端压力;

4. “消息风暴扩散系数”是指一个消息发出时,变成N个消息的扩散系数,这个系数一定程度上决定了技术采用推送还是拉取;

知道为什么,一个群最多500人了吧?

检验一下

检索练习 · 两种状态
「客户端状态」和「服务端状态」的区别是?

检索练习 · 消息风暴扩散系数
平均每人 200 个好友、20% 在线,一次状态变化会扩散成多少个推送请求?

检索练习 · 群友状态为何用拉取
20 个群、每群 200 人、20% 在线,群友状态为什么不能用实时推送?

检索练习 · 按需拉取
轮询拉取群友状态压力也大,进一步的优化是?

状态同步的权衡讲完了。换个角度:手机、PC 同时登录微信,消息怎么两边都收?换手机又怎么看到历史消息?——第 5 篇,多点登录与消息漫游怎么实现。

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

发表回复

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

京ICP备2025137728号-3