默认
打赏 发表评论 15
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?
微信扫一扫关注!

1、前言


“用户在线状态的一致性”(单聊好友在线状态、群聊用户在线状态)是IM应用领域比较难解决的一个技术问题,如何精准实时的获得好友、群友的在线状态,是今天将要探讨的话题。

2、IM开发干货系列文章


本文是系列文章中的第4篇,总目录如下:


更多群聊技术文章:


另外,如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

3、保持单聊好友状态的一致性


1场景一:用户uid-A登录时,如何获取自己全部好友的在线状态?


一个典型的IM大致的处理逻辑是这样的:

1)服务器要存储所有用户的在线状态(往往存储在保证高可用的缓存集群里) -> 保证状态可查,流程见下图:
1.jpg

2)用户状态实时变更,任何用户登录时,需要将服务端自己的在线状态置为online;任何用户登出时,需要将服务端自己的状态置为offline -> 保证服务端状态存储的一致性与实时性,流程见下图:
2.jpg

3)uid-A登录时,先去数据库拉取自己的好友列表,再去缓存获取所有好友的在线状态 -> 保证登录时好友状态获取的一致性与实时性,流程见下图:
3.jpg

2场景二:用户uid-A的好友uid-B状态改变时(由登录、登出、隐身等动作触发),uid-A如何知道这一事件?


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

方案一的缺点:
  • 如果uid-B的状态改变,uid-A获取不实时,可能有1分钟时延;
  • 如果uid-B的状态不改变,uid-A会有大量无效的轮询请求,占用服务器资源。

► 方案二的逻辑:
uid-B状态改变时(由登录、登出、隐身等动作触发),服务器不仅在缓存中修改uid-B的状态,还要将这个状体改变的通知推送给uid-B的在线反向好友(反向好友是指:加了uid-B为好友的人,而不是uid-B的好友,这个细节要注意)。
4.jpg

方案二的优点:实时。
方案二的缺点:当在线好友量很大时,任何一个用户状态的改变,会扩散成N个实时通知,这个N叫做“消息风暴扩散系数”。
设一个im系统平均每个用户有200个反向好友,平均有20%的反向好友在线,那么消息风暴扩散系数N=40,这意味着,任何一个状态的变化会变成40个推送请求。

4、保持群聊友状态的一致性


1场景一:群友状态一致性有什么不同,和好友状态一致性相比复杂在哪里?为什么不能采用实时推送?


理论上群友状态也可以通过实时推送的方式实现,以保证实时性。但实际上,群友状态一般都是采用拉取的方式获得,因为群友状态“消息风暴扩散系数”N实在太大,全部实时获取系统往往承受不了。

假设平均每个用户加了20个群,平均每个群有200个用户,依然假设20%的用户在线,那么为了保证群友状态的实时性,每个用户登录,就要将自己的状态改变通知发送给20*200*20%=800个群友,N=800,意味着,任何一个状态的变化会变成800个推送请求。

XXX系统使用的是群友状态推送,不存在的这样的问题?那很可能是,XXX系统的用户量和活跃度还不够高吧。

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


群友的数据量太大,虽然每个用户平均加入了20个群,但实际上并不会每次登录都进入每一个群。不采用轮询拉取,而采用按需拉取,延时拉取的方式,在真正进入一个群时才实时拉取群友的在线状态,是既能满足用户需求(用户感觉是状态是实时、一致的,但其实是进入群才拉取的),又能降低服务器压力。这是一种常见方法。

总结与建议


IM应用中在线状态的实时性与一致性是一个较难解决的技术问题,不同的业务接受度,不同的数据量并发量在线量,实现方式不同。

个人建议的方式是:

  • 好友状态,如果对实时性要求较高,可以采用推送的方式同步;如果实时性要求不高,可以采用轮询拉取的方式同步;
  • 群友的状态,由于消息风暴扩散系数过大,可以采用按需拉取,延时拉取的方式同步;
  • 系统消息/开屏广告等对实时性要求不高的业务,可以采用拉取的方式获取消息;
  • “消息风暴扩散系数”是指一个消息发出时,变成N个消息的扩散系数,这个系数与业务及数据相关,一定程度上它的大小决定了技术采用推送还是拉取。

(原文链接:点此进入,有删节)

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:如何保证IM实时消息的“时序性”与“一致性”?下一篇:IM群聊消息如此复杂,如何保证不丢不重?

本帖已收录至以下技术专辑

推荐方案
评论 15
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

个人认为,这应该是不对的,以QQ群为例:当当前正处理该群的聊天界面时,为了实时性,状态应该是实时推送过来的,而当此聊的聊天界面处于后台时则应是用“拉”的方式。这样就能在体验和性能上取得一个好的结果。至于文中担心的:当群员很多时会发生“推送风暴”,个人认为这不太可能发生,因为一个群里的人再多,同时正在打开这个群(即该群正处于当前聊天窗口)的人并不可能那么多。
签名: 国庆长假还没有缓过来,请让我静一静,产品狗死远点...
引用:IMDeveloper 发表于 2017-02-20 12:16
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

说的很好,赞!
引用:IMDeveloper 发表于 2017-02-20 12:16
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

分场景而论吧,看相关的技术
签名: 开始学习im
文章写的不错,受益匪浅!
支持一下
签名: 该会员没有填写今日想说内容.
引用:IMDeveloper 发表于 2017-02-20 12:16
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

混合使用
学习中
签名:
干货
签名: 心情好
细节的讨论
引用:IMDeveloper 发表于 2017-02-20 12:16
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

这样会出现新的需求,得维护正打开群页面用户的,这个数据变化应该是非常频繁的,是否得不偿失
沈剑老师,点赞
签名: now start 。。。
引用:IMDeveloper 发表于 2017-02-20 12:16
文章写的不错,但有些内容个人不赞同,比如作者说:
群状态的最佳建议是用“拉”的方式实现。

这种情况是不是可以订阅当前会话,当前会话实时推送,如果会话关闭结束退订即可。
感谢分享
又学到了新知识
支持一下
签名: 今天签到今天签到
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部