Recientemente intenté configurar el enrutamiento basado en SNI en HAProxy para mongodb+srv
la conexión del protocolo mongodb.
Lo hice funcionar, pero no fue hasta que puse
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
en mi configuración de frontend que comenzó a funcionar correctamente
Sin estos (ocon solo unode estos) Seguí recibiendo restablecimientos de conexión esporádicos para alrededor del 70% de mis solicitudes. Tenga en cuenta que en algún momento la conexión logró establecerse.
De acuerdo ahttp://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-tcp-request%20content
Las reglas basadas en contenido se evalúan en su orden exacto de declaración. Si ninguna regla coincide o si no hay ninguna regla, la acción predeterminada es aceptar el contenido. No existe un límite específico para el número de reglas que pueden insertarse.
Entonces debería haber estado funcionando de forma predeterminada.
O me falta algún concepto fundamental de TCP o algún detalle específico de la conexión Mongo. Pero me he dado cuenta de que casi todo el mundo tiene definida la misma regla cuando opta por el enrutamiento basado en SNI, por lo que debe tener sentido para la mayoría de las personas.
Configuración de HAProxy en funcionamiento:
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
También vale la pena mencionar que HAProxy está implementado en Kubernetes (clúster administrado por Google en GCP), tiene un istio-sidecar y está expuesto a través del servicio Internal LoadBalancer k8s.
Como se indicó, la configuración anterior funciona perfectamente. Lo que me interesa es por qué tcp-request content accept
es absolutamente necesario y la conexión no [siempre] se acepta de forma predeterminada aquí.
Respuesta1
Intentaré responder mi propia pregunta después de pensarlo un poco.
Entonces, los documentos de HAProxy también tienen la siguiente mención: http://cbonte.github.io/haproxy-dconv/2.0/configuration.html
Si es necesario cambiar de contenido, se recomienda esperar primero un saludo completo del cliente (tipo 1), como en el siguiente ejemplo.
Ahora, dado que los datos SNI también están contenidos en la sección Hola del cliente de la solicitud (https://www.rfc-editor.org/rfc/rfc6066#page-6) mi suposición es la siguiente:
En el caso de que Client Hello se distribuya en varios paquetes TCP y no tcp-request content accept is configured
, al recibir el primer paquete, HAProxy intenta enrutarlo y sucede una de dos cosas:
- Si se configura el backend predeterminado, el paquete se reenvía a este backend.
- Si no se configura ningún backend predeterminado (mi caso), el paquete se descarta y se restablece la conexión.
También tenga en cuenta que incluso en el primer caso descrito, el servidor al que apunta HAProxy en la sección backend también podría requerir SNI. Por lo tanto, reenviar una solicitud incompleta sin la indicación SNI también resultará en el restablecimiento de la conexión.