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

思考个问题, Java 如何通过 websocket 和 RabbitMq 集群实现复杂聊天系统呢

  •  
  •   inktiger · 2020-06-02 17:36:57 +08:00 · 3516 次点击
    这是一个创建于 1628 天前的主题,其中的信息可能已经有所发展或是发生改变。

    网上看到的方案貌似都是用 redis 队列 /订阅或者 mq 队列来实现集群的,那么假如有 10 台服务器,使用 webscoket 和 RabbitMq 来实现集群间的消息发送,用户和连接的服务器关系保存在 redis,那么某一个用户发送消息是否就代表着群里有多少人就需要查询多少次 redis 获取到其他在线用户所在服务器依次给其他用户发送消息呢?这样是否太夸张了,消息在于实时性,单单一个用户发一条消息就要这么折腾 redis,如果多了是否就扛不住了

    21 条回复    2020-12-29 15:20:40 +08:00
    Austaras
        1
    Austaras  
       2020-06-02 18:01:26 +08:00
    别问,问就是用 elixir
    wellsc
        2
    wellsc  
       2020-06-02 18:04:21 +08:00
    用 Akka
    guyeu
        3
    guyeu  
       2020-06-02 18:11:34 +08:00
    emmmm redis 有键空间通知和键事件通知来避免你说的这种情况。。。
    inktiger
        4
    inktiger  
    OP
       2020-06-02 18:15:21 +08:00
    @guyeu 额,感觉用这个的好少
    inktiger
        5
    inktiger  
    OP
       2020-06-02 18:15:32 +08:00
    @wellsc 这么冷门的东西么。。。
    opengps
        6
    opengps  
       2020-06-02 18:15:54 +08:00
    大部分人对于大型系统的理解,中间件成了必不可少,完全错了,中间件只是为了解耦合和提高吞吐!
    如果你的 socket 服务端可以做到精确命中目标连接所在服务器然后转发,那么 mq 这一层显然必要性就不高了,毕竟你只有 10 台机器的压力负载
    guyeu
        7
    guyeu  
       2020-06-02 18:22:41 +08:00
    @inktiger #4 这个东西有一些限制,具体用起来也不像消息队列那种订阅 /推送的模式舒服,各种客户端的支持也不见得好。但它确实能解决你提出的那个问题。
    shenjixiang
        8
    shenjixiang  
       2020-06-02 18:36:21 +08:00
    @opengps 不用 mq 队列,那怎么保证消息先后到达的顺序呢?
    shenjixiang
        9
    shenjixiang  
       2020-06-02 18:39:50 +08:00
    lz 提出的这个问题完全是数据结构的设计问题。。
    opengps
        10
    opengps  
       2020-06-02 18:45:13 +08:00
    @shenjixiang 你用了 mq 也仅仅是对到达服务器的顺序做了个强制排序而已。
    我做过类似聊天业务,回想下业务场景,一对一私聊,0.1 秒的时差就已经足够对消息排序了。即使把并发考虑到钉钉那种 5000 人大群的规模,用微秒本身去排序也没啥大问题的,因为同一微秒的消息即使乱序,也已经不会对群消息造成直接影响了(网络因素本身就已经不能让消息不是微秒级别都准确了)
    inktiger
        11
    inktiger  
    OP
       2020-06-02 18:45:26 +08:00
    @opengps 其实 mq 也有一个作用就是定位到消息推送到长连接所在用户的那一台服务器
    nwljy
        12
    nwljy  
       2020-06-02 18:55:52 +08:00
    RocketMQ 自身可以支持 webscoket ( Kafka )
    opengps
        13
    opengps  
       2020-06-02 18:56:12 +08:00
    @inktiger 是的,达到业务效果怎么着都行。我最早的交换通信就是只用 memcached 全局共享存下所有公网连接信息,然后各个服务器收到消息通过 memcached 找准服务器,然后内网用短链接精准转发消息
    opengps
        14
    opengps  
       2020-06-02 18:57:36 +08:00
    @nwljy 虽然可以,但是这个功能你不会真敢用在公网吧? im 通信一定得用一套自己的通信协议来实现数据加密的
    qinxi
        15
    qinxi  
       2020-06-02 23:49:34 +08:00
    每个集群节点订阅自己的 $ip_$port_quenename, 自己 redis 维护一份 用户连接所在服务器所订阅的队列名. ,需要给他发消息,就发到对应服务器的队列
    tairan2006
        16
    tairan2006  
       2020-06-03 08:19:01 +08:00 via Android
    直接用 mqtt 不就完了
    inktiger
        17
    inktiger  
    OP
       2020-06-03 10:19:15 +08:00
    @qinxi 其实我就是这么做的,但是如果有群发的情况,当用户都分布在不同服务器的时候,你就得去挨个读取用户的所在服务器,我就在想这样会不会量大的时候读不过来
    yyConstantine
        18
    yyConstantine  
       2020-06-03 10:34:13 +08:00
    @inktiger 简单粗暴一点直接广播消费呢?
    inktiger
        19
    inktiger  
    OP
       2020-06-03 11:24:34 +08:00
    @yyConstantine 广播消费的话太浪费资源了,还是精准推送节约点
    ljzxloaf
        20
    ljzxloaf  
       2020-06-03 15:43:23 +08:00
    用户建立连接时,查看当前服务器是否已经订阅了该用户所属的所有群的 queue,没有的话去订阅;连接关闭时,就像引用计数一样,判断下哪些 queue 已经用不到了,取消订阅。

    没做过,纯脑洞。感觉这样的话建立连接和关闭连接的开销也不小。。
    jaylee4869
        21
    jaylee4869  
       2020-12-29 15:20:40 +08:00
    前段时间看到这个问题,没想到就碰到了。写了一篇文章总结: https://lawrenceli.me/blog/websocket-cluster
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1433 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 17:44 · PVG 01:44 · LAX 09:44 · JFK 12:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.