V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
melonux
V2EX  ›  程序员

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

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

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

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

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

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

    尤其 IM 还要考虑到实际的离线消息,就更加复杂麻烦跟炸性能。反正我做到这边我就扔着等有时间再优化了,还没时间拆人家的 IM 抄袭(划掉)琢磨人家的设计跟优化……
    Bijiabo
        11
    Bijiabo  
       2020-09-16 18:48:57 +08:00
    一般 MQTT 会配合规则引擎使用,用户加入哪些群,在云端可以通过规则引擎将消息聚合到一个用户的 topic 中
    也就是说,用户订阅一个消息 topic 就足够了。
    neoblackcap
        12
    neoblackcap  
       2020-09-16 19:11:51 +08:00
    没记错的话,微信是参考微软的 Exchange ActiveSync 。用 mqtt 硬套不了。同时最开始的那版好像是基于 xmpp 的
    zjyl1994
        13
    zjyl1994  
       2020-09-17 00:38:26 +08:00 via Android
    肯定不能每个会话一个 topic 的,你把群理解为特殊的用户就行了。有人在群里发消息,触发一个遍历群成员挨个写入推送渠道的动作就可以了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3007 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 13:29 · PVG 21:29 · LAX 05:29 · JFK 08:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.