Spis treściKliknij link, aby przejść do wybranego miejsca
Ta treść została automatycznie przetłumaczona z ukraińskiego.
Problem gromadzenia się procesów - to sytuacja w rozwoju oprogramowania, gdy wiele procesów lub zapytań jednocześnie zwraca się do tego samego zasobu. Każdy z nich działa logicznie i poprawnie, ale razem tworzą nagły wzrost obciążenia, którego system nie wytrzymuje.
Nazwa jest metaforyczna: wyobraź sobie stado zwierząt, które jednocześnie rusza z miejsca. Osobno każde zwierzę nie stanowi problemu, ale razem mogą zniszczyć wszystko na swojej drodze.
Przykład problemu gromadzenia się procesów
W praktyce często wygląda to tak: masz pamięć podręczną z TTL. Klucz wygasa, a w tym samym momencie przychodzi wiele zapytań. Każde z nich widzi, że pamięć podręczna jest pusta, i postanawia samodzielnie udać się do bazy danych lub zewnętrznej usługi. W rezultacie zamiast jednego kontrolowanego zapytania otrzymujesz setki lub tysiące. Baza jest przeciążona, opóźnienia rosną, pojawiają się timeouty, a czasami nawet całkowite awarie usługi. Pamięć podręczna, która miała chronić system, w rzeczywistości staje się przyczyną awarii.
Problem ten jest szczególnie podstępny, ponieważ występuje nie w spokojnych warunkach, ale w najgorszych momentach: podczas szczytowego ruchu, po restarcie usług, przy wdrożeniach lub gdy zewnętrzna zależność zaczyna odpowiadać wolniej. Lokalne lub na etapie testów prawie niemożliwe jest jego odtworzenie, dlatego w produkcji wygląda jak "losowy" incydent bez oczywistej przyczyny.
Jak walczyć z problemem gromadzenia się procesów?
Walka z problemem gromadzenia się procesów może odbywać się na różne sposoby, ale idea zawsze jest ta sama: system nie powinien zachowywać się zbyt synchronicznie. Często wystarczy pozwolić tylko jednemu procesowi na aktualizację pamięci podręcznej, podczas gdy wszystkie inne czekają lub odczytują poprzednią wartość. W innych przypadkach lepiej tymczasowo oddać nieco przestarzałe dane, niż stworzyć lawinę zapytań do bazy. Nawet drobny szczegół, taki jak losowe przesunięcie TTL, może znacznie zmniejszyć ryzyko, że wszystkie klucze wygasną jednocześnie.
Osobną kategorią problemów są retrie. Gdy usługa pada lub odpowiada wolno, naiwna logika retry zmusza klientów do ponownego wysyłania zapytań synchronicznie. Zamiast przywrócenia system otrzymuje jeszcze większy cios. Dlatego opóźnienia, exponential backoff i losowy jitter to nie optymalizacja, a konieczność.
Problem gromadzenia się procesów to nie błąd w kodzie, a konsekwencja rozwiązań architektonicznych. Pojawia się tam, gdzie system skalowalny jest ilościowo, ale nie uwzględnia konkurencji o wspólne zasoby. Jeśli myśleć nie tylko o "jak działa", ale także o "jak się zachowuje pod obciążeniem", można uniknąć tego problemu już na etapie projektowania.
Ten post nie ma jeszcze żadnych dodatków od autora.