Strategie obsługi częściowych niepowodzeń

Napiwek

Ta zawartość jest fragmentem książki eBook, architektury mikrousług platformy .NET dla konteneryzowanych aplikacji platformy .NET dostępnych na platformie .NET Docs lub jako bezpłatnego pliku PDF, który można odczytać w trybie offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Aby poradzić sobie z częściowymi awariami, użyj jednej ze strategii opisanych tutaj.

Użyj komunikacji asynchronicznej (na przykład komunikacji opartej na komunikatach) w ramach wewnętrznych mikrousług. Zdecydowanie nie zaleca się tworzenia długich łańcuchów synchronicznych wywołań HTTP wewnętrznych mikrousług, ponieważ niepoprawny projekt ostatecznie stanie się główną przyczyną nieprawidłowych awarii. Wręcz przeciwnie, z wyjątkiem komunikacji frontonu między aplikacjami klienckimi a pierwszym poziomem mikrousług lub precyzyjnych bram interfejsów API, zaleca się używanie tylko asynchronicznej (opartej na komunikatach) komunikacji po przejściu do początkowego cyklu żądania/odpowiedzi w ramach wewnętrznych mikrousług. Spójność ostateczna i architektury sterowane zdarzeniami pomogą zminimalizować efekty falowania. Te podejścia wymuszają wyższy poziom autonomii mikrousług i w związku z tym zapobiegają wystąpieniu problemu w tym miejscu.

Użyj ponownych prób z wycofywaniem wykładniczym. Ta technika pomaga uniknąć krótkich i sporadycznie niepowodzeń, wykonując ponowną próbę wywołania określoną liczbę razy, w przypadku gdy usługa nie była dostępna tylko przez krótki czas. Może się to zdarzyć z powodu sporadycznych problemów z siecią lub przeniesienia mikrousługi/kontenera do innego węzła w klastrze. Jeśli jednak te próby nie są prawidłowo zaprojektowane z wyłącznikami, może to pogorszyć efekty falowania, ostatecznie nawet powodując odmowę usługi (DoS).

Obejście limitów czasu sieci. Ogólnie rzecz biorąc, klienci powinni nie blokować przez czas nieokreślony i zawsze używać limitów czasu podczas oczekiwania na odpowiedź. Użycie limitów czasu gwarantuje, że zasoby nigdy nie są powiązane przez czas nieokreślony.

Użyj wzorca wyłącznika. W tym podejściu proces klienta śledzi liczbę żądań zakończonych niepowodzeniem. Jeśli szybkość błędów przekracza skonfigurowany limit, "wyłącznik" przechodzi tak, aby dalsze próby zakończyły się niepowodzeniem natychmiast. (Jeśli duża liczba żądań kończy się niepowodzeniem, sugeruje to, że usługa jest niedostępna i że wysyłanie żądań jest bezcelowe). Po upływie limitu czasu klient powinien ponowić próbę i, jeśli nowe żądania zakończą się pomyślnie, zamknij wyłącznik.

Podaj rezerwowe. W tym podejściu proces klienta wykonuje logikę rezerwową, gdy żądanie kończy się niepowodzeniem, na przykład zwraca buforowane dane lub wartość domyślną. Jest to podejście odpowiednie dla zapytań i jest bardziej złożone w przypadku aktualizacji lub poleceń.

Ogranicz liczbę żądań w kolejce. Klienci powinni również nałożyć górną granicę liczby zaległych żądań, które mikrousługi klienta mogą wysyłać do określonej usługi. Jeśli limit został osiągnięty, prawdopodobnie nie ma sensu wykonywać dodatkowych żądań, a próby te powinny zakończyć się niepowodzeniem natychmiast. Jeśli chodzi o implementację, można użyć zasad izolacji bulkhead polly, aby spełnić to wymaganie. Takie podejście jest zasadniczo ograniczeniem SemaphoreSlim równoległym ze sposobem implementacji. Zezwala również na "kolejkę" poza grodziem. Możesz aktywnie rzucić nadmiar obciążenia jeszcze przed wykonaniem (na przykład ze względu na to, że pojemność jest uważana za pełną). Sprawia to, że jego reakcja na niektóre scenariusze awarii jest szybsza niż wyłącznik, ponieważ wyłącznik czeka na awarie. Obiekt BulkheadPolicy w polly ujawnia, jak pełne są grodzi i kolejki, i oferuje zdarzenia na przepełnieniu, dzięki czemu można również użyć do automatycznego skalowania w poziomie.

Dodatkowe zasoby