FULL PRO CQRS - czy w tym przypadku warto i pytania

FULL PRO CQRS - czy w tym przypadku warto i pytania
Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Postów:779
0

Cześć. Wyobraźmy sobie, że mamy dość sporą apkę mikroserwisową z ładnie odseparowanymi DB z PGSQL (uwzględniłem to, bo pracowałem w banku, gdzie były MSy na wspólnej DB i fajnie, łatwo robiło się CQRS.. oczywiście nie zważając na wady wspólnej bazy w tym przypadku).

Żeby nie zagłębiać się super w domenę tej apki na warsztat weźmy trzy mikroserwisy - item , customer oraz search. Item to jakiś tam produkt w sklepie, customer to wiadomo - kupujący lub sprzedający, a search to mikroserwis nasłuchujący na zdarzenia domenowe i zapisujący sobie dane w elasticsearchu, które potem łatwo można szukać poprzez jakieś filtrowania.

Mamy sobie dwa ekrany na UI:

  1. Lista produktów z różnymi filtrami szukającymi
  2. Ekran szczegółów produktu

Póki co agregowanie danych na tych ekranach jest rozwiązane w ten sposób:

  1. Na podstawie filtrów idzie request do search service, który przeszukuje sobie elasticsearcha i zwraca listę IDków itemów (mimo, że ma część danych każdego itemu na potrzeby filtrowania), a następnie idzie drugi request już do item service z tymi id po listę itemów z większą ilością danych.

  2. Tutaj wejściem jest id itemu i następuje ok 5 zapytań do kilku różnych mikroserwisów po potrzebne dane. Czyli najpierw idzie request po detale itemu, następnie idzie request po detale sprzedawcy (jak już znamy sellerId z pierwszego requestu) i potem kaskadowo po inne potrzebne dane (niektóre oczywiście idą równolegle). Generalnie logika tam na froncie jest dość skomplikowana - po prostu front jest agregatem danych.

Czy na te dwa ekrany (i wiele innych w systemie gdzie agregujemy dane z wielu MS) CQRS byłbym dobrym rozwiązaniem?

  1. Sprawę z search service można załatwić w trochę odwrotny sposób - mógłby nasłuchiwać na dedykowany dla siebie rozszerzony event ze WSZYSTKIMI danymi danego itemu. Wtedy nie musimy uderzać z listą id do item service tylko po prostu search service jest naszym wejściem do części query.

  2. Wykorzystać search service, utworzyć w nim jakiś read model typu ItemDetails zawierający wszystkie dane potrzebne na tamtym ekranie i potworzyć nowe dedykowane eventy typu UserUpdated, AddressUpdated. Wtedy na ekranie Item Details nie musimy robić 5 requestów po dane tylko jeden do tego search service.

Jakie mam wątpliwości i pytania..

  1. Już teraz istnieje mi w systemie event ItemAdded/ItemUpdated z biznesowymi danymi, na które nasłuchują inne biznesowe MSy. Jeśli miałbym dołożyć nowy event emitowany przy dodaniu, edycji itemu to powinienem rozszerzyć ten istniejący czy dodać zupełnie nowy i emitować po prostu dwa eventy? Oczywiście pytam tu nie tylko o kontekst itemu, ale o resztę, którą będzie ten search używał do agregowania danych.

  2. Jak zasilić search service o istniejące dane po wprowadzeniu featura aby doprowadzić do jego spójności z resztą? No bo teraz on np. nie słucha na Usera, a musiałby,

  3. Jakie są strategie sprawdzania spójności i naprawiania ewentualnych braków? Zawsze event może nie dojść, albo coś innego może się sypnąć.

  4. Czy to jest w ogóle dobry pomysł?

edytowany 3x, ostatnio: Bambo
Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Postów:779
0

Ktoś, coś ? ;p

Na tematy architektury chyba najczęściej wypowiada się @Charles_Ray

Zastanawiam się jak najlepiej przeprowadzić taką migrację.

  1. Dać search servicowi dostęp read-only do baz danych potrzebnych MSów i zrobić migracje na poziomie skryptów.

czy też

  1. Po starcie Search Service sprawdzić stan elastica i jak będzie pusty to wysłać jakiś event w stylu dbread.initialized i wtedy wszystkie MSy powysyłają techniczne eventy w stylu ItemMigrationEvent, UserMigrationEvent. Boję się trochę o wydajność i zastanawiam się czy tą migrację robić wtedy jakoś batchowo czy jeden event na rekord czy też w jednym evencie wszystkie rekordy.
edytowany 1x, ostatnio: Bambo
Charles_Ray
Jakie mam SLA na odpowiedz? :)
Bambo
Naprawdę odpowiedź na takie pytania kosztuje ? :D
Charles_Ray
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 2 godziny
  • Postów:1873
0
  1. Przed zapisaniem dokumentu w Elasticu możesz w serwisie dociągnąć synchronicznie niezbędne dane. Czyli reagujesz na event, że dodano item i sobie dociągasz usera albo dane z innych domen.
  2. Nie rozumiem koncepcji z tymi migracjami, chodzi o inicjalizację na start wyszukiwarki? Jeśli chodzi o utrzymanie spójności (eventual consistency), to nie wiem jak to zrobić perfekcyjnie, ale może w 90% przypadków wystarczy monitoring laga na kolejce. W przypadku, kiedy nie uda się dociągnąć danych (np. tego usera) można albo odbić cały event ItemAdded, albo ponawiać pobieranie usera.

”Engineering is easy. People are hard.” Bill Coughran
Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Postów:779
0

Tak, chodzi o inicjacie wyszukiwarka na start. No bo jakieś dane już w tabelkach mam i muszę jakoś wystartować tega elastica z danymi.

Charles_Ray
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 2 godziny
  • Postów:1873
0

Ile tych danych? Może przerzucić jednorazowo skryptem? Wyemitować sztucznie eventy? Trzeba tylko uważać, żeby nie dać zbyt dużego ruchu jeśli to prod.


”Engineering is easy. People are hard.” Bill Coughran
Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Postów:779
0

Powiedzmy, że z 10 tabel po 10 tys rekordów (i tak dużo zawyżyłem). To na razie staging, proda jeszcze nie ma. Mogę to opędzlować batchowo zawsze,

Miałem pomysł na taki mechaizm, aby w każdym mikroserwisie, który emituje eventy zrobić tabelkę SYNCHRONIZING_COMMAND, która będzie zawierała takie dane, jak nazwa tabeli, min id, max id i confirmed i zdefiniować joba, która sobie chodzi co jakiś tam czas i sprawdza czy jest coś do zasilenia. Załóżmy, że chcemy zaktualizować Searcha wszystkimi danymi z tabeli item to po prostu:

Insertujemy do DB wiersz z table_name = ITEM, min id = null, max id = null, confirmed = false. Nulle oznaczają, że nie ma granic po obu stronach więc ściągamy wsio. Emitujemy migracyjne eventy i zapisujemy confirmed na true. Ta tabelka byłaby po prostu odpowiedzialna za trzymanie poleceń migracji.

Dzięki takiemu mechanizmowi możemy w trakcie działania apki naprawiać jak jakieś dane przestaną być z jakiegoś powodu spójne.

O przerzuceniu skryptem też myślałem, żeby użyć jakiegoś logstasha do tego.

edytowany 2x, ostatnio: Bambo
Charles_Ray
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 2 godziny
  • Postów:1873
1

Ciekawe, nie wiem jakby to rozwiązanie się skalowało względem liczby usług oraz jaki byłby narzut na development i utrzymanie tego. Jeśli to jest jednorazowa akcja, to zrobiłbym to najprościej jak się da, czyli skrypt :) przy takiej ilości danych to w ogóle nie widzę komplikacji, to nie są TB danych


”Engineering is easy. People are hard.” Bill Coughran
edytowany 1x, ostatnio: Charles_Ray
Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Postów:779
0

W jakim sensie skalowało względem lizcby usług?
Jestem świadomy tego, że na każdy Mikroserwis wymagałby stworzenia takiej tabeli, napisania tego joba, emisji eventów itd. Chociaż no to nie jest też aż tak sporo pisania kodu.

Charles_Ray
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 2 godziny
  • Postów:1873
0

Może to czego szukasz to wzorzec Transactional Outbox. Pamiętaj ze tabela to baza, a baza dodaje złożoności do aplikacji, bo to jest osobny komponent który trzeba ogarniać. Nie wiem czy podejście „nowa usługa - nowa tabela” nie jest przeinżyniorowaniem, które potem będzie uwierać jak kamień w bucie. Może problem ma charakter bardziej lokalny?


”Engineering is easy. People are hard.” Bill Coughran
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)