Wzorce MSA - Event Sourcing

MSA Patterns: Event Sourcing – Wzorzec Projektowy w Architekturze Mikrousług

W architekturze mikrousług (MSA), zarządzanie stanem aplikacji i danymi to jedno z najważniejszych wyzwań. Tradycyjne podejścia, w których systemy po prostu aktualizują swoje bazy danych, mogą być problematyczne, gdy system staje się bardziej złożony i rozproszony. Event Sourcing to wzorzec, który pozwala na efektywne zarządzanie stanem aplikacji poprzez przechowywanie wszystkich zdarzeń, które zmieniają ten stan.



Czym jest Event Sourcing?

W tradycyjnych systemach aktualizujemy dane, nadpisując poprzednią wartość – np. w bazie danych. W Event Sourcingu każda zmiana stanu systemu jest zapisywana jako zdarzenie (ang. event). Zamiast zapisywać aktualny stan, zapisujemy historię zdarzeń, które doprowadziły do tego stanu. Dzięki temu możemy odtworzyć dowolny poprzedni stan systemu, co daje większą elastyczność i niezawodność.

Główne zalety Event Sourcing:

  1. Rekonstruowanie stanu: Możliwość odtworzenia dowolnego stanu systemu na podstawie sekwencji zdarzeń.
  2. Pełna historia: Każda zmiana jest zapisywana, co pozwala na pełne audytowanie wszystkich działań.
  3. Integracja z CQRS: Event Sourcing często idzie w parze z CQRS (Command Query Responsibility Segregation), co umożliwia rozdzielenie operacji zapisu i odczytu danych.
  4. Asynchroniczne przetwarzanie: Zdarzenia mogą być przetwarzane w sposób asynchroniczny, co zwiększa wydajność systemu.

Przykład Event Sourcing w Javie

Poniżej przedstawiamy przykład prostego systemu zarządzania kontem bankowym z zastosowaniem wzorca Event Sourcing w Javie.

Definiowanie zdarzeń

Najpierw definiujemy zdarzenia, które będą zapisywane w systemie:


public interface Event {} public class MoneyDepositedEvent implements Event { private final String accountId; private final double amount; public MoneyDepositedEvent(String accountId, double amount) { this.accountId = accountId; this.amount = amount; } public String getAccountId() { return accountId; } public double getAmount() { return amount; } } public class MoneyWithdrawnEvent implements Event { private final String accountId; private final double amount; public MoneyWithdrawnEvent(String accountId, double amount) { this.accountId = accountId; this.amount = amount; } public String getAccountId() { return accountId; } public double getAmount() { return amount; } }

Rekonstruowanie stanu

Kolejnym krokiem jest odtworzenie stanu konta na podstawie sekwencji zdarzeń:


public class Account { private String accountId; private double balance = 0.0; public Account(String accountId) { this.accountId = accountId; } public void apply(Event event) { if (event instanceof MoneyDepositedEvent) { this.balance += ((MoneyDepositedEvent) event).getAmount(); } else if (event instanceof MoneyWithdrawnEvent) { this.balance -= ((MoneyWithdrawnEvent) event).getAmount(); } } public double getBalance() { return balance; } }

Zarządzanie zdarzeniami

Na koniec implementujemy mechanizm, który będzie obsługiwał zapisywanie i odtwarzanie zdarzeń:


import java.util.ArrayList; import java.util.List; public class EventStore { private List<Event> events = new ArrayList<>(); public void addEvent(Event event) { events.add(event); } public List<Event> getEvents() { return events; } }

Event Sourcing z użyciem CQRS

Wzorzec CQRS (Command Query Responsibility Segregation) często współpracuje z Event Sourcing. CQRS rozdziela operacje zapisu (zmian stanu) i odczytu, co pozwala na lepszą optymalizację tych procesów. Dzięki Event Sourcing możemy odtworzyć aktualny stan systemu na podstawie historii zdarzeń, a CQRS pozwala na rozdzielenie obsługi tych zdarzeń od zapytań.

Diagramy Event Sourcing w PlantUML

Poniżej znajduje się przykład diagramu sekwencji, który przedstawia przepływ zdarzeń w systemie opartym na Event Sourcing.



Wyzwania związane z Event Sourcing

Chociaż Event Sourcing oferuje wiele korzyści, warto również pamiętać o kilku wyzwaniach:

  1. Złożoność: Zarządzanie historią zdarzeń i odtwarzanie stanu może być bardziej skomplikowane niż w tradycyjnych systemach.
  2. Rozmiar danych: W miarę jak system zapisuje coraz więcej zdarzeń, baza danych zdarzeń może rosnąć, co może wpływać na wydajność.
  3. Eventual Consistency: W systemach rozproszonych stosujących Event Sourcing często musimy radzić sobie z eventual consistency, czyli sytuacją, w której stan systemu nie jest natychmiastowo spójny, ale stanie się spójny w pewnym momencie.

Podsumowanie

Event Sourcing to potężny wzorzec projektowy, który umożliwia pełne śledzenie i odtwarzanie stanu aplikacji. Jest szczególnie przydatny w rozproszonych systemach opartych na mikrousługach, gdzie konieczna jest niezawodność, elastyczność i pełna historia działań. Dzięki zastosowaniu Event Sourcing można lepiej zarządzać stanem aplikacji, integrując go z innymi wzorcami, takimi jak CQRS, oraz czerpać korzyści z asynchronicznego przetwarzania danych

Komentarze