微服务方案中 Socket 和 WebSocket 如果实现多实例负载呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
coala
V2EX    Java

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

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

    其他模块依赖 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     Solana     878 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:12 PVG 05:12 LAX 14:12 JFK 17:12
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86