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

2022-04-28 08:40:32 +08:00
 coala

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

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

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

想做到升级服务不中断

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

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

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

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

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

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

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

不建议客户端在感知到连接断开后自动重新启动。除非你能保证常规客户端连接成功(连接加注册加鉴权等)的几率接近 100%,否则当连接失败的客户端多了之后,会形同与向服务器发动拒绝服务攻击。
Chengxians
2022-04-28 09:46:25 +08:00
最近弄 socket 启动多实例注册到 nacos , 每个实例 socket 连接存到内存中得 每个实例都订阅了 redis ,A 发 B 或者群发得时候用 redis 推送,每个实例监听到就找自己实例有没有这个连接,有就发送,没有得实例就浪费点资源查找
fds
2022-04-28 09:47:49 +08:00
啥服务重启要 1 分钟呀?启动新的可以先不关闭旧的,新的每秒尝试 bind 端口,等新的 ready 了再停旧的,这样也就不到 2s 的切换时间。
进阶版在 linux 下是可以进程间传递 socket 连接,不断连的,但是要处理好状态、读写缓存啥的,比较麻烦。
sciel
2022-04-28 10:06:35 +08:00
https://github.com/Terry-Mao/goim 可以看看 goim 的结构,不错~
lotusp
2022-04-28 10:19:41 +08:00
在微服务上下文里,不管是短连接还是长连接,前端打交道的后端应该都不止一个
可以专门为长连接建立一个 gateway ,这一层对前端是长连接,对后端可以长连接,也可以短连接
后端服务升级重启做到优雅退出,就不影响前端
xuanbg
2022-04-28 13:57:38 +08:00
微服务升级不中断 Socket 是不可能的
GopherDaily
2022-04-28 14:23:00 +08:00
不中断是不可能的,做好重连就行。
长链接的负载均衡可以参考下 grpc 相关的
coala
2022-04-28 15:08:41 +08:00
@MoYi123 很酷
meeop
2022-04-28 15:17:15 +08:00
为什么要不中断,连接就是要随意可中断才行,断了重连就是

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/849702

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX