如何让长连接负责均衡呢?

115 天前
 dampler

假设我们有以下机器:

现客户端每隔 10s 向服务器上报心跳,流量路径客户端>CLB>服务器,使用的是 http 连接,keep-alive 设置的 30s 。按理来说连接经过 CLB ,服务器负责的连接是均衡的。

现在,假设故障了 4 台服务器,流量会偏移到一台服务器上,现在重启这 4 台机器,这些连接由于 keep-alive ,不会重新分布。

请问,这种问题怎么解决呢?

2464 次点击
所在节点    Go 编程语言
32 条回复
cz5424
115 天前
都用 http 了,http 一般都人为是无状态的,我感觉你是 http 请求了之后,不完成,一直挂着链接
cz5424
115 天前
服务端通知客户端断线,让客户端重连,就均衡了
dampler
115 天前
@cz5424 有两种方案啊,一种是客户端定时断开重连。另外还有一种是服务端主动断开,想问问,服务端主动断开连接的细节是咋样的,老哥有了解吗?我们用的是 go ,gin 框架
dampler
115 天前
@cz5424 给个关键字就好,其他的我再去找找资料
dampler
115 天前
@cz5424 这个通知客户端连接,咋个操作哦,那我还得记录这个连接的时间啊,比如 30s ,主动在 header 头里通知客户端断开连接吗?
fds
115 天前
我个人其实觉得不是什么大问题。大不了等那 4 台好了,把之前那 1 台重启一下,全部断开连接。问了下 GPT ,说是可以在服务内部根据情况给客户端发送关闭连接的 header 。

func main() {
router := gin.Default()
router.Use(func(c *gin.Context) {
// 可以根据具体情况决定是否关闭连接
c.Header("Connection", "close")
c.Next()
})

router.GET("/heartbeat", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})

router.Run() // 默认在 localhost:8080
}

话说应该怎么格式化代码呢?
fds
115 天前
不过你这种架构我觉得还是应该负载均衡 LB 自己处理这些连接问题,直接断掉连接等重连就行。
csys
115 天前
如果是 http1.1+keep-alive 做长连接,现有负载均衡应该是能正常工作的,keep-alive 超时 tcp 链接就会被关闭,你新发送的请求就会开启新的链接

客户端请求头上的 keepalive 好像指定的是保持连接的最小时长(这个我不太确定
服务端可以配置 keepalive 的超时时间
dampler
115 天前
@csys 这 keep-alive=30 ,表示 30s 内如果没有请求就会断开,现在心跳每 10s 一次,就比较尴尬了
dampler
115 天前
@csys gin 框架没有看到有这个参数,老哥有了解吗
dampler
115 天前
@fds clb 上可配置的参数太少了,用的腾讯云
dampler
115 天前
@fds 这里有个问题,什么时候发送 close
csys
114 天前
@dampler 可以参考 timeout 中间件,请求头上的 keepalive 不是个强制超时时间,而是给服务端的一个暗示,表示“需要保持 xx 秒的长连接”,具体什么时候 close 取决于双方的设置,如果库或框架没有自动 close ,你直接定时 close 就行
dampler
114 天前
@csys 明白你的意思了,是通过中间件,判断建连的时间和当前时间的差值,超过设定的值就 close 。(我去找找,看看能不能获取建连的时间,这一块我去了解下 Thx )
lasuar
114 天前
1. 首先客户端要支持无感重连
2. 服务端长连接程序能够感知其他节点的启动时间和负载压力,然后根据自己的负载压力决定是否要进行主动连接断开(无感的关键是通过自定义消息通知客户端,而不是简单断连)
lasuar
114 天前
3. 决定要进行断连时,选择较老且**空闲**的连接进行断开。
gongguowei02
114 天前
@dampler #10 应该是直接可以 set 在 headers 里面的,试一下?
coderxy
114 天前
不要用 clb , 用 alb ,alb 负责与客户端连接,客户端请求 alb 再转发到 ecs 时关闭长连接,这样每次都是新建一个 http 连接了。
xxs55
114 天前
把长连接 单独一个服务 然后 rpc 调用 其他服务可以不。
mingyuewandao
114 天前
讲真,我之前也探索过类似的问题,但没有得到很好的答案。对于长链接,如果是 grpc 这种,通常要通过客户端负载均衡来做。如果加了 lb 后,客户端无法感知服务端服务器变化,因此客户端负载均衡肯定行不通。此时应该由 lb 来提供对应能力。如果通过连接经过 lb 已经建立,lb 如何重新调整是个问题,我也没有想到应该如何做。因此问了下 GPT ,以下可做参考:



在这种情况下,服务器故障后重启,由于 HTTP 连接的 keep-alive 特性,现有的连接可能不会立即重新分布到所有服务器上,这可能导致剩余的服务器负载过高。以下是一些可能的解决方案:

1. **重置连接**:在服务器重启后,可以配置负载均衡器( CLB )发送一个重置信号给客户端,通知它们现有的连接已经无效,需要重新建立连接。这可以通过 HTTP 响应状态码如`408 Request Timeout`或`503 Service Unavailable`来实现。

2. **调整 keep-alive 超时**:如果可能,可以在服务器重启前调整 HTTP 连接的 keep-alive 超时时间,使其更短,这样在服务器重启后,客户端会更快地重新建立连接。

3. **使用更智能的负载均衡策略**:一些负载均衡器支持基于服务器当前负载的动态调整流量分配的策略。如果 CLB 支持这种策略,可以在服务器重启后动态调整流量分配。

4. **客户端重连机制**:客户端可以在检测到服务器故障或响应超时时,自动尝试重新连接到其他健康的服务器。

5. **使用会话持久性**:如果 CLB 支持会话持久性( session persistence ),可以配置它在服务器重启后将流量重新分配给所有可用的服务器,而不是只连接到一台服务器。

6. **心跳机制调整**:可以调整客户端的心跳上报机制,使其在检测到服务器故障时,立即断开连接并重新连接到其他服务器。

7. **使用更高级的负载均衡技术**:例如使用基于 IP 的负载均衡,这样即使 TCP 连接保持打开状态,新的请求也可以被分配到不同的服务器。

8. **监控和自动化**:实现监控系统来检测服务器状态和负载情况,一旦检测到故障或负载不均衡,自动化脚本可以介入,进行流量重新分配或触发重连机制。

9. **使用 WebSocket**:如果适用,可以考虑使用 WebSocket 代替 HTTP 长连接,因为 WebSocket 提供了一个全双工通信渠道,可以在服务器端更容易地管理连接状态。

10. **服务发现**:使用服务发现机制,让客户端能够动态地发现可用的服务实例,并在必要时重新连接。

选择哪种解决方案取决于具体的应用场景、现有的技术栈以及可接受的复杂度。在实际应用中,可能需要结合多种策略来确保系统的高可用性和负载均衡。

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

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

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

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

© 2021 V2EX