我有一个 Google Kubernetes Engine 集群,在几个带有NodePort
s 的 pod 中,所有的都通过 暴露Ingress
,它创建了一个 HTTP 负载均衡器 (LB)。我正在为 LB 使用带有 Google 托管 SSL 证书的自定义域。
我的后端是一个用 Go 编写的 HTTP 服务器,使用它的"net/http"
包。它使用带有 LB 的 mTLS 的自签名证书(Google 的 HTTP LB 接受任何 mTLS 证书)。
一切正常,除了一种情况,即客户端创建与 LB 的 HTTP 1.1 连接,然后取消请求。这会取消客户端和 LB 之间的连接,但 LB 会与我的后端保持打开连接,直到服务器超时。
我的用例要求打开请求甚至几个小时,所以我的服务器有很大的超时值。请求中的业务逻辑正确使用了请求Context
,并考虑了请求是否被客户端取消。
如果客户端发出 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)
}
case <-ctx.Done():
永远不会为取消的 HTTP 1.1 请求调用。
为了便于测试,我使用 curl 和Ctrl+C
; 这有效:
curl -v --http2 'https://example.com/long_running_task'
这不会:
curl -v --http1.1 'https://example.com/long_running_task'
不管NodePort
是 HTTPS 还是 HTTP2,LB 对客户端取消的请求的行为完全相同。
我尝试用 Go 1.14.4 和 1.13.12 编译服务器,结果是一样的。
这是 Kubernetes、Ingress、Google Kubernetes Engine、Google 的 HTTP 负载均衡器、Go 的 HTTP 服务器中的错误吗?还是我缺少 HTTP 1.1 的东西?有什么问题,我该如何解决?
...不可能知道后端的 HTTP 版本,所以我可以拒绝所有 HTTP 1.1 请求。LB 在与其后端通信时始终使用相同的 HTTP 版本,无论客户端的 HTTP 版本如何。