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:
iptables -t mangle -A PREROUTING -i eth1 -d 123.123.123.123/32 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -A PREROUTING -i eth1 -m mark --mark 1 -j DROP
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:
- Ich aktiviere den iptables-Regelsatz und sehe sofort die neuen Verbindungen zum anderen HAproxy.
- Ich behalte "netstat -an | grep ESTABLISHED | wc -l" im Auge, um den "Entleerungs" -Prozess zu überwachen.
- Sobald es nur wenige (oder keine) Verbindungen gibt, "ifconfig dummy0 down", um das Keepalived-Failover zu erzwingen, sodass der gesamte Datenverkehr zum anderen HAproxy geleitet wird.
- Ich entferne den Iptables-Regelsatz
- (Nur für "non-preempting" keepalive config) "ifconfig dummy0 up".
Der IPtables-Regelsatz kann einfach in ein Start / Stopp-Skript integriert werden:
#!/bin/sh
case $1 in
start)
echo Redirection for new sessions is enabled
# echo 0 > /proc/sys/net/ipv4/tcp_fwmark_accept
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f; done
iptables -t mangle -A PREROUTING -i eth1 ! -d 123.123.123.123 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -A PREROUTING -i eth1 -m mark --mark 1 -j DROP
;;
stop)
iptables -t mangle -D PREROUTING -i eth1 -m mark --mark 1 -j DROP
iptables -t mangle -D PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -D PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -D PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -D PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -D PREROUTING -i eth1 ! -d 123.123.123.123 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
echo Redirection for new sessions is disabled
;;
esac