Projekt GitHub CQRS.NET zawiera kilka konkretnych przykładów tego, jak można zrobić EventStores w kilku różnych technologiach. W chwili pisania tego tekstu istnieje implementacja w języku SQL przy użyciu Linq2SQL i zgodny ze schematem SQL , jeden dla MongoDB , jeden dla DocumentDB (CosmosDB, jeśli jesteś na Azure) i jeden wykorzystujący EventStore (jak wspomniano powyżej). Na platformie Azure jest więcej, takich jak Table Storage i Blob Storage, które są bardzo podobne do płaskiego magazynu plików.
Myślę, że głównym celem jest to, że wszystkie są zgodne z tym samym zleceniem / umową. Wszystkie przechowują informacje w jednym miejscu / kontenerze / tabeli, używają metadanych do identyfikacji jednego zdarzenia od innego i „po prostu” przechowują całe zdarzenie tak, jak było - w niektórych przypadkach serializowane, w technologiach pomocniczych, tak jak było. W zależności od tego, czy wybierzesz bazę danych dokumentów, relacyjną bazę danych lub nawet plik płaski, istnieje kilka różnych sposobów, aby osiągnąć ten sam cel magazynu zdarzeń (jest to przydatne, jeśli w dowolnym momencie zmienisz zdanie i stwierdzisz, że musisz przeprowadzić migrację lub wesprzeć więcej niż jednej technologii przechowywania).
Jako programista przy projekcie mogę podzielić się spostrzeżeniami na temat niektórych wyborów, których dokonaliśmy.
Po pierwsze stwierdziliśmy (nawet z unikalnymi identyfikatorami UUID / GUID zamiast liczb całkowitych) z wielu powodów identyfikatory sekwencyjne występują ze względów strategicznych, dlatego samo posiadanie identyfikatora nie było wystarczająco unikalne dla klucza, więc połączyliśmy naszą główną kolumnę klucza identyfikatora z danymi / typ obiektu, aby stworzyć coś, co powinno być naprawdę (w sensie aplikacji) unikalnym kluczem. Wiem, że niektórzy ludzie mówią, że nie musisz go przechowywać, ale będzie to zależeć od tego, czy jesteś od podstaw, czy też musisz współistnieć z istniejącymi systemami.
Utknęliśmy z jednym kontenerem / tabelą / kolekcją ze względu na łatwość konserwacji, ale bawiliśmy się z oddzielną tabelą na jednostkę / obiekt. W praktyce stwierdziliśmy, że oznacza to, że aplikacja potrzebuje uprawnień „TWÓRZ” (co ogólnie nie jest dobrym pomysłem ... generalnie zawsze są wyjątki / wykluczenia) lub za każdym razem, gdy nowy obiekt / obiekt powstawał lub był wdrażany, nowy potrzebne do wykonania pojemniki / stoły / kolekcje magazynowe. Okazało się, że było to boleśnie powolne w przypadku lokalnego rozwoju i problematyczne w przypadku wdrożeń produkcyjnych. Możesz nie, ale takie było nasze doświadczenie w świecie rzeczywistym.
Inną rzeczą do zapamiętania jest to, że żądanie wykonania akcji X może spowodować wystąpienie wielu różnych zdarzeń, a zatem poznanie wszystkich zdarzeń wygenerowanych przez polecenie / zdarzenie / cokolwiek jest przydatne. Mogą również dotyczyć różnych typów obiektów, np. Naciśnięcie przycisku „kup” w koszyku może wywołać uruchomienie zdarzeń dotyczących konta i magazynu. Konsumująca aplikacja może chcieć wiedzieć to wszystko, dlatego dodaliśmy CorrelationId. Oznaczało to, że konsument mógł poprosić o wszystkie zdarzenia wywołane w wyniku jego żądania. Zobaczysz to w schemacie .
W szczególności w przypadku SQL odkryliśmy, że wydajność naprawdę stała się wąskim gardłem, jeśli indeksy i partycje nie były odpowiednio używane. Pamiętaj, że jeśli używasz migawek, wydarzenia będą musiały być przesyłane strumieniowo w odwrotnej kolejności. Wypróbowaliśmy kilka różnych indeksów i stwierdziliśmy, że w praktyce do debugowania rzeczywistych aplikacji w środowisku produkcyjnym potrzebne są pewne dodatkowe indeksy. Ponownie zobaczysz to w schemacie .
Inne metadane w trakcie produkcji były przydatne podczas dochodzeń opartych na produkcji, a sygnatury czasowe dały nam wgląd w kolejność utrwalania i zgłaszania zdarzeń. To dało nam pewną pomoc przy szczególnie silnie sterowanym zdarzeniami systemie, który generował ogromną liczbę zdarzeń, dając nam informacje o wydajności takich rzeczy, jak sieci i dystrybucja systemów w sieci.