Ich verwende einen HAProxy-Lastausgleichsserver, um die Last auf mehrere Apache-Server zu verteilen. Ich muss HAProxy jederzeit neu laden, um den Algorithmus für den Lastenausgleich zu ändern.
Dies alles funktioniert einwandfrei, mit der Ausnahme, dass ich den Server neu laden muss, ohne ein einziges Paket zu verlieren (im Moment führt ein erneutes Laden zu einem durchschnittlichen Erfolg von 99,76%, mit 1000 Anfragen pro Sekunde für 5 Sekunden). Ich habe viele Stunden lang nachgeforscht und den folgenden Befehl gefunden, um den HAProxy-Server ordnungsgemäß neu zu laden:
haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
Dies hat jedoch nur geringe oder keine Auswirkungen im Vergleich zum normalen Alter service haproxy reload
, es fällt durchschnittlich immer noch um 0,24%.
Gibt es eine Möglichkeit, die HAProxy-Konfigurationsdatei neu zu laden, ohne dass ein Benutzer ein einzelnes Paket fallen lässt?
Antworten:
Laut https://github.com/aws/opsworks-cookbooks/pull/40 und folglich http://www.mail-archive.com/[email protected]/msg06885.html können Sie:
quelle
iptables v1.4.14: invalid port/service
Folgendes : --syn "Angegeben"$PORT
den aktuellen Port ersetzen sollen,haproxy
lauscht. Wenn haproxy mehrere Ports überwacht, schreiben Sie "replace"--dport $PORT
mit--dports $PORTS_SEPARATED_BY_COMMAS
z--dports 80,443
.Yelp verfolgte einen differenzierteren Ansatz, der auf sorgfältigen Tests basierte. Der Blog-Artikel ist ein intensiver Tauchgang und es lohnt sich, Zeit zu investieren, um ihn vollständig zu würdigen.
HAProxy-Reloads ohne Ausfallzeiten
Verwenden Sie Linux tc (Traffic Control) und iptables, um SYN-Pakete vorübergehend in die Warteschlange zu stellen, während HAProxy neu lädt und zwei Pids an denselben Port (
SO_REUSEPORT
) angeschlossen sind.Es ist mir unangenehm, den gesamten Artikel auf ServerFault erneut zu veröffentlichen. dennoch sind hier ein paar auszüge, um ihr interesse zu wecken:
Inhalt: https://gist.github.com/jolynch/97e3505a1e92e35de2c0
Ein Hoch auf Yelp für den Austausch solch erstaunlicher Einsichten.
quelle
Es gibt einen anderen, viel einfacheren Weg, um Haproxy mit einer Ausfallzeit von Null neu zu laden - es heißt iptables flipping (der Artikel ist eigentlich Unbounce-Antwort auf Yelp-Lösung). Es ist sauberer als akzeptierte Antworten, da keine Pakete verworfen werden müssen, die Probleme mit langen Nachladevorgängen verursachen könnten.
Kurz gesagt besteht die Lösung aus den folgenden Schritten:
iptable
Befehlen erledigt .Darüber hinaus kann die Lösung auf alle Arten von Diensten (Nginx, Apache usw.) angewendet werden und ist fehlertoleranter, da Sie die Standby-Konfiguration testen können, bevor sie online geht.
quelle
Bearbeiten: Meine Antwort geht davon aus, dass der Kernel nur Verkehr an den letzten Port sendet, der mit SO_REUSEPORT geöffnet werden soll, während er tatsächlich Verkehr an alle Prozesse sendet, wie in einem der Kommentare beschrieben. Mit anderen Worten, der Iptables-Tanz ist weiterhin erforderlich. :(
Wenn Sie sich in einem Kernel befinden, der SO_REUSEPORT unterstützt, sollte dieses Problem nicht auftreten.
Der Prozess, den Haproxy beim Neustart ausführt, ist:
1) Versuchen Sie, SO_REUSEPORT festzulegen, wenn Sie den Port öffnen ( https://github.com/haproxy/haproxy/blob/3cd0ae963e958d5d5fb838e120f1b0e9361a92f8/src/proto_tcp.c#L792-L798 ).
2) Versuchen Sie den Port zu öffnen (wird mit SO_REUSEPORT erfolgreich sein)
3) Wenn dies nicht erfolgreich war, signalisieren Sie dem alten Prozess, dass der Port geschlossen werden soll, warten Sie 10 ms und wiederholen Sie den Vorgang. ( https://github.com/haproxy/haproxy/blob/3cd0ae963e958d5d5fb838e120f1b0e9361a92f8/src/haproxy.c#L1554-L1577 )
Es wurde zuerst im Linux 3.9-Kernel unterstützt, aber einige Distributionen haben es zurückportiert. Zum Beispiel unterstützen EL6-Kernel von 2.6.32-417.el6 dies.
quelle
SO_REUSEPORT
unter bestimmten Umständen passieren - insbesondere unter starkem Verkehr. Wenn SYN an den alten Haproxy-Prozess gesendet wird und im selben Moment den Listening-Socket schließt, führt dies zu RST. Siehe oben in einer anderen Antwort genannten Yelp-Artikel.Ich erkläre mein Setup und wie ich die anmutigen Nachladevorgänge gelöst habe:
Ich habe ein typisches Setup mit 2 Knoten mit HAproxy und Keepalived. Keepalived Tracks Interface Dummy0, also kann ich ein "ifconfig Dummy0 down" machen, um das Umschalten zu erzwingen.
Das eigentliche Problem ist, dass bei einem "haproxy reload" immer noch alle eingerichteten Verbindungen getrennt werden :( Ich habe das von gertas vorgeschlagene "iptables flipping" ausprobiert, aber ich habe einige Probleme gefunden, weil es ein NAT auf dem Ziel ausführt IP-Adresse, die in einigen Szenarien nicht geeignet ist.
Stattdessen habe ich mich entschieden, einen CONNMARK-Dirty-Hack zu verwenden, um Pakete zu markieren, die zu NEUEN Verbindungen gehören, und diese markierten Pakete dann auf den anderen Knoten umzuleiten.
Hier ist der Iptables-Regelsatz:
Die ersten beiden Regeln kennzeichnen die Pakete, die zu den neuen Flows gehören (123.123.123.123 ist der Keepalived-VIP, der auf dem Haproxy zum Binden der Frontends verwendet wird).
Die dritte und vierte Regel markieren Pakete FIN / RST-Pakete. (Ich weiß nicht warum, TEE-Ziel "ignoriert" FIN / RST-Pakete).
Die fünfte Regel sendet ein Duplikat aller markierten Pakete an den anderen HAproxy (192.168.0.2).
Die sechste Regel verwirft Pakete, die zu neuen Flüssen gehören, um zu verhindern, dass sie ihr ursprüngliches Ziel erreichen.
Denken Sie daran, rp_filter auf Interfaces zu deaktivieren, da der Kernel diese Martian-Pakete sonst verwirft.
Und last but not least, achten Sie auf die zurückgegebenen Pakete! In meinem Fall gibt es asymmetrisches Routing (Anfragen kommen zu Client -> haproxy1 -> haproxy2 -> Webserver und Antworten gehen von Webserver -> haproxy1 -> Client), aber es hat keine Auswirkungen. Es funktioniert gut.
Ich weiß, die eleganteste Lösung wäre, iproute2 für die Umleitung zu verwenden, aber es hat nur für das erste SYN-Paket funktioniert. Als es das ACK (3. Paket des 3-Wege-Handshakes) erhielt, wurde es nicht markiert :( Ich konnte nicht viel Zeit für Nachforschungen aufwenden, sobald ich sah, dass es mit dem TEE-Ziel funktioniert, ließ es es dort. Natürlich können Sie es auch mit iproute2 ausprobieren.
Grundsätzlich funktioniert das "Graceful Reload" so:
Der IPtables-Regelsatz kann einfach in ein Start / Stopp-Skript integriert werden:
quelle