Go 谷歌云HTTP(S)负载平衡器不取消与后端的连接
我有一个Google Kubernetes引擎集群,在几个带有Go 谷歌云HTTP(S)负载平衡器不取消与后端的连接,go,kubernetes,google-kubernetes-engine,http-1.1,google-cloud-load-balancer,Go,Kubernetes,Google Kubernetes Engine,Http 1.1,Google Cloud Load Balancer,我有一个Google Kubernetes引擎集群,在几个带有NodePorts的pod中,所有这些都通过一个Ingress公开,它创建了一个HTTP负载平衡器(LB)。我正在使用自定义域与谷歌管理的SSL证书的LB 我的后端是一个用Go编写的HTTP服务器,使用它的“net/HTTP”包。它使用带LB的MTL自签名证书(Google的HTTP LB接受MTL的任何证书) 除了一种情况外,一切都正常工作,即客户端与LB创建HTTP 1.1连接,然后取消请求。这将取消客户端和LB之间的连接,但LB
NodePort
s的pod中,所有这些都通过一个Ingress
公开,它创建了一个HTTP负载平衡器(LB)。我正在使用自定义域与谷歌管理的SSL证书的LB
我的后端是一个用Go编写的HTTP服务器,使用它的“net/HTTP”
包。它使用带LB的MTL自签名证书(Google的HTTP LB接受MTL的任何证书)
除了一种情况外,一切都正常工作,即客户端与LB创建HTTP 1.1连接,然后取消请求。这将取消客户端和LB之间的连接,但LB将保持与我的后端的开放连接,直到服务器超时
我的用例要求打开请求,甚至需要几个小时,所以我的服务器有巨大的超时值。请求内部的业务逻辑正确地使用了请求的上下文
,并考虑了客户端是否取消了请求
如果客户端发出HTTP2请求并取消它(即,到我的后端的整个连接被取消),则一切正常
下面是一个模拟可取消长期运行任务的Go处理程序示例:
func handleLongRunningTask(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
t := time.Now()
select {
case <-ctx.Done():
log.Println("request canceled")
case <-time.After(30 * time.Second):
log.Println("request finished")
}
log.Printf("here after: %v\n", time.Since(t))
w.WriteHeader(http.StatusOK)
}
这并不是:
curl -v --http1.1 'https://example.com/long_running_task'
无论NodePort
是HTTPS还是HTTP2,LB对于客户端取消的请求都有完全相同的行为
我试着用Go 1.14.4和1.13.12编译服务器,结果是一样的
这是Kubernetes、Ingres、Google Kubernetes引擎、Google的HTTP负载平衡器、Go的HTTP服务器中的一个bug吗?还是我缺少了HTTP 1.1的某些功能?可能有什么问题,我如何解决
…不可能知道后端的HTTP版本,因此我可以拒绝所有HTTP 1.1请求。LB在与其后端通信时始终使用相同的HTTP版本,无论客户端的HTTP版本如何。根据您的描述,问题可能出现在和后端之间,因为 我的看法是,您看到了协议版本之间的这种差异,因为它们都处理连接持久性 对于HTTP2,连接将打开。但对于HTTP1.1,指定终止: HTTP/1.1服务器可能假设HTTP/1.1客户端打算维护持久连接,除非在请求中发送了包含连接令牌“close”的连接头。如果服务器选择在发送响应后立即关闭连接,则应发送一个包含连接令牌close的连接头 这也许可以解释为什么HTTP1.1遵循了标准,而HTTP2没有 我建议在您想要终止连接时尝试主动发送终止头。安: 此外,似乎有一些成功的案例将您的集群转变为现实,因为它消除了kube代理连接管理 最后,你可能处于一个非常特殊的情况,值得单独评估。您可能希望尝试使用向GKE团队发送一些复制步骤
我希望这会有所帮助。我已经尝试了HTTP(S)1.1和HTTP2后端,即使在客户端发出HTTP 1.1请求,LB向后端发出HTTP2请求(BE)的情况下,行为也是一样的,即当客户端取消其请求时,LB和BE之间的HTTP2连接不会终止。我的用例是特定的,因为在客户端取消请求之前,我的服务器一直在处理。因此,
连接
标题已退出游戏。我需要在LB和BE之间进行适当的请求取消。强制所有客户机使用HTTP2仍然是不可能的:(我打开了一个我忘记的问题;我的集群是VPC原生的。
curl -v --http1.1 'https://example.com/long_running_task'
func (m *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Printf("HTTP request from %s", r.RemoteAddr)
// Add this header to force to close the connection after serving the request.
w.Header().Add("Connection", "close")
fmt.Fprintf(w, "%s", m.hostname)
}