W skrócie, czy powinniśmy projektować śmierć w naszych programach, procesach i wątkach na niskim poziomie, dla dobra całego systemu?
Awarie się zdarzają. Procesy giną. Planujemy katastrofę i od czasu do czasu się z niej odzyskujemy. Ale rzadko projektujemy i wdrażamy nieprzewidywalną śmierć programu. Mamy nadzieję, że przestoje naszych usług będą trwać tak długo, jak długo staramy się je utrzymać.
Makroprzykładem tej koncepcji jest Małpa Chaosu Netflix , która losowo kończy wystąpienia AWS w niektórych scenariuszach. Twierdzą, że pomogło im to odkryć problemy i zbudować więcej zbędnych systemów.
Mówię o niższym poziomie. Chodzi o to, aby tradycyjnie długotrwałe procesy były losowo zamykane. Powinno to wymusić redundancję w projekcie i ostatecznie wytworzyć bardziej odporne systemy.
Czy ta koncepcja ma już nazwę? Czy jest już używany w branży?
EDYTOWAĆ
W oparciu o komentarze i odpowiedzi obawiam się, że moje pytanie nie było jasne. Dla jasności:
- tak, mam na myśli losowo,
- tak, mam na myśli w produkcji, i
- nie, nie tylko do testowania.
Aby wyjaśnić, chciałbym narysować analogię do organizmów wielokomórkowych.
W naturze organizmy składają się z wielu komórek. Komórki rozwidlają się, tworząc nadmiarowość i ostatecznie umierają. Ale zawsze powinno być wystarczającej liczby odpowiednich komórek, aby organizm mógł funkcjonować. Ten wysoce zbędny system ułatwia także gojenie się po zranieniu. Komórki umierają, więc organizm żyje.
Włączenie przypadkowej śmierci do programu zmusiłoby większy system do przyjęcia strategii redundancji, aby pozostały opłacalne. Czy te same strategie pomogłyby systemowi zachować stabilność w obliczu innych nieprzewidzianych awarii?
A jeśli ktoś tego próbował, jak to się nazywa? Chciałbym przeczytać więcej na ten temat, jeśli już istnieje.
Odpowiedzi:
Nie.
Powinniśmy zaprojektować odpowiednią obsługę złej ścieżki i zaprojektować przypadki testowe (i inne ulepszenia procesu), aby sprawdzić, czy programy dobrze radzą sobie z tymi wyjątkowymi warunkami. Rzeczy takie jak Małpa Chaosu mogą być tego częścią, ale gdy tylko ustawisz „musi losowo upaść” wymóg, rzeczywiste losowe awarie stają się tym, czego testerzy nie mogą zgłosić jako błędów.
źródło
Proces wprowadzania defektów w oprogramowaniu lub w sprzęcie w celu przetestowania odporności na uszkodzenia mechanizmów nazywa iniekcja błędów .
Z Wikipedii:
źródło
Tak. Nie, może.
Okresowe zakończenie jest mieczem obosiecznym. Zostaniesz trafiony jedną lub drugą krawędzią, a to, co jest mniejszym z dwóch zła, zależy od twojej sytuacji.
Jedną z zalet jest niezawodność: jeśli zmusisz program do losowego (lub przewidywalnego) zakończenia w uporządkowany sposób, możesz być przygotowany na to wydarzenie i sobie z nim poradzić. Możesz zagwarantować, że proces zakończy się, gdy nie będzie zajęty robieniem czegoś pożytecznego. Gwarantuje to również, że błędy, które ujawnią się po przekroczeniu sankcjonowanego czasu działania, nie odwrócą swoich brzydkich głów podczas produkcji, co jest dobrą rzeczą. Apache HTTPD ma ustawienie, które pozwala dostroić liczbę żądań, które proces potomny (lub wątek w nowszych wersjach) będzie obsługiwał przed zakończeniem.
Drugą zaletą jest także niezawodność: jeśli nie pozwolisz programowi długo działać, nigdy nie znajdziesz błędów, które pojawią się z czasem. Kiedy w końcu napotkasz jeden z tych błędów, znacznie bardziej prawdopodobne jest, że program zwróci złą odpowiedź lub w ogóle jej nie zwróci. Co gorsza, jeśli uruchomisz wiele wątków tego samego zadania, błąd spowodowany czasem lub liczeniem może wpłynąć na bardzo dużą liczbę zadań naraz i spowodować całą podróż do biura o trzeciej nad ranem.
W środowisku, w którym uruchamia się wiele takich samych wątków (np. Na serwerze WWW), praktycznym rozwiązaniem jest zastosowanie podejścia mieszanego, które skutkuje akceptowalnym wskaźnikiem awaryjności. Jeśli uruchomisz 100 wątków, uruchomienie stosunku krótko- i długiego 99: 1 oznacza, że tylko jeden będzie wykazywał błędy długoterminowe, podczas gdy inne będą nadal robić to, co robią, bez porażki. Porównaj to z uruchomieniem 100% długości, gdzie istnieje znacznie większe ryzyko, że wszystkie wątki zawiodą jednocześnie.
Jeśli masz jeden wątek, prawdopodobnie lepiej po prostu pozwolić mu działać i zawieść, ponieważ czas martwy podczas restartu może powodować niepożądane opóźnienia, gdy prawdziwa praca zostanie wykonana pomyślnie.
W obu przypadkach ważne jest, aby było coś nadzorującego procesy, aby można je było natychmiast ponownie uruchomić. Ponadto, nie ma prawa, które mówi, że twoje początkowe decyzje dotyczące tego, jak długo proces powinien trwać, muszą zostać wrzucone w kamień. Zbieranie danych operacyjnych pomoże dostroić system, aby ograniczyć awarie do akceptowalnego poziomu.
Odradzałbym przypadkowe zakończenie, ponieważ utrudnia to ustalanie błędów związanych z czasem. Chaos Monkey robi to, aby upewnić się, że oprogramowanie nadzorujące działa, co jest nieco innym problemem.
źródło
Czy naprawdę masz na myśli przypadek? Losowe zabijanie oprogramowania wydaje się okropnym pomysłem. Jakiemu punktowi to służy?
Zgaduję, że tak naprawdę masz na myśli to, że powinniśmy być realistyczni w kwestii długo działających wątków / procesów i zaakceptować, że im dłużej działają, tym bardziej prawdopodobne jest, że napotkali jakiś ukryty błąd i popadli w niefunkcjonalność stan. Tak więc, jako czysto pragmatyczny środek, żywotność procesów i wątków powinna być ograniczona.
Uważam, że pod koniec lat 90. serwer WWW Apache używał czegoś takiego. Mieli pulę procesów roboczych (nie wątków), a każdy proces roboczy został zabity po określonym czasie życia. Dzięki temu serwer nie został zmonopolizowany przez procesy robocze, które utknęły w stanie patologicznym.
Od jakiegoś czasu nie pracowałem w tej okolicy, więc nie wiem, czy nadal tak jest.
źródło
Problem, jaki widzę, polega na tym, że jeśli taki program umrze, powiemy tylko: „Och, to kolejne przypadkowe zakończenie - nie ma się o co martwić”. Ale co jeśli istnieje prawdziwy problem, który wymaga naprawy? Zostanie zignorowany.
Programy już „losowo” zawodzą ze względu na to, że programiści robią mistayki, błędy wprowadzają je do systemów produkcyjnych, awarie sprzętu itp. Gdy to nastąpi, chcemy o tym wiedzieć, abyśmy mogli to naprawić. Projektowanie śmierci w programach tylko zwiększa prawdopodobieństwo niepowodzenia i zmusi nas do zwiększenia nadmiarowości, co kosztuje.
Nie widzę nic złego w przypadkowym zabijaniu procesów w środowisku testowym podczas testowania nadmiarowego systemu (powinno się to zdarzać częściej niż w rzeczywistości), ale nie w środowisku produkcyjnym. Czy wyjmowalibyśmy kilka dysków twardych z systemu produkcji na żywo co kilka dni, czy dezaktywowaliśmy jeden z komputerów w samolocie, który leci pełen pasażerów? W scenariuszu testowym - w porządku. W scenariuszu na żywo - wolałbym nie.
źródło
Dodanie losowego kodu wyjścia do aplikacji nie powinno być konieczne. Testerzy mogą pisać skrypty, które losowo zabijają procesy aplikacji.
W sieci konieczne jest symulowanie zawodnej sieci w celu przetestowania implementacji protokołu. Nie jest to wbudowane w protokół; może być symulowany na poziomie sterownika urządzenia lub za pomocą zewnętrznego sprzętu.
Nie dodawaj kodu testowego do robienia programu dla sytuacji, które można osiągnąć zewnętrznie.
Jeśli to jest przeznaczone do produkcji, nie mogę uwierzyć, że to poważne!
Po pierwsze, chyba że procesy zakończą się nagle, co spowoduje utratę transakcji w toku i niestabilnych danych, nie jest to uczciwa implementacja tej koncepcji. Planowane, pełne wdzięku wyjścia, nawet jeśli są losowe, nie pomagają odpowiednio przygotować architektury do radzenia sobie z prawdziwymi awariami, które nie są taktowne.
Jeśli w aplikację wbudowane są rzeczywiste lub realistyczne usterki, mogą one spowodować szkody ekonomiczne, podobnie jak rzeczywiste usterki, a celowa szkoda ekonomiczna jest w zasadzie przestępstwem prawie z definicji.
Możesz być w stanie uniknąć klauzul zawartych w umowie licencyjnej, które zwalniają odpowiedzialność cywilną z wszelkich szkód wynikających z działania oprogramowania, ale jeśli szkody te są projektowane, możesz nie być w stanie zrzec się odpowiedzialności karnej.
Nawet nie myśl o takich wyczynach kaskaderskich: spraw, aby działał tak niezawodnie, jak to tylko możliwe, i umieszczaj fałszywe scenariusze awarii tylko w specjalnych kompilacjach lub konfiguracjach.
źródło
Możesz szukać „ proaktywnego odzyskiwania ” i „ odmładzania ” w kontekście odpornych na awarie systemów rozproszonych, aby radzić sobie z dowolnymi błędami (tj. Nie tylko zawieszonymi procesami, ale także uszkodzonymi danymi i potencjalnie złośliwym zachowaniem). Przeprowadzono wiele badań dotyczących tego, jak często i w jakich warunkach należy restartować proces (w sensie abstrakcyjnym, może to być maszyna wirtualna lub host). Intuicyjnie możesz zrozumieć zalety tego podejścia, ponieważ wolisz radzić sobie z martwym procesem niż z procesem zdrajcy ...
źródło
Tak naprawdę nie różni się to od testowania. Jeśli projektujesz zawsze dostępne rozwiązanie przełączania awaryjnego (takie jak Netflix), to tak - powinieneś je przetestować. Nie wiem jednak, czy przypadkowe wyjścia rozsypane w bazie kodu są odpowiednim sposobem na przetestowanie tego. O ile naprawdę nie zamierzasz testować, czy Twój projekt jest odporny na strzelanie sobie w stopę, bardziej odpowiednie wydaje się przetestowanie go poprzez manipulowanie środowiskiem wokół kodu i sprawdzenie, czy zachowuje się odpowiednio.
Jeśli nie projektujesz nadmiarowych systemów, nie - nie powinieneś dodawać tej funkcji, ponieważ dodałeś kilka losowych wyjść. Powinieneś po prostu usunąć losowe wyjścia, a wtedy nie będziesz miał tego problemu. Twoje środowisko wciąż może zawieść na tobie, w którym to momencie albo zaczniesz pisać, że nie jest ono obsługiwane / nie naprawisz, albo nie zahartujesz kodu przed tym niepowodzeniem i dodasz test. Czy to wystarczająco często, i zdasz sobie sprawę, że rzeczywiście są projektowaniu redundantnego systemu - patrz scenariusza # 1.
W pewnym momencie możesz stwierdzić, że nie jesteś już pewien, jakie awarie są lub nie są obsługiwane. Teraz możesz zacząć losowo wyciągać dywan, aby wykryć punkty awarii.
Jedyną interesującą rzeczą w przykładzie Netflix jest to, że uruchamiają te testy w produkcji. To ma pewien sens - niektóre błędy są tak naprawdę produkcyjnymi rzeczami, które są bardzo trudne lub niemożliwe do symulacji w odizolowanym środowisku. Podejrzewam, że Netflix spędził dużo czasu w środowiskach testowych, zanim były wystarczająco wygodne, aby to zrobić w produkcji. I tak naprawdę wszystko, co robią, to próby spowodowania awarii w godzinach pracy, co ma pewien sens dla ich rynku, ale nie dla wielu innych.
źródło
Termin, którego szukasz, został niedawno ukuty przez Nassima Nicholasa Taleba: Antifragility. Jego książka Antifragile jest zdecydowanie zalecana. Ledwie wspomina o IT, ale niewypowiedziane, oczywiste podobieństwa są najbardziej inspirujące. Jego pomysłem jest rozszerzenie skali kruchej <-> odpornej na delikatną <-> solidną <-> antyfragile. Kruche przerwy z przypadkowymi zdarzeniami, solidne zarządzanie z przypadkowymi zdarzeniami i anty-kruche zyski z przypadkowymi zdarzeniami.
źródło
To zależy. Zauważyłem, że programiści zwykle nadmiernie generalizują techniki stosowane w ich konkretnych domenach, ignorując wszystkie inne. Na przykład wydanie programu kosztem naprawy wszystkich błędów może być dobre ... chyba że zaprogramujesz kontroler statku powietrznego, reaktor jądrowy itp. „Nie optymalizuj - koszt programatora jest większy niż koszt uruchomienia programu” nie jest konieczny ważne dla HPC, ponieważ stosunkowo prosty program może zajmować klaster przez wiele miesięcy itp. (lub nawet popularny program, z którego korzysta duża liczba użytkowników). Więc nawet jeśli firma X robi Y z bardzo dobrego powodu, nie musisz podążać ich śladami, ponieważ Twoja sytuacja może być inna.
Zwykle procedury obsługi błędów są najgorzej przetestowaną częścią kodu - choć wydaje się to proste, trudno jest zasymulować brak wystarczającej ilości pamięci lub brak jakiegoś ważnego pliku. Z tego powodu czytam teksty, które proponowały jądro uniksowe, aby przypadkowo zawiodły niektóre wywołania systemowe. Utrudnia to jednak pisanie prostych programów (jeśli muszę połączyć 3 biblioteki C ++, aby uruchomić program na 2 plikach, gdy nie chcę zawracać sobie głowy obsługą błędów). Nawet z wyjątkami, GC, musisz upewnić się, że pozostawiłeś spójny stan (wyobraź sobie wyjątek w środku dodawania węzła do listy połączonej).
Im więcej usług rozproszonych masz, tym więcej awarii oznacza pytanie „jak często” to „jeśli” lub „kiedy”. W centrach danych wymiana dysków w macierzach RAID stanowi część rutynowych operacji z tego, co wiem - nie jest to nieoczekiwana awaria. Jeśli działasz na dużą skalę, musisz wziąć to pod uwagę, ponieważ nawet jeśli prawdopodobieństwo awarii jednego elementu jest niewielkie, istnieje prawdopodobieństwo, że coś zawiedzie.
Nie wiem, co dokładnie robisz, ale aby wiedzieć, czy warto, musisz pomyśleć, czy porażka jest czymś, co musisz wziąć pod uwagę (ponieważ ignorowanie kosztuje) lub jest zbyt kosztowne, aby analizować (jako uwzględnianie błędów pod uwagę czas opracowania kosztów).
źródło
Serwer IIS ma konfigurowalną funkcję, która automatycznie odzyskuje procesy robocze albo po zużyciu określonej ilości pamięci, albo po obsłużeniu określonej liczby żądań lub po upływie określonego czasu. ( http://msdn.microsoft.com/en-us/library/ms525803(v=vs.90).aspx ) i ( http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/ 1652e79e-21f9-4e89-bc4b-c13f894a0cfe.mspx? Mfr = true )
Gdy robi to KONTENER, taki jak IIS, sensowne jest, aby chronić serwer przed nieuczciwymi procesami. Wolałbym jednak wyłączyć tę opcję, ponieważ nie ma sensu, jeśli wystarczająco przetestowałeś swój kod.
Pracujemy już na niewiarygodnych warstwach (sprzęt, sieć), więc nigdy nie napisałbym żadnego kodu, który celowo zabiłby jego wątki lub procesy. Losowe zabijanie jest również złym pomysłem z ekonomicznego punktu widzenia - nikt nie użyłby mojego API, gdyby zorientowali się, że zaprogramowałem go tak, aby losowo się zawiesił. Wreszcie, gdybym miał skonsumować API lub użyć systemu z przypadkowo zawieszającymi się wątkami, musiałbym wydać dużo pieniędzy, aby stworzyć wystarczająco solidny mechanizm monitorowania, aby móc spokojnie spać w nocy.
Zamiast tego Gdybym rozwijał system lub interfejs API, pisałbym skrypty lub korzystałbym z uprzęży, która robiłaby to wyłącznie w celu przetestowania wytrzymałości systemu. I przeprowadziłbym taki test na wszystkich kompilacjach, aby zidentyfikować złe kompilacje. Chociaż byłby to jednak test konieczny, nigdy nie mógłby być testem „wystarczającym”.
źródło
Istnieje literatura związana z tym pomysłem, zwana oprogramowaniem Crash-Only (również Recovery Oriented Computing) i możesz zacząć od tego papieru usenix Candea & Fox z 2003 roku. Zamiast losowych zabójstw autor twierdzi, że można poprawić niezawodność systemu tylko zawsze zatrzymując swoje programy, zabijając je, więc posiadanie jednego przełącznika „zabicia” jako przycisku wyłączania i pojedynczej dobrze wytrenowanej ścieżki startowej do odzyskiwania.
Chociaż nie jestem pewien, jak dobrze wpadł na ten pomysł, niektóre z konkretnych technik pozostają użyteczne. Na przykład brak zaufania do oprogramowania, które może zamknąć się na żądanie, a więc przy użyciu wyspecjalizowanych programów nadzorczych (np. Superwizja itp.), A także dokładne przemyślenie, jaki stan programu jest niezbędny, i upewnienie się, że zostało zarejestrowane w odpowiednim czasie w zaprojektowanym magazynie danych aby umożliwić odzyskiwanie (np. baza danych SQL).
źródło
Naprawdę losowo, nie. Ale prawdopodobnie dobrym pomysłem jest, aby długo działające procesy / wątki wychodziły / restartowały w danym przedziale czasu lub po tym, jak pozostawały bezczynne przez określony (ale zależny od określonych kryteriów) czas trwania lub po wykonaniu określonego rodzaju zadania. Długotrwałe procesy gromadzą się w sposób nieunikniony, włączając w to przestarzałe rzeczy, mogą prawdopodobnie zawiesić się w pamięci, zapobiegając zwolnieniu przestrzeni wymiany, z których wszystkie zostaną (lub powinny zostać) wyczyszczone po wyjściu, poprawiając ogólną stabilność systemu.
źródło
To zależy od rodzaju projektowanej aplikacji.
Przypadkowe awarie to świetny sposób na przetestowanie i poprawę niezawodności systemów rozproszonych (sieciowych).
W przykładzie Netflix, gdy twój program jest zależny od usług zdalnych, które mogą zawieść z różnych przyczyn, które są poza twoją kontrolą (dysk twardy ulega awarii, utrata zasilania, awaria meteoru w centrum danych itp.). Twoja usługa musi jednak nadal działać.
Jak to robisz? Dodaj nadmiarowość, a skalowanie jest powszechnym rozwiązaniem.
Na przykład, jeśli mysz gryzie kabel zasilający serwera, usługa powinna mieć jakieś rozwiązanie, aby móc dalej działać. Może na przykład zachować nadmiarowe serwery kopii zapasowych, których zacznie używać zamiast tego.
Jeśli jednak twój program jest aplikacją jednoprocesową, która nie działa w sieci, zabicie go nie spowoduje przetestowania niczego, ponieważ nie ma sposobu na odzyskanie go.
Oto dodatkowy komentarz dotyczący koncepcji Chaos Monkeys http://www.codinghorror.com/blog/2011/04/working-with-the-chaos-monkey.html
źródło
Możliwe jest, że przypadkowe odwrócenie bitów nastąpi z powodu promieniowania kosmicznego . Problem ten został rozpoznany i opracowano różne techniki , aby zapobiec występowaniu odwracania bitów.
Jednak nie można go naprawić w 100%, a uszkodzenie pamięci może nadal powodować problemy, a problemy te nadal występują ( z bardzo małym prawdopodobieństwem ).
Teraz, aby odpowiedzieć na twoje pytanie. To, czy potrzebujesz zaprojektować bardzo solidny system, zależy od tego, co robisz. Jeśli chcesz stworzyć statek kosmiczny, lepiej uczyń go super wytrzymałym, a wtedy będziesz musiał wziąć pod uwagę każdy możliwy problem.
Jeśli potrzebujesz zaprojektować normalną aplikację komputerową, powinieneś spojrzeć na przypadkowe awarie jako błędy w kodzie.
źródło
To nie wydaje się takie niedorzeczne.
System operacyjny Android losowo zabija i ponownie uruchamia aplikacje / usługi użytkownika przez cały czas. Z mojego doświadczenia zdecydowanie pomogło mi to głębiej zastanowić się nad warunkami błędu, a także zaprojektować solidniejsze architektury.
źródło
onDestroy
,onPause
,onSaveInstanceState
, itd ... nigdy nie można nazwać na działalności lub usługi. Na poziomie aplikacji nie ma nawetonDestory
oddzwaniania. Więc tak, są pewne haki do wdzięcznych wyłączeń, ale wciąż musisz być przygotowany na losowe wyjścia.onPause()
zanim aktywność zostanie zabita. Po Honeycomb masz gwarancję, że plusonStop()
. Aplikacje na Androida to tylko kolekcje działań, które są ze sobą powiązane i nie ma koncepcji na poziomie aplikacji w zakresie cyklu życia.