Korzystam z serwera równoważenia obciążenia HAProxy, aby zrównoważyć obciążenie wielu serwerów Apache. Muszę ponownie załadować HAProxy w dowolnym momencie, aby zmienić algorytm równoważenia obciążenia.
To wszystko działa dobrze, z wyjątkiem faktu, że muszę ponownie załadować serwer bez utraty jednego pakietu (w tej chwili przeładowanie daje mi średnio 99,76% sukcesu przy 1000 żądaniach na sekundę przez 5 sekund). Przeprowadziłem wiele godzin badań na ten temat i znalazłem następujące polecenie „płynnego przeładowania” serwera HAProxy:
haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
Ma to jednak niewielki lub żaden efekt w porównaniu do zwykłego starego service haproxy reload
, wciąż spada średnio o 0,24%.
Czy jest jakiś sposób na ponowne załadowanie pliku konfiguracyjnego HAProxy bez jednego upuszczonego pakietu od dowolnego użytkownika?
Odpowiedzi:
Zgodnie z https://github.com/aws/opsworks-cookbooks/pull/40, a zatem http://www.mail-archive.com/[email protected]/msg06885.html możesz:
źródło
iptables v1.4.14: invalid port/service
syn „określono”$PORT
faktycznym portem,haproxy
na którym nasłuchuje. Jeśli haproxy nasłuchuje na wielu portach, zapisu zastąpić--dport $PORT
z--dports $PORTS_SEPARATED_BY_COMMAS
np--dports 80,443
.Yelp podzieliło bardziej wyrafinowane podejście oparte na skrupulatnych testach. Artykuł na blogu to głębokie nurkowanie i warte czasu, aby w pełni go docenić.
Odświeżanie HAProxy True Zero Przestoju
tl; dr używa Linux tc (kontrola ruchu) i iptables do tymczasowego umieszczania w kolejce pakietów SYN podczas przeładowywania HAProxy i podłączania dwóch pid do tego samego portu (
SO_REUSEPORT
).Nie czuję się komfortowo ponownie publikując cały artykuł o ServerFault; Niemniej jednak oto kilka fragmentów, które wzbudzą Twoje zainteresowanie:
Gist: https://gist.github.com/jolynch/97e3505a1e92e35de2c0
Pozdrawiam Yelp za dzielenie się tak niesamowitymi spostrzeżeniami.
źródło
Istnieje jeszcze inny, znacznie prostszy sposób przeładowywania haproxy z prawdziwym zerowym przestojem - nazywa się to iptables flipping (artykuł jest w rzeczywistości odpowiedzią Unbounce na rozwiązanie Yelp). Jest to czystsze niż zaakceptowana odpowiedź, ponieważ nie trzeba upuszczać żadnych pakietów, które mogą powodować problemy z długimi przeładowaniami.
W skrócie, rozwiązanie składa się z następujących kroków:
iptable
poleceń .Co więcej, rozwiązanie można dostosować do dowolnej usługi (nginx, apache itp.) I jest bardziej odporne na awarie, ponieważ można przetestować konfigurację trybu gotowości przed przejściem do trybu online.
źródło
Edycja: Moja odpowiedź zakłada, że jądro wysyła ruch tylko do najnowszego portu, który ma zostać otwarty za pomocą SO_REUSEPORT, podczas gdy faktycznie wysyła ruch do wszystkich procesów, jak opisano w jednym z komentarzy. Innymi słowy, taniec iptables jest nadal wymagany. :(
Jeśli korzystasz z jądra obsługującego SO_REUSEPORT, ten problem nie powinien się zdarzyć.
Proces, który wykonuje haproxy po ponownym uruchomieniu, to:
1) Spróbuj ustawić SO_REUSEPORT podczas otwierania portu ( https://github.com/haproxy/haproxy/blob/3cd0ae963e958d5d5fb838e120f1b0e9361a92f8/src/proto_tcp.c#L792-L798 )
2) Spróbuj otworzyć port (zakończy się sukcesem w przypadku SO_REUSEPORT)
3) Jeśli to się nie powiedzie, zasygnalizuj, że stary proces zamknął port, odczekaj 10 ms i spróbuj ponownie. ( https://github.com/haproxy/haproxy/blob/3cd0ae963e958d5d5fb838e120f1b0e9361a92f8/src/haproxy.c#L1554-L1577 )
Po raz pierwszy był obsługiwany w jądrze Linuksa 3.9, ale niektóre dystrybucje go przeportowały. Na przykład jądra EL6 z wersji 2.6.32-417.el6 obsługują to.
źródło
SO_REUSEPORT
niektórych szczególnych scenariuszy - szczególnie przy dużym natężeniu ruchu. Kiedy SYN jest wysyłany do starego procesu haproxy iw tym samym momencie zamyka gniazdo nasłuchiwania, co powoduje RST. Zobacz artykuł Yelp wspomniany w innej odpowiedzi powyżej.Wyjaśnię moją konfigurację i jak rozwiązałem pełne wdzięku przeładowania:
Mam typową konfigurację z 2 węzłami z uruchomionym HAproxy i keepalived. Interfejs Keepalived śledzi interfejs dummy0, więc mogę zrobić „manekina ifconfig w dół”, aby wymusić przełączenie.
Prawdziwy problem polega na tym, że nie wiem, dlaczego „haproxy reload” nadal usuwa wszystkie ESTABLISHED połączenia :( Próbowałem „iptables flipping” zaproponowanego przez gertas, ale znalazłem pewne problemy, ponieważ wykonuje NAT w miejscu docelowym Adres IP, który nie jest odpowiednim rozwiązaniem w niektórych scenariuszach.
Zamiast tego zdecydowałem się użyć brudnego hacka CONNMARK do oznaczenia pakietów należących do NOWYCH połączeń, a następnie przekierować te oznaczone pakiety do innego węzła.
Oto zestaw reguł iptables:
Dwie pierwsze reguły oznaczają pakiety należące do nowych przepływów (123.123.123.123 jest utrzymywanym VIP-em używanym w haproxy do wiązania frontendów).
Trzecia i czwarta zasada oznacza pakiety pakiety FIN / RST. (Nie wiem dlaczego, cel TEE „ignoruje” pakiety FIN / RST).
Piąta reguła wysyła duplikat wszystkich oznaczonych pakietów do drugiego HAproxy (192.168.0.2).
Szósta reguła odrzuca pakiety należące do nowych przepływów, aby uniemożliwić dotarcie do pierwotnego celu.
Pamiętaj, aby wyłączyć rp_filter na interfejsach, w przeciwnym razie jądro usunie te marsjańskie pakiety.
I na koniec, pamiętaj o powracających pakietach! W moim przypadku istnieje routing asymetryczny (żądania przychodzą do klienta -> haproxy1 -> haproxy2 -> serwer WWW, a odpowiedzi wychodzą z serwera www -> haproxy1 -> klient), ale to nie ma wpływu. To działa dobrze.
Wiem, że najbardziej eleganckim rozwiązaniem byłoby użycie iproute2 do przekierowania, ale działało to tylko dla pierwszego pakietu SYN. Kiedy otrzymał ACK (trzeci pakiet 3-kierunkowego uścisku dłoni), nie oznaczył go :( Nie mogłem poświęcić dużo czasu na badanie, jak tylko zobaczyłem, że działa z celem TEE, zostawiłem go tam. Oczywiście możesz spróbować z iproute2.
Zasadniczo „płynne przeładowanie” działa w następujący sposób:
Zestaw reguł IPtables można łatwo zintegrować ze skryptem start / stop:
źródło