微信/钉钉里, 用户可以任意建群聊天, 这是怎么实现的?

2020-09-16 16:42:47 +08:00
 melonux
教科书上写, 让客户端使用 MQTT 做订阅. 订阅的 topic 就是 群名字 . 原理上是没问题. 可是几年用下来, 大大小小的群能够上千个了, 好多都很久没有发言了. 如果往这种僵尸群中发言, 群成员还是能立刻收到消息. 那就意味着, 一个用户要一直订阅着上千个群了. 这会非常消耗 MQTT broker 的资源吧. 业界都是怎么解决的呢?
3687 次点击
所在节点    程序员
13 条回复
ck19920702
2020-09-16 16:46:24 +08:00
不用 MQTT
melonux
2020-09-16 17:01:20 +08:00
@ck19920702 那用什么? 不管是啥, 也得订阅吧. 只要订阅, 就涉及那么多群是否都要一直订阅着的问题.
joesonw
2020-09-16 17:20:15 +08:00
发言的时候推到每个人自己的 topic?
CloudnuY
2020-09-16 17:27:40 +08:00
群绑定用户,用户不绑定群,新建的群拉进去之后不发言 被拉的人是看不到的
pengjay
2020-09-16 17:33:35 +08:00
群消息通知每个用户一个公用 topic 。进群聊界面才开始订阅群的 topic,离开群就取消订阅。
GM
2020-09-16 17:35:34 +08:00
客户端和服务器保持一个连接,几个活跃用户就几个连接,这个是必须的,现阶段已经很成熟了,不是难题了。
然后服务器维护群和群员关系,这里要尽量用紧凑高效的数据结构。
当群有新消息,服务器通过群员关系,遍历出所有需要发消息的群员,通过第一步建立的长连接发出去。

就这样,任务结束。
kop1989
2020-09-16 17:41:29 +08:00
我的理解是群里面包含成员字段。
既有一个群表。里面有群 id/code 、 群名称、群组成员 id 。
然后当一个人发消息之后。
相当于是对此群 id 讲话。

然后通过群 id 查询群组成员 id 。再通过群组成员 id 查询当前的在线状态决策如何同步消息。
如果当前活跃则走 websocket/长轮询 /tcp,辅以推送透传消息作为保底手段。通知客户端有新的消息,然后客户端发起信息同步。
当前用户不活跃则直接发送系统级 notification,待用户唤起 app/应用再由客户端发起信息同步。
kop1989
2020-09-16 17:43:20 +08:00
换句话说,群也是一个“用户”,只不过这个用户包含有多个真正的用户。然后几个用户之间都是在和这个叫“群”的用户交流。
opengps
2020-09-16 17:58:03 +08:00
你为什么非要用 topic 的原理来实现群聊呢?
我完全可以用传统关系型数据库给你,所有群内成员遍历发送一遍来实现,这个原理你理解下
Code418
2020-09-16 18:39:43 +08:00
以前用 MQTT 搞过,不过最终的感觉是其实 IM 用 MQTT 实现还是挺麻烦的,我不是专门作 IM 的,这部分也是菜,只能讲一些粗浅的地方。其实上面大家都讲的差不多了。

群或私聊本身有自己的 topic,但事实上在客户端进入聊天时再订阅就好,关键在用户需要一个随连线一起订阅的 notify 用的自己的 topic,连上 broker 就必定订阅这个,往这里面 notify 就好。反正你消息包定义定好了你想通知什么都可以。

重点在 notification 的设计上怎么作高效。可以实时发 notify,单纯做到这步的话实现很简单。但是一个群就得先捞完所有群员然后各自发的话,无论是 dispatch 或是实际的 I/O,人多群多的情况下就会非常吃重,这部分看实际业务状况跟想怎么去设计权重与优化。不过单纯用 MQTT 的机制做起来我觉得挺麻烦困难的,本身的使用场景其实就不是常规的 Chatting 。

尤其 IM 还要考虑到实际的离线消息,就更加复杂麻烦跟炸性能。反正我做到这边我就扔着等有时间再优化了,还没时间拆人家的 IM 抄袭(划掉)琢磨人家的设计跟优化……
Bijiabo
2020-09-16 18:48:57 +08:00
一般 MQTT 会配合规则引擎使用,用户加入哪些群,在云端可以通过规则引擎将消息聚合到一个用户的 topic 中
也就是说,用户订阅一个消息 topic 就足够了。
neoblackcap
2020-09-16 19:11:51 +08:00
没记错的话,微信是参考微软的 Exchange ActiveSync 。用 mqtt 硬套不了。同时最开始的那版好像是基于 xmpp 的
zjyl1994
2020-09-17 00:38:26 +08:00
肯定不能每个会话一个 topic 的,你把群理解为特殊的用户就行了。有人在群里发消息,触发一个遍历群成员挨个写入推送渠道的动作就可以了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/707617

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX