[TOC] > [参考](https://www.w3cschool.cn/architectroad/architectroad-qq-status-consistency.html) ## 好友状态一致性 uid-B状态改变时(由登录、登出、隐身等动作触发),服务器不仅在缓存中修改uid-B的状态,还要将这个状体改变的通知**推送**给uid-B的在线反向好友(反向好友是指:加了uid-B为好友的人,而不是uid-B的好友,这个细节要注意) ![UTOOLS1576159382396.png](http://yanxuan.nosdn.127.net/7b09a29a1b844e9db0544d7b615d4ebb.png) 优点: (1)实时 缺点: (2)当在线好友量很大时,任何一个用户状态的改变,会扩散成N个实时通知,这个N叫做“**消息风暴扩散系数**”。 假设一个im系统平均每个用户有200个反向好友,平均有20%的反向好友在线,那么消息风暴扩散系数N=40,这意味着,任何一个状态的变化会变成40个推送请求。 ## 群友状态一致性 理论上群友状态也可以通过实时推送的方式实现,以保证实时性。但实际上,群友状态一般都是采用拉取的方式获得,因为群友状态“消息风暴扩散系数”N实在太大,全部实时获取系统往往承受不了。 假设平均每个用户加了20个群,平均每个群有200个用户,依然假设20%的用户在线,那么为了保证群友状态的实时性,每个用户登录,就要将自己的状态改变通知发送给20*200*20%=800个群友,N=800,意味着,任何一个状态的变化会变成800个推送请求。 群友的数据量太大,虽然每个用户平均加入了20个群,但实际上并不会每次登录都进入每一个群。**不采用轮询拉取,而采用按需拉取,延时拉取**的方式,在真正进入一个群时才实时拉取群友的在线状态,是既能满足用户需求(用户感觉是状态是实时、一致的,但其实是进入群才拉取的),又能降低服务器压力。这是一种常见方法 ## 总结与建议 状态的实时性与一致性是一个较难解决的技术问题,不同的业务接受度,不同的数据量并发量在线量,实现方式不同,个人建议的方式是: (1)好友状态,如果对实时性要求较高,可以采用推送的方式同步;如果实时性要求不高,可以采用轮询拉取的方式同步 (2)群友的状态,由于消息风暴扩散系数过大,可以采用按需拉取,延时拉取的方式同步 (3)系统消息/开屏广告等对实时性要求不高的业务,可以采用拉取的方式获取消息 (4)“消息风暴扩散系数”是指一个消息发出时,变成N个消息的扩散系数,这个系数与业务及数据相关,一定程度上它的大小决定了技术采用推送还是拉取