mongodb+srv
Ich habe kürzlich versucht, SNI-basiertes Routing auf HAProxy für eine MongoDB -Protokollverbindung einzurichten .
Ich habe es zum Laufen gebracht, aber erst als ich
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
in meiner Frontend-Konfiguration, dass es richtig funktionierte
Ohne diese (odermit nur einemdavon) Bei etwa 70 % meiner Anfragen kam es immer wieder zu sporadischen Verbindungsabbrüchen. Beachten Sie, dass die Verbindung manchmal tatsächlich hergestellt werden konnte.
Entsprechendhttp://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-tcp-request%20content
Inhaltsbasierte Regeln werden in der genauen Reihenfolge ihrer Deklaration ausgewertet. Wenn keine Regel übereinstimmt oder keine Regel vorhanden ist, besteht die Standardaktion darin, den Inhalt zu akzeptieren. Es gibt keine bestimmte Begrenzung für die Anzahl der Regeln, die eingefügt werden können.
Es sollte also standardmäßig funktionieren.
Entweder übersehe ich ein grundlegendes TCP-Konzept oder ein bestimmtes Mongo-Verbindungsdetail. Aber mir ist aufgefallen, dass fast jeder die gleiche Regel definiert hat, wenn er sich für SNI-basiertes Routing entscheidet, also muss es für die meisten Leute Sinn ergeben.
Funktionierende HAProxy-Konfiguration:
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
Erwähnenswert ist auch, dass HAProxy in Kubernetes (von Google verwalteter Cluster in GCP) bereitgestellt wird, über einen Istio-Sidecar verfügt und über den Internal LoadBalancer k8s-Dienst verfügbar gemacht wird.
Wie gesagt funktioniert die obige Konfiguration einwandfrei. Mich interessiert, warum dies tcp-request content accept
unbedingt erforderlich ist und die Verbindung hier nicht [immer] standardmäßig akzeptiert wird.
Antwort1
Ich werde versuchen, meine eigene Frage zu beantworten, nachdem ich darüber nachgedacht habe.
Daher enthalten die HAProxy-Dokumente auch Folgendes: http://cbonte.github.io/haproxy-dconv/2.0/configuration.html
Wenn ein Inhaltswechsel erforderlich ist, wird empfohlen, zunächst auf ein vollständiges Client-Hello (Typ 1) zu warten, wie im folgenden Beispiel.
Da die SNI-Daten nun auch im Abschnitt „Client Hello“ der Anfrage enthalten sind (https://www.rfc-editor.org/rfc/rfc6066#page-6) meine Vermutung ist folgende:
Falls Client Hello über mehrere TCP-Pakete verteilt ist und kein tcp-request content accept is configured
, versucht HAProxy beim Empfang des ersten Pakets, es weiterzuleiten, und es passiert eines der folgenden zwei Dinge:
- Wenn das Standard-Backend konfiguriert ist, wird das Paket an dieses Backend weitergeleitet.
- Wenn kein Standard-Backend konfiguriert ist (mein Fall), wird das Paket gelöscht und die Verbindung zurückgesetzt.
Beachten Sie auch, dass selbst im ersten beschriebenen Fall der Server, auf den HAProxy im Backend-Abschnitt verweist, möglicherweise ebenfalls SNI erfordert. Das Weiterleiten einer unvollständigen Anfrage ohne SNI-Angabe führt daher ebenfalls zur Zurücksetzung der Verbindung.