我最近尝试在 HAProxy 上为 mongodbmongodb+srv
协议连接设置基于 SNI 的路由。
我让它工作,但直到我把它
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
在我的前端配置中它开始正常工作
如果没有这些(或只有其中之一),我的大约 70% 的请求会不断收到零星的连接重置。请注意,有时连接确实能够建立。
根据http://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-tcp-request%20content
基于内容的规则按照它们的确切声明顺序进行评估。如果没有规则匹配或没有规则,则默认操作是接受内容。可插入的规则数量没有具体限制。
所以它应该默认工作。
要么是我遗漏了一些基本的 TCP 概念,要么是一些特定的 Mongo 连接细节。但我注意到几乎每个人在选择基于 SNI 的路由时都定义了相同的规则,因此它对大多数人来说一定是有意义的。
工作 HAProxy 配置:
frontend fe_mongo-nonprod
bind :27017
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net
use_backend be_mongo-nonprod if mongoAtlas-01 || mongoAtlas-02 || mongoAtlas-03
backend be_mongo-nonprod
mode tcp
acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net
use-server server-01 if mongoAtlas-01
use-server server-02 if mongoAtlas-02
use-server server-03 if mongoAtlas-03
server server-01 host1.mongodb.net:27017
server server-02 host2.mongodb.net:27017
server server-03 host3.mongodb.net:27017
还值得一提的是,HAProxy 部署在 Kubernetes(GCP 中由 Google 管理的集群)中,具有 istio-sidecar 并通过 Internal LoadBalancer k8s 服务公开。
如上所述,上述配置运行良好。我感兴趣的是为什么tcp-request content accept
绝对需要并且这里默认情况下 [always] 不接受连接。
在考虑一下之后,我将尝试回答我自己的问题。
因此,HAProxy 文档也有以下提及: http ://cbonte.github.io/haproxy-dconv/2.0/configuration.html
现在,由于 SNI 数据也包含在请求的客户端问候部分中 ( https://www.rfc-editor.org/rfc/rfc6066#page-6 ),我的假设如下:
在这种情况下,如果 Client Hello 分布在多个 TCP 数据包中,并且没有
tcp-request content accept is configured
,在收到第一个数据包时,HAProxy 会尝试路由它,并且会发生以下两种情况之一:另请注意,即使在第一种情况下描述的服务器 HAProxy 指向后端部分也可能需要 SNI。因此在没有 SNI 指示的情况下转发不完整的请求也会导致重置连接。