Niezawodność środowiska wykonawczego Rust/Wasm wymaga obsługi zarówno paniki, jak i przerwania odzyskiwania
Gdy współdzielona instancja Wasm zacznie akceptować wywołania przez długi czas, awaria będzie się nasilać od pojedynczej awarii do problemu z przywróceniem stanu i izolowaniem usterek.
Na początku Wasm można z łatwością uznać za warstwę przenoszącą: kod można zaprogramować, strona może działać, wydajność jest w porządku i wszystko wydaje się być mniej więcej takie same. To naprawdę zaczyna być trudne, zwykle po przejściu wersji demonstracyjnej. Gdy moduły, takie jak edytory, moduły renderujące i analizatory dokumentów, przejdą z eksperymentów jednostronicowych do długoterminowych środowisk wykonawczych, modele błędów natychmiast się zmienią.
W tej chwili panika i przerwanie nie są już gałęziami wyjątków w warstwie językowej. Decydują: czy ta instancja może nadal otrzymywać dalsze prace, czy stan w pamięci jest zanieczyszczony, czy warstwa hosta powinna natychmiast odrzucić instancję i czy należy zapełnić pulę instancji. Kiedy zespół mobilny przenosi do sieci jądro, które przez długi czas działało w natywnych kontenerach, to właśnie tę warstwę zmian najłatwiej niedoceniać.
Po przejściu wersji demonstracyjnej model usterki właśnie się rozpoczął.
Awarie podczas jednego połączenia nie są trudne do zrozumienia. Kliknięcie przycisku uruchamia połączenie Wasm. Jeśli się nie powiedzie, zostanie zgłoszony błąd operacji. Odśwież stronę i spróbuj ponownie. Koszt jest nadal kontrolowany.
Problem występuje, gdy środowisko wykonawcze zaczyna ponownie wykorzystywać instancje. Kiedy ta sama instancja Wasm w sposób ciągły otwiera wiele dokumentów, otrzymuje wiele rund zdarzeń wejściowych i przechodzi przez wiele wywołań mostu JS, zakres wpływu paniki i przerwania nie kończy się już na bieżącej akcji. Niekompletna awaria może przeciągnąć w dół kolejne żądania.
Takie zagrożenia często nie są ujawniane już pierwszego dnia. Na pierwszym etapie zwykle widzisz tylko rozproszone raporty o błędach: sporadyczne błędy renderowania, pewien eksport zostaje zablokowany, a określony dokument jest w nieprawidłowym stanie po zamknięciu i ponownym otwarciu. Jeśli sprawdzisz dalej, wskazówki będą stopniowo zbliżać się do tego samego zjawiska: chociaż awaria wystąpiła w łańcuchu połączeń, uszkodzenie pozostało we współdzielonej instancji.
W tym momencie dyskusja nie skupia się już na tym, „czy kod Rusta wpadnie w panikę”, ale na tym, czy to środowisko wykonawcze jest odpowiednie do kontynuowania obsługi następnego wywołania po panice.
Panikę można złapać, przerwanie może jedynie zmienić instancje.
Najważniejszą rzeczą do oddzielenia w Rust/Wasm są dwie semantyki niepowodzenia: panika i przerwanie.
Panika daje również możliwość odprężenia się wzdłuż ustalonych granic. Jeśli warstwa powiązania i warstwa hosta z góry uzgodnią metodę odzyskiwania, bieżące wywołanie może zakończyć się niepowodzeniem, a inne stany instancji również mogą zostać utrzymane. aborcja w ogóle nie jest dobrym rozwiązaniem. Oznacza to, że bieżące wykonanie osiągnęło stan niemożliwy do odzyskania. Jeśli będziesz nadal korzystać z tej samej instancji do odbierania żądań, zasadniczo obstawiasz, że pamięć i zasoby nie ulegną uszkodzeniu w połowie.
Gdy te dwa elementy zostaną zmieszane w czasie wykonywania, z pewnością pojawią się problemy w dalszym przetwarzaniu:
- Przerwij operację w ramach normalnego wyjątku, a pula instancji będzie nadal ponownie wykorzystywać obiekty, które utraciły wiarygodność.
- Traktuj wszystkie paniki tak, jakby instancja musiała zostać zniszczona, a przepustowość zostanie niepotrzebnie zmniejszona
- Host JS wie tylko, że połączenie nie powiodło się, ale nie wie, czy ponowić próbę, utracić instancję, czy przerwać bieżącą sesję
Jest to również najbardziej realistyczna rzecz dotycząca niezawodności środowiska wykonawczego Wasm: najpierw należy zdefiniować semantykę odzyskiwania, zanim będzie można wdrożyć późniejszą izolację i planowanie.
Jeśli warstwa powiązania nie zapewnia semantyki odzyskiwania, warstwa hosta przyjmie zły stan i będzie nadal akceptować pracę.
Najbardziej niebezpiecznym miejscem na tego typu problemy nie jest kod biznesowy, ale warstwa wiążąca, która wydaje się być już „zajęta”. Warstwa hosta często widzi tylko zgłoszony obiekt błędu i rejestruje go jako normalny błąd wywołania. Dziennik jest dostępny i strona nie ulega natychmiastowej awarii, ale system mógł pozostawić zły stan wewnątrz instancji.
To, co naprawdę wymaga naprawy, to nie tylko próba/złapanie, ale także obsługa działań po niepowodzeniu. Logika podobna do poniższej właśnie zaczęła wchodzić w projektowanie niezawodności:
async function runWithRecovery(instance, input) {
try {
return await instance.exports.handle(input)
} catch (error) {
if (isAbort(error)) {
pool.replace(instance.id)
}
throw error
}
}
Ten kod nie koncentruje się na składni, ale na prostej ocenie: czy bieżąca awaria oznaczyła tę instancję jako niezaufany obiekt. Jeśli odpowiedź brzmi „tak”, akcja odzyskiwania nie powinna kończyć się na rzuceniu błędów, ale powinna trwać aż do eliminacji instancji, odtworzenia zasobów i zażądania ograniczenia przepływu.
Dopóki ta warstwa nie jest jasno zdefiniowana, będzie się wydawać, że system obsługuje błędy, ale w rzeczywistości przywraca potencjalnie uszkodzone środowisko wykonawcze z powrotem do ścieżki produkcyjnej.
Instancje współdzielone zwiększą problem odzyskiwania i zamienią go w problem strategii łączenia
Po umieszczeniu Wasma w prawdziwych produktach rzadko zdarza się tylko „jedna instancja, zanim strona zostanie zamknięta”. Bardziej powszechne są pule instancji, pule procesów roboczych lub dokumenty na pierwszym planie i zadania w tle współdzielące zestaw zasobów wykonawczych. Na tym etapie koszty naprawy w postaci paniki i przerwania spowodują bezpośrednie przepisanie strategii łączenia zasobów.
Jeśli inicjalizacja instancji jest kosztowna, system będzie naturalnie miał tendencję do ponownego jej wykorzystania w miarę możliwości. Jednak po ustaleniu możliwości ponownego wykorzystania należy jednocześnie ulepszyć izolację usterek:
- Które stany można zawiesić tylko w przypadku pojedynczego połączenia i zostaną odrzucone wraz z połączeniem w przypadku niepowodzenia
- Które pamięci podręczne mogą być zachowywane podczas połączeń i które pamięci podręczne muszą zostać całkowicie unieważnione po napotkaniu przerwania
- W jaki sposób po wymianie instancji zostaną przeniesione zadania oczekujące w kolejce? Czy ponowna próba spowoduje dwukrotne skutki uboczne?
To nie są odpowiedzi, które warstwa językowa wyśle automatycznie. Są to projekty wykonawcze.
Z tego powodu, jeśli dyskusja na temat niezawodności Rust/Wasm zatrzyma się jedynie na pytaniu: „Czy można wychwycić panikę?”, łatwo jest nie docenić problemu. Tym, co naprawdę zwiększa różnicę w kosztach utrzymania, jest to, czy pula instancji może utrzymać wyraźną granicę zaufania po awarii.
Obowiązująca granica jest silnie powiązana z cyklem życia
Ten zestaw projektów renowacji nie jest wymagany w przypadku każdego projektu Wasm.
Jeśli moduł jest tylko jednorazowym narzędziem offline lub cała instancja zostanie odtworzona po zniszczeniu strony, wówczas różnica między paniką a przerwaniem będzie nadal istnieć, ale korzyści z odzyskiwania będą znacznie mniejsze. Często wystarczy bezpośrednio odświeżyć stronę i od razu ponownie uruchomić zadanie.
Gdy system będzie miał następujące cechy, semantyka odzyskiwania szybko zmieni się z „elementu optymalizacji” na „element infrastruktury”:
- Instancja znajduje się przez długi czas i nie ulega zniszczeniu wraz z cyklem życia pojedynczej strony
- Ta sama instancja stale wykonuje wiele rund wywołań
- Warstwa hostingowa musi korzystać z puli w zamian za czas uruchamiania i przepustowość
- Chroń stan sesji, stan pamięci podręcznej i zadania w kolejce po awarii
Kiedy zespoły mobilne przenoszą natywne możliwości do Internetu, granica ta jest najbardziej prawdopodobna. Relacja izolacji, która pierwotnie została domyślnie ustanowiona w procesie aplikacji, często musiała zostać wypełniona ponownie po osiągnięciu granicy hosta JS/Wasm.
Wasm ułatwia natywnemu kodowi wejście do przeglądarki, ale nie zapewnia semantyki odzyskiwania w czasie wykonywania. Gdy tylko system zacznie udostępniać instancje, ponownie wykorzystywać stan i akceptować wywołania długoterminowe, panikę i przerwanie należy traktować jako dwa różne zdarzenia w czasie wykonywania. Ten pierwszy dba o to, jak zakończyć bieżące połączenie, a drugi o to, czy ta instancja może nadal żyć w puli. Jeśli najpierw nie zostanie podjęta taka ocena, im skuteczniejsze będzie przeszczepienie kodu, tym trudniej będzie uporać się z kolejnymi niepowodzeniami.
What to read next
Want more posts about iOS?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home