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

微服务方案中 Socket 和 WebSocket 如果实现多实例负载呢?

  •  
  •   coala ·
    qq418745 · 2022-04-28 08:40:32 +08:00 · 4130 次点击
    这是一个创建于 780 天前的主题,其中的信息可能已经有所发展或是发生改变。

    其他模块依赖 Redis 共享缓存和资源, 可以比较方便的实现多实例同时跑。

    定时任务只好跑个单实例, 尽量让它简单化不出故障.

    Socket 这块怎么办比较好呢, 我需要维护几百个长链接.

    想做到升级服务不中断

    现在的想法式尽量抽取 Socket 服务端, 后期尽量不修改...

    第 1 条附言  ·  2022-04-28 15:34:33 +08:00
    其实就是想实现业务不中断.

    现在实现的比较简陋, 自己的想法就是抽取, 就是 Socket 服务端简单化(心跳,连接, 收发消息).
    提供成 HTTP 服务给其他服务调用,尽量不改动., 客户端重新连接的也设计时间比较慢.

    目的就是想实现升级业务不中断, 然后多机负载(后期怕一台撑不住) ,

    多实例负载和多实例负载带来的 AB 升级问题实在不知道怎么做..

    感谢大家的回复!
    29 条回复    2022-04-29 22:04:13 +08:00
    buruoyanyang
        1
    buruoyanyang  
       2022-04-28 08:44:07 +08:00
    插眼,我们也有这样的需求,想学习
    THESDZ
        2
    THESDZ  
       2022-04-28 08:54:54 +08:00   ❤️ 1
    1.Socket 多实例,不做任何状态保存,状态存到外部,例如每次传输携带 token 等
    2.采取环形 hash 的方式进行节点分配
    licoycn
        3
    licoycn  
       2022-04-28 09:01:16 +08:00   ❤️ 1
    只要有完善重连机制即可,做好状态维护
    coala
        4
    coala  
    OP
       2022-04-28 09:11:44 +08:00
    @licoycn 就是让客户端断了, 能够快速的自动重连就好? (我现在的业务中断个 1 -2 分钟可能就客户会叫了, 直接重启现在只敢晚上搞, 大概中断 1 分钟)

    如 @THESDZ 所说 实现环形 hash
    A 节点挂了, 赶紧重连到 B 节点, A 重启后再重启 B, 所有客户端重连到 A. 这样感觉问题也不大 (可能中断在加起来几秒?)
    licoycn
        5
    licoycn  
       2022-04-28 09:14:12 +08:00
    @coala #4 启动多个新的实例,然后再将流量转移过去,然后再将旧的实例关闭,这样之间的中断只有几秒吧
    coala
        6
    coala  
    OP
       2022-04-28 09:20:43 +08:00
    @THESDZ Socket 状态存到外部, 多个实例共享这些状态吗?
    emm.... 我有点查不到什么资料.

    有无一些推荐的 Demo 之类的开源项目做到了这些呢?
    littlefishcc
        7
    littlefishcc  
       2022-04-28 09:21:46 +08:00   ❤️ 1
    2 和 3 楼方法已经说出来了,连接要重连机制,不管你是长连接还是短连接,这块可以借鉴微信开源的网络库 mars
    我感觉作者想要一个类似 ngnix 代理,可以考虑在业务程序前加一个前置程序(一般游戏登录服务器),然后再分配到具体业务服务器。
    A[前置] + (B+C+...)[业务服务器]
    B+C 等业务服务器状态通过 redis 同步数据。
    coala
        8
    coala  
    OP
       2022-04-28 09:22:17 +08:00
    @licoycn 对哦, 这样感觉不错, 实现也比较简单
    sujin190
        9
    sujin190  
       2022-04-28 09:23:11 +08:00   ❤️ 1
    Socket 这种应该是统一接到接入网关的吧,网关不包含实际业务逻辑,一般很少需要更新重启吧,之后对内部的调用就是常规的负载均衡了
    MoYi123
        10
    MoYi123  
       2022-04-28 09:34:20 +08:00   ❤️ 2
    之前给公司做了一个比较骚的方案. 用 unix domain 传文件描述符更新长连接服务.

    https://github.com/mmooyyii/mmooyyii/tree/master/codes/share_socket
    看下这个代码吧.
    caryqy
        11
    caryqy  
       2022-04-28 09:40:20 +08:00   ❤️ 1
    增加一个 gateway 层,所有长连接都在这里,逻辑简单化,做到长期不需要修改

    gateway 与内部 rpc 通信
    nothingistrue
        12
    nothingistrue  
       2022-04-28 09:45:11 +08:00   ❤️ 1
    能跑 HTTP 负载均衡的网关,通常经过配置后就能支持长连接的负载均衡,至少 ngnix 和 caddy 是可以的,负载均衡这里不是问题。但是你这个想要的不是负责均衡而是 AB 升级,这对于长连接来说,光靠服务器就不行了。

    简单来说,你可以设计个重新连接协议:服务器下发切换服务器指令,指令里面带上新服务的 IP ,客户端收到这个指令后,断开当前连接去连接那个新 IP 。更新的时候:首先开启 B 服务器,同时 A 服务阻止新的连接;然后 A 服务器给所有当前连接下发切换服务器指令;当 A 服务器的所有连接都断开,或者超过指定时间后,A 服务器搞停、更、启这一套;之后你想切回 A 服务器就重走上面的流程,不想切就结束了(因为 B 服务器应该已经更新过了)。

    不建议客户端在感知到连接断开后自动重新启动。除非你能保证常规客户端连接成功(连接加注册加鉴权等)的几率接近 100%,否则当连接失败的客户端多了之后,会形同与向服务器发动拒绝服务攻击。
    Chengxians
        13
    Chengxians  
       2022-04-28 09:46:25 +08:00   ❤️ 1
    最近弄 socket 启动多实例注册到 nacos , 每个实例 socket 连接存到内存中得 每个实例都订阅了 redis ,A 发 B 或者群发得时候用 redis 推送,每个实例监听到就找自己实例有没有这个连接,有就发送,没有得实例就浪费点资源查找
    fds
        14
    fds  
       2022-04-28 09:47:49 +08:00   ❤️ 1
    啥服务重启要 1 分钟呀?启动新的可以先不关闭旧的,新的每秒尝试 bind 端口,等新的 ready 了再停旧的,这样也就不到 2s 的切换时间。
    进阶版在 linux 下是可以进程间传递 socket 连接,不断连的,但是要处理好状态、读写缓存啥的,比较麻烦。
    sciel
        15
    sciel  
       2022-04-28 10:06:35 +08:00   ❤️ 2
    https://github.com/Terry-Mao/goim 可以看看 goim 的结构,不错~
    lotusp
        16
    lotusp  
       2022-04-28 10:19:41 +08:00   ❤️ 1
    在微服务上下文里,不管是短连接还是长连接,前端打交道的后端应该都不止一个
    可以专门为长连接建立一个 gateway ,这一层对前端是长连接,对后端可以长连接,也可以短连接
    后端服务升级重启做到优雅退出,就不影响前端
    xuanbg
        17
    xuanbg  
       2022-04-28 13:57:38 +08:00   ❤️ 1
    微服务升级不中断 Socket 是不可能的
    GopherDaily
        18
    GopherDaily  
       2022-04-28 14:23:00 +08:00   ❤️ 1
    不中断是不可能的,做好重连就行。
    长链接的负载均衡可以参考下 grpc 相关的
    coala
        19
    coala  
    OP
       2022-04-28 15:08:41 +08:00
    @MoYi123 很酷
    meeop
        20
    meeop  
       2022-04-28 15:17:15 +08:00
    为什么要不中断,连接就是要随意可中断才行,断了重连就是
    meeop
        21
    meeop  
       2022-04-28 15:17:46 +08:00
    反之如果不能中断,那用户网随便抖一下客户端就崩了这不合适吧
    meeop
        22
    meeop  
       2022-04-28 15:19:42 +08:00
    @coala 断了重连的耗时应该是毫秒级别的,根本不会有感知.能断 2 分钟大概是你没做滚动升级吧.保证任何时刻都有可用服务器供连接就行
    coala
        23
    coala  
    OP
       2022-04-28 15:31:45 +08:00
    @meeop 客户端有重连机制, 就是现在不会很快重连, (太快重连怕服务器顶不住哇)
    Socket 实现的比较简陋, 就是单机, 然后走网关连过来, 多机不知道咋整太菜这不是来问了
    coala
        24
    coala  
    OP
       2022-04-28 15:35:24 +08:00
    @meeop 可以看看附言
    meeop
        25
    meeop  
       2022-04-28 16:34:25 +08:00
    @coala ab 升级简陋的办法是先不停止 a,先启动好 b,b 起好后把流量打到 b,然后关闭 a
    就算手动操作,这个切流量也就是 ng 刷下配置的事,很快的
    xylophone21
        26
    xylophone21  
       2022-04-28 16:47:11 +08:00
    @sciel 这个机制看起来确实很 cool ,想问一下有使用的案例或者数据吗?我们之前对 MQTT 服务做集群也考虑过类似的方案,但 MQTT 可能跨节点订阅,导致所有的流量实际还是要打到所有的节点上。但似乎没有哪个 MQTT 集群用了这种方式来做集群。
    xylophone21
        27
    xylophone21  
       2022-04-28 16:53:12 +08:00   ❤️ 1
    另外,如果你只有几百个长链接的话,可以试试 MQTT ,单机绰绰有余。这个服务本身因为抽象的很好,也不需要修改和升级,业务逻辑订阅主体后丢队列里,重启切换一些消费者就好。
    mouyong
        28
    mouyong  
       2022-04-28 19:33:59 +08:00
    workerman gatewayworker
    aSmallNewbie
        29
    aSmallNewbie  
       2022-04-29 22:04:13 +08:00
    之前使用消息队列解决的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2444 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 79ms · UTC 11:46 · PVG 19:46 · LAX 04:46 · JFK 07:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.