我最近嘗試在 HAProxy 上設定基於 SNI 的路由以進行 mongodbmongodb+srv
協定連接。
我讓它工作了,但直到我把
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,並透過內部 LoadBalancer k8s 服務公開。
如上所述,上述配置運作良好。我感興趣的是為什麼這tcp-request content accept
是絕對必需的,並且默認情況下不[總是]接受連接。
答案1
經過一番思考後,我將嘗試回答自己的問題。
因此,HAProxy 文件也提到了以下內容: http://cbonte.github.io/haproxy-dconv/2.0/configuration.html
如果需要內容切換,建議先等待完整的用戶端問候(類型 1),如下例所示。
現在,由於 SNI 資料也包含在請求的 Client Hello 部分中(https://www.rfc-editor.org/rfc/rfc6066#page-6)我的假設如下:
如果 Client Hello 分佈在多個 TCP 封包中且 no tcp-request content accept is configured
,則在收到第一個封包後,HAProxy 會嘗試路由它,並且會發生以下兩種情況之一:
- 如果配置了預設後端,則封包將轉送到該後端。
- 如果沒有配置預設後端(我的情況),資料包將被丟棄並重置連接。
另請注意,即使在描述的第一種情況下,後端部分中指向的伺服器 HAProxy 也可能需要 SNI。因此轉送不帶 SNI 指示的不完整請求也會導致連線重設。