V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
xhldtc
V2EX  ›  程序员

IM 中如何处理节点故障,导致消息不可靠问题?请教

  •  
  •   xhldtc · 2023-02-17 19:54:54 +08:00 · 1899 次点击
    这是一个创建于 674 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在做一个 IM 的开发,初次尝试 IM 开发,碰到点问题向懂这块的兄弟们请教一下。直接上图: IM 技术方案 先简单说一下技术方案吧:

    • 用户登录之后与一台 server 建立连接,会话信息保存到本地( SessionMap ),就是把 userId 和 channel 的映射关系存起来,再把 userId 和 server 所在主机 MAC 地址的映射关系存到 redis 中。

    • 每台 server 在启动的时候,会在 MQ 里订阅自己所在主机的 MAC 主题(这里是把主机 MAC 作为 MQ 的 Topic 用的)。

    • 两个 user 之间相互发消息:

      • 如果两个 user 在同一台主机,直接从本地 SessionMap 获取对方 channel 完成消息传递;

      • 如果两个 user 在不同的主机,一个 user 发完消息后,server 端从 redis 中获取对方所在主机 MAC (假设为 MAC_2 ),然后把消息丢到 MQ 的 MAC_2 Topic 中,传递到对方主机,再从对方主机 SessionMap 中取出对方 channel ,完成消息传递;

      • 如果是传给 MAC_3 上的 user ,user 不在线,就离线存储。

    现在问题是,假如说某台机器故障了,比如假设 MAC_3 故障,硬件损坏,那 MQ 中 MAC_3 Topic 中的消息会越积越多,而这个 Topic 又没有订阅者,那这部分信息该怎么处理?

    20 条回复    2023-02-19 16:16:54 +08:00
    Nazz
        1
    Nazz  
       2023-02-17 20:01:11 +08:00 via Android
    做好容灾就行了
    billlee
        2
    billlee  
       2023-02-17 20:03:24 +08:00 via Android
    应该用 userId 的 hash 来分区。哪有人用服务器的地址分区的。
    wyx119911
        3
    wyx119911  
       2023-02-17 20:14:14 +08:00
    这架构很难维护,服务应该做成无状态的
    KristenGe
        4
    KristenGe  
       2023-02-17 22:24:21 +08:00
    @Nazz 问题是一旦量上来了,扩缩容的时候,可能会出现多台主机对应的 MQ Topic 处于无订阅状态。
    KristenGe
        5
    KristenGe  
       2023-02-17 22:26:14 +08:00
    @billlee 能具体点吗?目前 MQ 中的消息等于是通过 userId 寻址,找 Topic 送达对应主机,userId 分区是怎么个做法?
    KristenGe
        6
    KristenGe  
       2023-02-17 22:27:28 +08:00
    @wyx119911 服务如果无状态,消息寻址,或者说消息路由吧,怎么送达对方的 channel 呢?
    Nazz
        7
    Nazz  
       2023-02-17 22:49:33 +08:00 via Android
    @gemingsy im server 应该是有状态副本集, 把用户分配到固定的节点上.
    KristenGe
        8
    KristenGe  
       2023-02-17 23:16:38 +08:00
    @Nazz 这个其实没有问题的,无非就是 client 和 server 之间做一层 routing ,现在问题是不同节点上的用户之间消息交互,是通过对方机器标识(或服务标识)做 MQ 的 Topic ,精准送达,如果服务 down 了,topic 成无订阅状态,消息无法消费了。现在能想到的是用 ZK ,不过前期不想太复杂。
    javapythongo
        9
    javapythongo  
       2023-02-17 23:41:04 +08:00
    可以把用户是否在线存储到 redis 中,发送消息前,判断下,不在线就直接离线存储
    b1ghawk
        10
    b1ghawk  
       2023-02-17 23:41:06 +08:00 via Android
    可以把消息泛播到每个服务器上,
    每个服务器判定这条消息的用户是否在本机上又连接,有的话就发出去。
    huanw
        11
    huanw  
       2023-02-17 23:51:11 +08:00
    楼上的老哥说得对,消息应该散播到集群每个节点上,因为你每个节点都有 SessionMap ,由节点来决定怎么给客户端发消息。做到无状态才有利于扩展,比如断线重连,本来连接节点 1 ,断线后连接节点 2 ,这都不影响消息发送。
    mawerss1
        12
    mawerss1  
       2023-02-18 00:02:07 +08:00 via Android
    不说这个系统设计如何,单论这个问题,在你这个设计里挂了消息就只能扔掉,如果丢消息,你需要在发送端做好存储
    KristenGe
        13
    KristenGe  
       2023-02-18 01:40:34 +08:00 via Android
    @b1ghawk 这种做法我感觉在 IM 的系统中不太现实,量一旦上来了,会造成网络堵塞;而且每台机器都等于要处理全网的消息量,性能一定会成为瓶颈
    KristenGe
        14
    KristenGe  
       2023-02-18 01:48:38 +08:00 via Android
    @mawerss1 发送端其实已经收到消息发送成功的应答了,因为消息已经落到 MQ 里了
    Nazz
        15
    Nazz  
       2023-02-18 07:29:15 +08:00 via Android
    @gemingsy 服务挂了让副本起来工作啊,每个编号的 Deployment 搞多个 Pod ,订阅同一个主题
    Nazz
        16
    Nazz  
       2023-02-18 07:56:52 +08:00 via Android
    @Nazz 小集群内做成无状态服务
    PythonYXY
        17
    PythonYXY  
       2023-02-18 11:08:55 +08:00
    路由信息单独保存在 redis 或者 kv 数据库中,抽象出一个路由服务集群统一消费 MQ 消息,对消息进行路由推送。不过要考虑路由服务的消费能力,避免过高的消息延迟。
    NUT
        18
    NUT  
       2023-02-18 11:23:57 +08:00
    通用问题。 其实必须有一个主去做 session 状态的分配。 陌陌老早时候有一个 ppt 分享他们的策略。 分三层,一层是接入层, 无状态,可以任意扩展,主要是接受链接, 第二层 逻辑层,保证消息业务逻辑的路由等, 第三层存储。

    其实你的服务没有脑子,需要有一个脑子,去做这种订阅关系的维护, 也就是 接入层上线以后, 由 master 去做分配 session 相关策略。主要保证 master 强一致就行。

    不过咋说,难度就会上一个层级。 还可以看看 codis 还有 tidb 等分布式设计。 会有帮助的。
    guonaihong
        19
    guonaihong  
       2023-02-18 17:14:12 +08:00
    收藏下下。。。
    KristenGe
        20
    KristenGe  
       2023-02-19 16:16:54 +08:00
    @NUT 如果有接入层,单论接入层的话,像连接的 channel 这种东西是作为集群各个节点本地 session 存储,还是用序列化方式统一存储,channel 这种东西适合做序列化统一存储吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6012 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 02:02 · PVG 10:02 · LAX 18:02 · JFK 21:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.