Wzorzec grodziowy

Azure

Wzorzec grodzi jest typem projektu aplikacji, który jest odporny na awarie. W architekturze grodziowej, znanej również jako architektura oparta na komórkach, elementy aplikacji są izolowane do pul, dzięki czemu w przypadku awarii pozostałe będą nadal działać. Nosi nazwę od podzielonych partycji (grodzi) kadłuba statku. Jeśli dojdzie do naruszenia kadłuba statku, tylko uszkodzone sekcje wypełnią się wodą — dzięki temu statek nie zatonie.

Kontekst i problem

Aplikacja oparta na chmurze może obejmować wiele usług, a każda usługa może mieć jednego lub wielu użytkowników. Nadmierne obciążenie lub awaria w usłudze będzie mieć wpływ na wszystkich użytkowników usługi.

Ponadto użytkownik może wysyłać żądania jednocześnie do wielu usług, korzystając z zasobów dla każdego żądania. Gdy użytkownik wysyła żądanie do usługi, która jest błędnie skonfigurowana lub która nie odpowiada, zasoby używane przez żądanie klienta mogą nie zostać zwolnione w odpowiednim czasie. W miarę napływania żądań do usługi te zasoby mogą się wyczerpać. Przykładowo może dojść do wyczerpania puli połączeń klienta. W tym momencie na żądania konsumenta do innych usług mają wpływ. Po pewnym czasie użytkownik nie będzie już w stanie wysyłać żądań do innych usług, a nie tylko oryginalnej usługi, która nie odpowiada.

Ten sam problem związany z wyczerpaniem zasobów wpływa na usługi o wielu użytkownikach. Duża liczba żądań pochodzących od jednego klienta może wyczerpać dostępne zasoby w usłudze. Może dojść do sytuacji, w której inni klienci nie są w stanie korzystać z usługi, co powoduje efekt kaskadowej awarii.

Rozwiązanie

Partycjonowanie wystąpień usługi na różne grupy w oparciu o wymagania związane z obciążeniem użytkowników i dostępnością. Taka konstrukcja pomaga wyizolować awarie i umożliwia zapewnienie funkcjonowania usługi dla części użytkowników, nawet podczas awarii.

Użytkownik może również partycjonować zasoby, aby upewnić się, że zasoby używane do wywoływania jednej usługi nie mają wpływu na zasoby używane do wywoływania innej usługi. Przykładowo użytkownikowi, który wywołuje wiele usług, można przydzielić pulę połączeń dla każdej usługi. Jeśli usługa ulegnie awarii, wpłynie to tylko na pulę połączeń przypisaną dla tej usługi, a użytkownik nadal będzie mógł korzystać z innych usług.

Zalety tego wzorca obejmują:

  • Izolowanie użytkowników i usług zabezpiecza przed awariami kaskadowymi. Problem wpływający na użytkownika lub usługę można wyizolować w jego własnej „grodzi”, zapobiegając awarii całego rozwiązania.
  • Umożliwia zachowanie części funkcji nawet w przypadku awarii usługi. Inne usługi i funkcje aplikacji będą działać nadal.
  • Umożliwia wdrożenie usług, które oferują inną jakość usługi w przypadku używania aplikacji. Można skonfigurować pulę użytkowników o wysokim priorytecie, aby używać usług o wysokim priorytecie.

Na poniższym diagramie przedstawiono strukturę grodzi wokół pul połączeń wywołujących poszczególne usługi. Jeśli dojdzie do awarii usługi A lub spowoduje ona inny problem, pula połączeń zostanie wyizolowana, więc będzie to miało wpływ tylko na obciążenia używające puli wątków przypisanej do usługi A. Nie ma to wpływu na obciążenia używające usługi B i C, które mogą kontynuować pracę bez przeszkód.

Pierwszy diagram wzorca grodziowego

Następny diagram pokazuje wiele klientów wywołujących jedną usługę. Każdy klient ma przydzielone oddzielne wystąpienie usługi. Klient 1 wykonał zbyt wiele żądań i przeciążył swoje wystąpienie usługi. Ponieważ każde wystąpienie usługi jest wyizolowane od innych, inni klienci nadal mogą wykonywać wywołania.

Diagram przedstawiający wielu klientów wywołujących jedną usługę.

Problemy i kwestie do rozważenia

  • Zdefiniuj partycje w oparciu o biznesowe i techniczne wymagania aplikacji.
  • W przypadku używania taktycznego DDD do projektowania mikrousług granic partycji powinny być zgodne z powiązanymi kontekstami.
  • Podczas partycjonowania usług lub użytkowników do grodzi należy rozważyć poziom izolacji oferowany przez technologię oraz obciążenie w kontekście kosztów, wydajności i możliwości zarządzania.
  • Należy rozważyć połączenie grodzi przy użyciu wzorców ponawiania próby, wyłącznika i ograniczania przepustowości, aby zapewnić bardziej zaawansowaną obsługę błędów.
  • Podczas partycjonowania użytkowników do grodzi należy rozważyć użycie procesów, pul wątków i semaforów. Projekty takie jak resilience4j i Polly oferują platformę do tworzenia grodzi konsumenckich.
  • Podczas partycjonowania usług do grodzi należy rozważyć wdrożenie ich na oddzielnych maszynach wirtualnych, kontenerach lub procesach. Kontenery oferują dobrą równowagę w przypadku izolacji zasobu z dość małym obciążeniem.
  • Usługi, które komunikują się przy użyciu wiadomości asynchronicznych, można wyizolować za pośrednictwem innych zestawów kolejek. Każda kolejka może mieć dedykowany zestaw wystąpień przetwarzających wiadomości w kolejce lub pojedynczą grupę wystąpień używających algorytmu do usuwania z kolejki i przetwarzania wysyłania.
  • Określ stopień szczegółowości dla grodzi. Jeśli na przykład chcesz dystrybuować dzierżawy między partycjami, możesz umieścić każdą dzierżawę w oddzielnej partycji lub umieścić kilka dzierżaw w jednej partycji.
  • Monitoruj wydajność i umowę SLA każdej partycji.

Kiedy używać tego wzorca

Użyj tego wzorca, aby:

  • Izolować zasoby używane do korzystania z zestawu usług zaplecza, zwłaszcza jeśli aplikacja może zapewniać pewien poziom funkcjonalności nawet w sytuacji, gdy jedna z usług nie odpowiada.
  • Izolować użytkowników o krytycznym znaczeniu od użytkowników standardowych.
  • Chronić aplikację przed awariami kaskadowymi.

Ten wzorzec może być nieodpowiedni w następujących przypadkach:

  • Mniej wydajne wykorzystanie zasobów może być niedopuszczalne w projekcie.
  • Dodatkowa złożoność jest zbędna.

Projekt obciążenia

Architekt powinien ocenić, w jaki sposób wzorzec bulkhead może być używany w projekcie obciążenia, aby sprostać celom i zasadom opisanym w filarach platformy Azure Well-Architected Framework. Na przykład:

Filar Jak ten wzorzec obsługuje cele filaru
Decyzje projektowe dotyczące niezawodności pomagają obciążeniu stać się odporne na awarię i zapewnić, że zostanie przywrócony do w pełni funkcjonalnego stanu po wystąpieniu awarii. Strategia izolacji niepowodzeń wprowadzona za pomocą zamierzonej i pełnej segmentacji między składnikami próbuje zawierać błędy tylko do grodzi, które napotyka problem, uniemożliwiając wpływ na inne grodzi.

- RE:02 Przepływy krytyczne
- RE:07 Self-preservation
Decyzje dotyczące projektowania zabezpieczeń pomagają zapewnić poufność, integralność i dostępność danych i systemów obciążenia. Segmentacja między składnikami pomaga ograniczyć zdarzenia zabezpieczeń do zagrożonego grodzi.

- Segmentacja SE:04
Wydajność pomaga wydajnie sprostać zapotrzebowaniu dzięki optymalizacjom skalowania, danych, kodu. Każde grodzi można skalować indywidualnie, aby efektywnie zaspokoić potrzeby zadania hermetyzowanego w grodzie.

- PE:02 Planowanie pojemności
- PE:05 Skalowanie i partycjonowanie

Podobnie jak w przypadku każdej decyzji projektowej, należy rozważyć wszelkie kompromisy w stosunku do celów innych filarów, które mogą zostać wprowadzone przy użyciu tego wzorca.

Przykład

Następujący plik konfiguracji Kubernetes tworzy wyizolowany kontener, aby uruchomić jedną usługę z własnym procesorem CPU, zasobami pamięci i limitami.

apiVersion: v1
kind: Pod
metadata:
  name: drone-management
spec:
  containers:
  - name: drone-management-container
    image: drone-service
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "1"

Następne kroki