状态同步,与好友状态同步,与群好友状态同步,有的需要实时同步,有的可以容忍延迟。任何脱离业务的架构设计都是耍流氓。不同场景下,状态同步,是push还是pull?用户在线状态分为两种形式:客户端状态(端)和服务器状态(云端)。服务器状态是什么?服务器状态主要分为在线和离线。不同的业务流程可能会有不同的状态。比如对于消息的处理:服务器状态为在线,直接下发给用户;服务器状态为离线,离线消息直接存储,下次登录时拉取;如何实时更新服务器的状态?当用户uid-A登录时,会修改用户的服务器状态为在线。当用户uid-A注销时,用户的服务器状态会变为下线。通常,服务器会将用户的服务器状态存储在一个高可用的缓存集群中。什么是客户状态?不同的产品有不同的客户端状态,比如隐身、离线、忙碌、请勿打扰等,这些状态大多是产品功能需求。画外音:微信在设计之初就抛弃了客户端状态的概念。为了描述方便,我们假设要讨论的产品是QQ,它有一个客户端状态,假设客户端状态只有在线和离线两种状态,在本文中统称为“用户状态”下列的。如何获取好友状态?uid-A登录时,先去数据库拉取他的好友列表,然后去缓存中获取所有好友的状态。当用户uid-A的好友uid-B的状态发生变化时(登录、注销等动作触发),uid-A如何同步这个事件?这里有一个推拉式设计折衷方案。情况一:如果对状态变化的实时性要求不高,可以使用pull。Uid-A轮询服务器以拉取uid-B(实际上是其所有朋友)的状态,例如每1分钟一次。缺点是:如果uid-B的状态发生变化,uid-A的获取不是实时的,延迟1分钟;如果uid-B的状态没有变化,uid-A就会有大量无效的轮询请求,效率很低;Case2:如果对状态变化的实时性要求高,必须推送。当uid-B的状态发生变化时(登录、注销等触发),服务端不仅需要修改缓存中uid-B的状态,还要将状态变化的通知推送给uid在线的好友-B。push的优点是:实时。缺点是:当在线好友数量众多时,用户状态的任何变化都会扩散成N个实时通知,这个N称为“消息风暴扩散系数”。假设一个IM系统平均每个用户有200个好友,平均有20%的好友在线,那么消息风暴扩散系数N=40,也就是说任何一个状态变化都会变成40个推送请求。与好友状态一致性相比,群好友状态一致性的复杂度如何?可以使用实时推送吗?集团的业务场景也是大家非常熟悉的。你可以加入几个群(比如20个),假设平均每个群有200人,也就是你会有4000个群好友。理论上,群友状态也可以通过实时推送来实现,保证实时性。在进一步讨论之前,我们一起来估算一下这个业务场景下的“消息风暴扩散系数”。假设每个用户平均加20个群,每个群平均有200个用户,仍然假设20%的用户在线,那么为了保证群友的实时状态,每个用户都必须登录并且改变自己的状态通知发送给20*200*20%=800个群友,N=800,也就是说任何一个状态改变都会变成800个推送请求。如果实时推送好友状态,新闻风暴扩散系数N=40还可以,那么实时推送群友状态,N=800就惨了。这类业务往往采用轮询拉取的方式获取群友状态。轮询拉取群友状态也会给服务器造成太大的压力。还有哪些优化方法?群友数据量太大。虽然每个用户平均加入20个群,但实际上并不是每次都登录进入每个群。不采用轮询拉取的方式,而是采用按需拉取和延迟拉取的方式,在群友真正进群时实时拉取群友在线状态,既能满足用户需求(用户感觉状态真实-时间,一致,但实际上是进群后拉的),可以减轻服务器的压力。这是一种常用的方法。总结状态的实时性和一致性是一个很难解决的技术问题。不同的业务有不同的实现方式。一般来说,好友的状态同步都是通过push来完成的;大,一般采用pull方式同步;群好友状态同步也可以采用按需拉取的优化方式,进一步降低服务器压力;“消息风暴扩散系数”是指一条消息发出后,变成了N条消息,这个系数在一定程度上决定了技术采用的是push还是pull;画外音:群消息的推送也存在“消息风暴扩散系数”的问题。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
