Wzorzec transakcji wyrównującej

Azure

Jeśli używasz ostatecznie spójnej operacji składającej się z serii kroków, wzorzec transakcji wyrównywczej może być przydatny. W szczególności, jeśli co najmniej jeden krok nie powiedzie się, możesz użyć wzorca transakcji wyrównywałej, aby cofnąć pracę wykonywaną przez kroki. Zazwyczaj można znaleźć operacje zgodne z modelem spójności ostatecznej w aplikacjach hostowanych w chmurze, które implementują złożone procesy biznesowe i przepływy pracy.

Kontekst i problem

Aplikacje uruchamiane w chmurze często modyfikują dane. Te dane są czasami rozłożone na różne źródła danych w różnych lokalizacjach geograficznych. Aby uniknąć rywalizacji i zwiększyć wydajność w środowisku rozproszonym, aplikacja nie powinna próbować zapewnić wysokiego poziomu spójności transakcyjnej. Zamiast tego aplikacja powinna implementować spójność ostateczną. W przypadku modelu spójności ostatecznej typowa operacja biznesowa składa się z serii oddzielnych kroków. Chociaż operacja wykonuje te kroki, ogólny widok stanu systemu może być niespójny. Jednak po zakończeniu operacji i uruchomieniu wszystkich kroków system powinien zostać ponownie spójny.

Podstawy spójności danych zawierają informacje o tym, dlaczego transakcje rozproszone nie są dobrze skalowane. Ten zasób zawiera również listę zasad modelu spójności ostatecznej.

Wyzwaniem w modelu spójności ostatecznej jest sposób obsługi kroku, który kończy się niepowodzeniem. Po niepowodzeniu może być konieczne cofnięcie wszystkich czynności opisanych w poprzedniej operacji. Nie zawsze można jednak wycofać dane, ponieważ inne współbieżne wystąpienia aplikacji mogły je zmienić. Nawet w przypadkach, gdy współbieżne wystąpienia nie zmieniły danych, cofnięcie kroku może być bardziej złożone niż przywrócenie stanu pierwotnego. Może być konieczne zastosowanie różnych reguł specyficznych dla firmy. Aby zapoznać się z przykładem, zobacz witrynę internetową podróży opisaną w dalszej części tego artykułu.

Jeśli operacja, która implementuje spójność ostateczną, obejmuje kilka heterogenicznych magazynów danych, cofanie kroków operacji wymaga odwiedzenia każdego magazynu danych z kolei. Aby zapobiec zachowaniu niespójności systemu, należy niezawodnie cofnąć pracę wykonywaną w każdym magazynie danych.

Dane, na które ma wpływ operacja implementujące spójność ostateczną, nie zawsze są przechowywane w bazie danych. Rozważmy na przykład środowisko architektury zorientowanej na usługi (SOA). Operacja SOA może wywołać akcję w usłudze i spowodować zmianę stanu, który jest przechowywany przez tę usługę. Aby cofnąć operację, należy również cofnąć tę zmianę stanu. Ten proces może obejmować ponowne wywołanie usługi i wykonanie innej akcji, która odwraca efekty pierwszego.

Rozwiązanie

Rozwiązaniem jest zaimplementowanie transakcji wyrównującej. Kroki transakcji wyrównywujące cofają efekty kroków w pierwotnej operacji. Intuicyjne podejście polega na zastąpieniu bieżącego stanu stanem, w ramach którego system znajdował się na początku operacji. Jednak transakcja wyrównywająca nie zawsze może przyjąć to podejście, ponieważ może zastąpić zmiany wprowadzone przez inne współbieżne wystąpienia aplikacji. Zamiast tego transakcja wyrównywająca musi być inteligentnym procesem, który uwzględnia dowolną pracę współbieżną. Ten proces jest zwykle specyficzny dla aplikacji, napędzany charakterem pracy wykonywanej przez oryginalną operację.

Najczęściej stosowana metoda polega na użyciu przepływu pracy w celu zaimplementowania ostatecznie spójnej operacji, która wymaga wyrównania. Podczas wykonywania oryginalnej operacji system rejestruje informacje o każdym kroku, w tym o tym, jak cofnąć pracę wykonywaną przez krok. Jeśli operacja zakończy się niepowodzeniem w dowolnym momencie, przepływ pracy zostanie przywrócony przez wykonane kroki. W każdym kroku przepływ pracy wykonuje pracę, która odwraca ten krok.

Istnieją dwa ważne kwestie:

  • Transakcja wyrównywająca może nie być konieczna do cofnięcia pracy w dokładnej odwrotnej kolejności oryginalnej operacji.
  • Może być możliwe wykonanie niektórych kroków cofania równolegle.

Takie podejście jest podobne do strategii Sagas omówionej na blogu Clemensa Vastersa.

Transakcja wyrównywająca jest ostatecznie spójną operacją, więc może również zakończyć się niepowodzeniem. System powinien być w stanie wznowić transakcję wyrównującą w punkcie niepowodzenia i kontynuować pracę. Może być konieczne powtórzenie kroku, który kończy się niepowodzeniem, dlatego należy zdefiniować kroki w transakcji wyrównywałej jako polecenia idempotentne. Aby uzyskać więcej informacji, zobacz Idempotency Patterns (Wzorce idempotentności) na blogu Jonathana Olivera.

W niektórych przypadkach interwencja ręczna może być jedynym sposobem odzyskania sprawności po kroku, który zakończył się niepowodzeniem. W takich sytuacjach system powinien zgłosić alert i dostarczyć jak najwięcej informacji o przyczynie awarii.

Problemy i kwestie do rozważenia

Podczas podejmowania decyzji o zaimplementowaniu tego wzorca należy wziąć pod uwagę następujące kwestie:

  • Ustalenie, kiedy krok operacji implementujący spójność ostateczną kończy się niepowodzeniem, może nie być łatwe. Krok może nie zakończyć się natychmiast niepowodzeniem. Zamiast tego może zostać zablokowany. Może być konieczne zaimplementowanie mechanizmu przekroczenia limitu czasu.

  • Nie jest łatwo uogólnić logikę kompensacji. Transakcja wyrównywająca jest specyficzna dla aplikacji. Opiera się na założeniu, że aplikacja dostarczy wystarczająco dużo informacji, aby można było cofnąć skutki każdego kroku operacji zakończonej niepowodzeniem.

  • Kroki w ramach transakcji wyrównującej należy zdefiniować jako polecenia idempotentne. Jeśli to zrobisz, kroki można powtórzyć, jeśli sama transakcja wyrównywająca zakończy się niepowodzeniem.

  • Infrastruktura, która obsługuje kroki, musi spełniać następujące kryteria:

    • Jest odporny w pierwotnej operacji i w transakcji wyrównywjącej.
    • Nie traci informacji wymaganych do zrekompensowania nieudanego kroku.
    • Niezawodnie monitoruje postęp logiki kompensacji.
  • Transakcja wyrównywająca nie musi zwracać danych systemowych do stanu na początku oryginalnej operacji. Zamiast tego transakcja rekompensuje pracę, którą operacja zakończyła się pomyślnie przed jej niepowodzeniem.

  • Kolejność kroków w transakcji wyrównywczej nie musi być dokładnie przeciwieństwem kroków w pierwotnej operacji. Na przykład jeden magazyn danych może być bardziej wrażliwy na niespójności niż inny. Kroki transakcji wyrównywujące, które cofają zmiany w tym magazynie, powinny nastąpić najpierw.

  • Niektóre miary mogą pomóc zwiększyć prawdopodobieństwo powodzenia ogólnej aktywności. W szczególności można umieścić krótkoterminową blokadę opartą na przekroczeniu limitu czasu dla każdego zasobu wymaganego do ukończenia operacji. Możesz również uzyskać te zasoby z wyprzedzeniem. Następnie wykonaj pracę dopiero po uzyskaniu wszystkich zasobów. Finalizuj wszystkie akcje przed wygaśnięciem blokad.

  • Logika ponawiania prób, która jest bardziej forgiving niż zwykle, może pomóc zminimalizować błędy, które wyzwalają transakcję wyrównywalną. Jeśli krok operacji implementujący spójność ostateczną zakończy się niepowodzeniem, spróbuj obsłużyć błąd jako wyjątek przejściowy i powtórzyć ten krok. Zatrzymaj operację i zainicjuj transakcję wyrównywalną tylko wtedy, gdy krok wielokrotnie kończy się niepowodzeniem lub nie można go odzyskać.

  • Podczas implementowania transakcji wyrównywczej napotykasz wiele tych samych wyzwań, przed którymi napotykasz podczas implementowania spójności ostatecznej. Aby uzyskać więcej informacji, zobacz sekcję "Zagadnienia dotyczące implementowania spójności ostatecznej" w temacie Data Consistency Primer (Podstawy spójności danych).

Kiedy używać tego wzorca

Używaj tego wzorca tylko w przypadku operacji, które muszą zostać cofnięte w razie niepowodzenia. Jeśli to możliwe, projektuj rozwiązania tak, aby uniknąć konieczności stosowania transakcji wyrównujących.

Projekt obciążenia

Architekt powinien ocenić, w jaki sposób wzorzec transakcji wyrównywanej 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. Akcje kompensacji dotyczą awarii w krytycznych ścieżkach obciążenia przy użyciu procesów, takich jak bezpośrednie wycofywanie zmian danych, przerywanie blokad transakcji, a nawet wykonywanie natywnych zachowań systemowych w celu odwrócenia efektu.

- RE:02 Przepływy krytyczne
- RE:09 Odzyskiwanie po awarii

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

Klienci korzystają ze strony internetowej podróży, aby zarezerwować trasy podróży. Pojedyncza trasa może składać się z serii lotów i hoteli. Klient, który podróżuje z Seattle do Londynu, a następnie do Paryża, może wykonać następujące kroki podczas tworzenia trasy:

  1. Rezerwacja miejsca na lot F1 z Seattle do Londynu.
  2. Rezerwacja miejsca na lot F2 z Londynu do Paryża.
  3. Rezerwacja miejsca na lot F3 z Paryża do Seattle.
  4. Rezerwacja pokoju w hotelu H1 w Londynie.
  5. Rezerwacja pokoju w hotelu H2 w Paryżu.

Te kroki składają się na ostatecznie spójną operację, mimo że każdy krok to osobna akcja. Oprócz wykonywania tych kroków system musi również rejestrować operacje licznika w celu cofnięcia każdego kroku. Te informacje są potrzebne w przypadku anulowania trasy przez klienta. Kroki niezbędne do wykonania operacji licznika mogą być następnie uruchamiane jako transakcja wyrównywająca.

Kroki transakcji wyrównywujące mogą nie być dokładnym przeciwieństwem oryginalnych kroków. Ponadto logika w każdym kroku transakcji wyrównywjącej musi uwzględniać reguły specyficzne dla działania firmy. Na przykład anulowanie rezerwacji lotów może nie uprawniać klienta do całkowitego zwrotu kosztów.

Na poniższej ilustracji przedstawiono kroki w długotrwałej transakcji na potrzeby rezerwacji trasy podróży. Można również zobaczyć kroki transakcji wyrównywujące, które cofają transakcję.

Diagram przedstawiający kroki tworzenia trasy. Pokazano również kroki transakcji wyrównywczej, która anuluje trasę.

Uwaga

Kroki transakcji wyrównywujące mogą być wykonywane równolegle, w zależności od sposobu projektowania logiki wyrównywczej dla każdego kroku.

W wielu rozwiązaniach biznesowych awaria jednego kroku nie zawsze wymaga wycofywania systemu przy użyciu transakcji wyrównywujących. Rozważmy na przykład scenariusz witryny internetowej podróży. Załóżmy, że klient rezerwuje loty F1, F2 i F3, ale nie może zarezerwować pokoju w hotelu H1. Najlepiej jest zaoferować klientowi pokój w innym hotelu w tym samym mieście, a nie anulowanie lotów. Klient nadal może zdecydować się na anulowanie. W takim przypadku transakcja wyrównywalna jest uruchamiana i cofa rezerwacje lotów F1, F2 i F3. Klient powinien jednak podjąć tę decyzję, a nie system.

Następne kroki

  • Podstawy spójności danych. Wzorzec transakcji wyrównującej jest często używany do cofania operacji, które implementują model spójności ostatecznej. Ten element primer zawiera informacje o korzyściach i kompromisach dotyczących spójności ostatecznej.
  • Wzorce idempotentności. W transakcji wyrównywałej najlepiej używać poleceń idempotentnych. W tym wpisie w blogu opisano czynniki, które należy wziąć pod uwagę podczas implementowania idempotentności.
  • Wzorzec nadzorcy agenta harmonogramu. W tym artykule opisano sposób implementowania odpornych systemów wykonujących operacje biznesowe korzystające z rozproszonych usług i zasobów. W tych systemach czasami trzeba użyć transakcji wyrównywałej, aby cofnąć pracę wykonywaną przez operację.
  • Wzorzec ponawiania. Transakcje wyrównywujące mogą wymagać obliczeń. Możesz spróbować zminimalizować ich użycie przy użyciu wzorca ponawiania prób w celu zaimplementowania skutecznych zasad ponawiania prób operacji, które zakończyły się niepowodzeniem.
  • Wzorzec transakcji rozproszonych saga. W tym artykule wyjaśniono, jak używać wzorca Saga do zarządzania spójnością danych między mikrousługami w scenariuszach transakcji rozproszonych. Wzorzec saga obsługuje odzyskiwanie po awarii za pomocą transakcji wyrównywalnych.
  • Wzorzec potoków i filtrów. W tym artykule opisano wzorzec potoków i filtrów, którego można użyć do rozkładania złożonego zadania przetwarzania na serię elementów wielokrotnego użytku. Możesz użyć wzorca Potoki i filtry ze wzorcem transakcji wyrównywujących jako alternatywy do implementowania transakcji rozproszonych.
  • Projektuj pod kątem samonaprawy. W tym przewodniku wyjaśniono, jak projektować aplikacje samonaprawiania. Transakcje wyrównywujące można używać w ramach podejścia samonaprawiania.