Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

W 2016 roku byliśmy w Buffer przerzuciłem się na Kubernetesa, a obecnie około 60 węzłów (w AWS) i 1500 kontenerów pracuje w naszym klastrze k8s zarządzanym przez kops. Jednak metodą prób i błędów przeszliśmy do mikroserwisów i nawet po kilku latach pracy z k8s wciąż borykamy się z nowymi problemami. W tym poście będziemy rozmawiać ograniczenia procesora: dlaczego uznaliśmy je za dobrą praktykę i dlaczego okazały się niezbyt dobre.

Ograniczenia procesora i dławienie

Podobnie jak wielu innych użytkowników Kubernetes, Google zdecydowanie zaleca ustawienie limitów procesora. Bez takiego ustawienia kontenery w węźle mogą zająć całą moc procesora, co z kolei powoduje, że ważne procesy Kubernetesa (np. kubelet) przestanie odpowiadać na żądania. Dlatego ustawienie limitów procesora jest dobrym sposobem na ochronę węzłów.

Limity procesora ustawiają kontener na maksymalny czas procesora, jaki może wykorzystać przez określony czas (domyślnie jest to 100 ms), a kontener nigdy nie przekroczy tego limitu. W Kubernetesie dla dławienie pojemnika i zapobiec jego przekroczeniu, stosuje się specjalne narzędzie Limit CFS, ale te sztuczne limity procesora ostatecznie szkodzą wydajności i wydłużają czas reakcji kontenerów.

Co może się stać jeśli nie ustalimy limitów procesora?

Niestety sami musieliśmy zmierzyć się z tym problemem. Każdy węzeł posiada proces odpowiedzialny za zarządzanie kontenerami kubeleti przestał odpowiadać na prośby. Węzeł, gdy to nastąpi, przejdzie w stan NotReady, a kontenery z niego zostaną przekierowane gdzie indziej i spowodują te same problemy w nowych węzłach. Delikatnie mówiąc, nie jest to idealny scenariusz.

Manifestacja problemu dławienia i reakcji

Kluczowym miernikiem śledzenia kontenerów jest trottling, pokazuje, ile razy Twój kontener został ograniczony. Z zainteresowaniem zauważyliśmy obecność throttlingu w niektórych kontenerach, niezależnie od tego, czy obciążenie procesora było ekstremalne, czy nie. Jako przykład przyjrzyjmy się jednemu z naszych głównych interfejsów API:

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

Jak widać poniżej, ustawiliśmy limit na 800m (0.8 lub 80% rdzenia) i wartości szczytowe przy najlepszym zasięgu 200m (20% rdzenia). Wydawać by się mogło, że przed dławieniem usługi mamy jeszcze sporo mocy procesora, jednak…

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora
Być może zauważyłeś, że nawet gdy obciążenie procesora jest poniżej określonych limitów – znacznie poniżej – nadal występuje dławienie.

W obliczu tego wkrótce odkryliśmy kilka zasobów (problem na githubie, prezentacja na zadano, napisz na omio) o spadku wydajności i czasu reakcji usług na skutek throttlingu.

Dlaczego widzimy dławienie przy niskim obciążeniu procesora? Krótka wersja brzmi: „w jądrze Linuksa występuje błąd, który powoduje niepotrzebne dławienie kontenerów przy określonych limitach procesora”. Jeśli interesuje Cię istota problemu, możesz zapoznać się z prezentacją (wideo и tekst opcje) autorstwa Dave’a Chiluka.

Usuwanie ograniczeń procesora (z zachowaniem szczególnej ostrożności)

Po długich dyskusjach zdecydowaliśmy się usunąć ograniczenia procesora ze wszystkich usług, które bezpośrednio lub pośrednio wpływały na krytyczną funkcjonalność naszych użytkowników.

Decyzja nie była łatwa, gdyż wysoko cenimy stabilność naszego klastra. W przeszłości eksperymentowaliśmy już z niestabilnością naszego klastra i wtedy usługi zużywały zbyt wiele zasobów i spowalniały pracę całego swojego węzła. Teraz wszystko było nieco inne: mieliśmy jasne zrozumienie, czego oczekujemy od naszych klastrów, a także dobrą strategię wdrażania zaplanowanych zmian.

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora
Korespondencja biznesowa w pilnej sprawie.

Jak chronić swoje węzły po zniesieniu ograniczeń?

Izolacja usług „nieograniczonych”:

W przeszłości widzieliśmy już, że niektóre węzły przechodziły w stan notReady, głównie z powodu usług, które pochłaniały zbyt wiele zasobów.

Zdecydowaliśmy się umieścić takie usługi w oddzielnych („oznaczonych”) węzłach, aby nie zakłócały usług „powiązanych”. W rezultacie, zaznaczając niektóre węzły i dodając parametr tolerancji do „niepowiązanych” usług, uzyskaliśmy większą kontrolę nad klastrem i łatwiej było nam identyfikować problemy z węzłami. Aby samodzielnie przeprowadzić podobne procesy, możesz się z nimi zapoznać dokumentacja.

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

Przypisanie prawidłowego żądania procesora i pamięci:

Najbardziej obawialiśmy się, że proces pochłonie zbyt wiele zasobów i węzeł przestanie odpowiadać na żądania. Ponieważ teraz (dzięki Datadogowi) mogliśmy wyraźnie monitorować wszystkie usługi w naszym klastrze, przeanalizowałem kilkumiesięczne działanie tych, które planowaliśmy określić jako „niepowiązane”. Po prostu ustawiam maksymalne wykorzystanie procesora z marginesem 20% i w ten sposób przydzielam miejsce w węźle na wypadek, gdyby k8s próbował przypisać do węzła inne usługi.

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

Jak widać na wykresie, osiągnięto maksymalne obciążenie procesora 242m Rdzenie procesora (0.242 rdzeni procesora). W przypadku żądania procesora wystarczy przyjąć liczbę nieco większą od tej wartości. Należy pamiętać, że ponieważ usługi są zorientowane na użytkownika, szczytowe wartości obciążenia pokrywają się z natężeniem ruchu.

Zrób to samo z wykorzystaniem pamięci i zapytaniami i voila – wszystko gotowe! Dla większego bezpieczeństwa możesz dodać automatyczne skalowanie podów w poziomie. Zatem za każdym razem, gdy obciążenie zasobów będzie duże, autoskalowanie utworzy nowe pody, a kubernetes rozprowadzi je do węzłów z wolną przestrzenią. W przypadku braku wolnego miejsca w samym klastrze możesz ustawić sobie alert lub skonfigurować dodawanie nowych węzłów poprzez ich autoskalowanie.

Z minusów warto zauważyć, że przegraliśmy w „gęstość pojemnika", tj. liczba kontenerów działających w jednym węźle. Przy małym natężeniu ruchu też możemy mieć sporo „odpoczynków”, jest też szansa, że ​​osiągniemy duże obciążenie procesora, ale w tym ostatnim powinny pomóc węzły autoskalowania.

wyniki

Z przyjemnością publikuję te doskonałe wyniki eksperymentów przeprowadzonych w ciągu ostatnich kilku tygodni; zaobserwowaliśmy już znaczną poprawę reakcji we wszystkich zmodyfikowanych usługach:

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

Najlepsze wyniki osiągnęliśmy na naszej stronie głównej (buffer.com), tam usługa przyspieszyła dwadzieścia dwa razy!

Kubernetes: Przyspiesz swoje usługi, usuwając limity procesora

Czy błąd jądra Linuksa został naprawiony?

Tak, Błąd został już naprawiony i poprawka została dodana do jądra dystrybucje w wersji 4.19 i wyższej.

Jednak po przeczytaniu Problemy z kubernetesem na githubie na drugi września 2020 r wciąż spotykamy wzmianki o niektórych projektach linuksowych z podobnym błędem. Uważam, że niektóre dystrybucje Linuksa nadal zawierają ten błąd i właśnie pracują nad jego naprawieniem.

Jeśli Twoja wersja dystrybucji jest niższa niż 4.19, zalecałbym aktualizację do najnowszej, ale w każdym przypadku powinieneś spróbować usunąć ograniczenia procesora i sprawdzić, czy dławienie nadal występuje. Poniżej możesz zobaczyć częściową listę usług zarządzania Kubernetes i dystrybucji Linuksa:

  • Debian: poprawka zintegrowana z najnowszą wersją dystrybucji, busteri wygląda całkiem świeżo (Sierpień 2020). Niektóre poprzednie wersje mogą również zostać naprawione.
  • Ubuntu: poprawka zintegrowana z najnowszą wersją Ubuntu Focal Fossa 20.04
  • EKS ma jeszcze rozwiązanie w grudniu 2019 r. Jeśli Twoja wersja jest niższa, powinieneś zaktualizować AMI.
  • kopie: Od czerwca 2020 r у kops 1.18+ Głównym obrazem hosta będzie Ubuntu 20.04. Jeśli Twoja wersja kops jest starsza, być może będziesz musiał poczekać na poprawkę. Sami czekamy teraz.
  • GKE (Google Cloud): Zintegrowana poprawka w styczniu 2020jednak są problemy z dławieniem są nadal obserwowane.

Co zrobić, jeśli poprawka rozwiązała problem z ograniczaniem przepustowości?

Nie jestem pewien, czy problem został całkowicie rozwiązany. Gdy dojdziemy do wersji jądra z poprawką, przetestuję klaster i zaktualizuję post. Jeśli ktoś już zaktualizował, chętnie przeczytam wyniki.

wniosek

  • Jeśli pracujesz z kontenerami Docker pod Linuksem (bez względu na Kubernetes, Mesos, Swarm i inne), Twoje kontenery mogą stracić wydajność z powodu dławienia;
  • Spróbuj zaktualizować swoją dystrybucję do najnowszej wersji, mając nadzieję, że błąd został już naprawiony;
  • Usunięcie limitów procesora rozwiąże problem, ale jest to niebezpieczna technika, której należy używać ze szczególną ostrożnością (lepiej najpierw zaktualizować jądro i porównać wyniki);
  • Jeśli usunąłeś limity procesora, uważnie monitoruj wykorzystanie procesora i pamięci i upewnij się, że zasoby procesora przekraczają zużycie;
  • Bezpieczną opcją byłoby automatyczne skalowanie podów w celu utworzenia nowych podów w przypadku dużego obciążenia sprzętu, tak aby Kubernetes przypisał je do wolnych węzłów.

Mam nadzieję, że ten post pomoże Ci poprawić wydajność systemów kontenerowych.

PS Tutaj autor koresponduje z czytelnikami i komentatorami (w języku angielskim).


Źródło: www.habr.com

Dodaj komentarz