如何实现分布式消息同步?

查看 42|回复 4
作者:molvqingtai   
前段时间写了一个浏览器扩展,详见: /t/1076581?p=1#reply25
有一个痛点,因为所有消息都储存在本地,导致无法接收离线消息,例如:
现在有 UserA 、UserB 、UserC 、UserD 4 个用户,A 、B 、C 在线,D 离线
时间点 1:UserA 、UserB 、UserC 三个用户聊天,产生 3 条信息 “message-1-A, message-1-B, message-1-C”
时间点 2:UserC 离线退出聊天,UserA 与 UserB 继续聊天,产生 2 条信息:“message-2-A, message-2-B”
时间点 3:UserC 、UserD 上线加入聊天,那么此时,时间点 1 和时间点 2 的聊天信息需要同步给 UserC 和 User D
UserA 、UserB 拥有所有信息记录 5 条, 无需同步
UserC 本地记录 3 条,需要同步时间点 2 ,同步 2 条
UserD 本地无记录,需要同步时间点 1+2 同步 5 条
如上,我了解一些分布式同步的解决方案,etcd 、raft 等,奈何太菜看得一脸懵逼,上手太复杂
目前想到的解决方案就是,A 、B 、C 、D 广播自己所有的消息记录,然后各自接收,通过消息的时间戳 Diff, 然后同步时根据 Diff 出的差值,追加或插入。
[ol]
  • 性能问题:是否可以避免广播所有的消息记录,能否做到只广播其他用户需要同步的记录?
  • 同步信息过多:因为插件的消息时储存在浏览器 IndexDB 中,一方面是有大小限制,感觉没有必要同步所有的历史消息,比如可以设置一个只同步 7 天 30 天..的聊天记录,或许有更好的方案?
  • 消息数据结构:我现在只是简单的使用一个带时间戳的 List 来存储消息,要实现上面的功能是否有更好的存储方案,比如链表等?
    [/ol]
  • cpstar   
    我就想知道,如果没有远端服务器,如果 ABCD 全都离线状态,那么其中一者上线后,从哪获取消息?比如,CD 提前离线,而 AB 聊的火热但之后离线,CD 再上线时必然无法获取 AB 的消息,又聊的火热,再等 AB 其中一者上线时,CD 才能获取到 AB 最后聊天的内容,然后 CD 怎么插数据?
    于是必然需要远端存储,那么就与单纯本地存储相违背了。那么,没了,南山无敌说号称“不存”,么?说根本,OP 就在讨论一个 IM 的设计原则。单纯的本地存储只能解决点对点消息,而且一旦一点离线,无法发送,这么说当年抠抠差不多这个逻辑。一旦开群聊,那势必。。。
    iintothewind   
    部署一个 mq 服务, 支持每个用户创建可存储 mq 消费的 offset 的状态的 session,
    然后每个用户根据 id 创建 session 就好了.
    可选方案 mqtt, redis-mq 都可以, 没必要上 kafka.
    单用户多个客户端消息同步, 这个说真的比较难办, web 的话你没有权限拿到每个客户端的唯一 id, 很难区分, 即便能拿到, 你还要根据客户端不同, 从消息总线里面 replay+filter, 重新同步, 比较麻烦.
    带时间戳的 list, 你为啥不用 timer series 数据库, redis 本身就是了, 何必自己设计?
    qping   
    暂时想到两个方案
    1 要么选举出一个中心节点,如果中心节点下线,那要重新选举。
    2 所有客户端保留的都是最近 n 天的聊天记录,也就是说它们存储的历史消息都是一样的,有其他人上线时,就需要就近从任意一人那里获得历史消息
    方案一,实现复杂,如果中心节点下线那所有人都会卡顿
    方案二,如果有人改动了消息,比如在聊天时清空了本地的消息,正好有人上线和他同步,那就同步不到消息了
    qping   
    @iintothewind 他要的是分布式消息同步,只有客户端没有服务端
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部