Message Brokers/Event Streaming - wersjonowanie "api"

Message Brokers/Event Streaming - wersjonowanie "api"
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
1

Jeśli mamy API restowe, to jedną z możliwości utrzymaniu ładu i skladu przy wielu klientach jest wersjowanie API. Dzięki temu jeśli mamy 10 klientów, to możemy np. usunąc jakies pole z JSONa w nowszej wersji nie obawiając się że wykrzaczą się dotychczasowi klienci. Ale jak to jest w przypadku korzystania z narzędzi typu RabbitMQ albo Apache Kafka? W większych projektach jak jakiś amazon takich klientów jest troszkę, co zrobić gdy chcemy modyfikować format wiadomości?


edytowany 1x, ostatnio: scibi_92
danek
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Poznań
  • Postów:797
2

Jeśli się da, to rozbijać zmiany na nieblokujące


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
3

Nie modyfikujesz. Dodajesz nowe typy wiadomości. Hardkorowo to już mieć w nazwach "eventów" zaszyte wersje. UserMadePooV1.
Możesz nawet dodawać nowe topics (ale tego raczej nigdy nie robiłem).

Po jakimś czasie można usunąć oczywiście - jak już wiadomo, że nie będzie obsługi starego formatu.


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 3x, ostatnio: jarekr000000
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
1

W naprawdę dużych systemach takich jak wymieniony przez Ciebie Amazon to faktycznie sprawa jest bardziej skomplikowana, i tam rzeczywiście należy albo unikać do maksimum "breaking changes" albo jak wspomniał Jarek dodawać nowe wersje w postaci całkowicie nowych typów.

W innych systemach można pokusić się o zwykle wersjonowanie, i liczyć się z tym że jak np. usunie się jakieś pole z wiadomości to klienci którzy się nie zaktualizowali będą dostawać domyślne wartości (bo raczej tak będzie skonfigurowana deserializacja).


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
superdurszlak
  • Rejestracja:prawie 7 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Kraków
  • Postów:1999
1

Robić zmiany kompatybilne wstecz / wprzód, jeśli tylko się da

Takie "niełamiące" zmiany to może być np.:

  • usunięcie atrybutu, który dotąd był opcjonalny
  • dodanie opcjonalnego atrybutu

A jeśli musisz zrobić zmianę łamiącą kompatybilność i jako tako jesteś w stanie zapanować nad klientami (czyli nie na zasadzie - masz 100 klientów z czego 30 na pewno znajdzie ważny powód, by nigdy nie zupgradować swojej wersji klienta), to w miarę możliwości rozbić na etapy, np. chcąc usunąć/zastąpić atrybut, który był obowiązkowy ale właściwie na wyrost:

  • robisz ten niechciany atrybut jako opcjonalny (w nowej wersji/nowym typie - jak wolisz) i wypuszczasz klienta, który sobie bez niego poradzi, oznaczasz to jako deprecated czy coś i rozgłaszasz nowinę
  • dajesz temu trochę pożyć, żeby się otoczenie oswoiło i przeniosło (w końcu, kiedyś)
  • kiedyś będziesz mógł to bezpiecznie usunąć. Chyba. Oby. Nadal będą kombinacje producera / consumera które są ze sobą niekompatybilne, ale przynajmniej będą jakieś kompatybilne i istnieje jakakolwiek gładka ścieżka.

@jarekr000000

Nie modyfikujesz. Dodajesz nowe typy wiadomości.

Nie będzie to nadal powodowało problemów, jeżeli stary odbiorca nie przewiduje / nie obsługuje (nawet przez zignorowanie) nowych i nieznanych typów wiadomości? Jeśli w tej samej kolejce / topiku zacznie pojawiać się coś o nieznanym typie / schemacie to IMO tak czy owak może to łamać kompatybilność i stanowić breaking change. Jak ta nieznaność nie jest nijak obsłużona, to w sumie chyba mała różnica czy zmienił się typ, czy pojawił się nowy?

Tak czy siak moim zdaniem ważniejsze od konkretnego sposobu realizacji jest projektowanie z myślą o tym, by ewentualne zmiany były jak najmniej bolesne. Jeśli schemat jest sztywny i klient sztywno się go trzyma, to co do zasady ciężko będzie zrobić zmianę bez wysadzania czegoś w powietrze i/lub bez spędzenia kilku sprintów czekając, aż wszyscy łaskawie przyjmą do wiadomości zmianę.

Może trochę pomóc wpisanie do kodeksu rycerskiego, że w kwestii formatu wiadomości ostateczne słowo ma nadawca ;)


edytowany 1x, ostatnio: superdurszlak
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
0

Nie będzie to nadal powodowało problemów, jeżeli stary odbiorca nie przewiduje / nie obsługuje (nawet przez zignorowanie) nowych i nieznanych typów wiadomości?

No ale o to chodzi.
Jest np. topic1 z serwisu A , na który są podpięte serwisy X, Y, Z. Serwis A chce coś zmydyfikowac, więc powstaje topic2, X i Y zostają na topic1 a Z ma topic2


superdurszlak
  • Rejestracja:prawie 7 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Kraków
  • Postów:1999
1
Aleksander32 napisał(a):

No ale o to chodzi.
Jest np. topic1 z serwisu A , na który są podpięte serwisy X, Y, Z. Serwis A chce coś zmydyfikowac, więc powstaje topic2, X i Y zostają na topic1 a Z ma topic2

Słowa Jarka:

Możesz nawet dodawać nowe topics (ale tego raczej nigdy nie robiłem).

Zatem rozumiem, że idea dodawania nowych typów jest ortogonalna do dodawania nowych topików ;) nie mówiąc o tym, że w systemach rozproszonych mniej znaczy więcej, im mniej "odnóg" w postaci wysyłania eventów, requestów itd. tym lepiej bo mniej rzeczy może się popsuć.

Nie mówiąc o tym, że sam fakt dodania / zaprzestania używania topików sam w sobie mógłby stanowić breaking change. Szczególnie, jeśli zaczniesz rozważać sytuacje, gdy w tych topicach persystujesz sobie eventy przez nieograniczony czas i potencjalnie możesz do nich kiedyś wrócić - ale wtedy to już jakikolwiek breaking change, nawet rozbity na etapy, będzie dużym problemem gdy np. baaardzo nowy consumer zassie przedpotopowy event...

Ba, jak popuścić wodze fantazji jest jeszcze gorzej - co, jeśli oba topiki (stary i nowy) są spartycjonowane, kolejność eventów zachowana jest w obrębie partycji, a wprowadzona zmiana dotknie sposobu partycjonowania bo dotknie jakoś klucza? Może się okazać, że w zależności od topiku consumerzy mogą dostawać te same eventy w zamienionej kolejności - to już chyba lepiej walczyć z wieloma wersjami pod jednym topikiem ;)


edytowany 2x, ostatnio: superdurszlak
jarekr000000
dostawać te same eventy w zamienionej kolejności w zasadzie to prawie zawsze trzeba się przygotowwywać na absurdalne kolejności eventów. Np. najpierw dostajesz anulowanie zamówienia, a potem zamówienie - dość często to normalka.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
2

@superdurszlak:

Nie będzie to nadal powodowało problemów, jeżeli stary odbiorca nie przewiduje / nie obsługuje (nawet przez zignorowanie) nowych i nieznanych typów wiadomości? Jeśli w tej samej kolejce / topiku zacznie pojawiać się coś o nieznanym typie / schemacie to IMO tak czy owak może to łamać kompatybilność i stanowić breaking change. Jak ta nieznaność nie jest nijak obsłużona, to w sumie chyba mała różnica czy zmienił się typ, czy pojawił się nowy?

Tak będą problemy - stąd te nowe topics. Nie pracuje w żadnych amazonach więc u mnie tego typu problemy sa raczej proste:
a ) release - puty wszystkie instancje nie zostaną zupdatowane - (i tylko w dziwnych przypadkach to nie jest pare minut )- wtedy wystarczy zrobić najpierw release obsługujacy nowe wersje eventów, a jak już wszystko się zupdatuje to wrzucam taki, który też nowe eventy faktycznie wrzuca
b) inne serwisy, ale to są negocjowalne pojedyncze przypadki - można zawsze plan ułożyć (stare wersje eventów do starej kolejki/topiku, nowe do nowej)


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 2x, ostatnio: jarekr000000
superdurszlak
To jest to o czym pisałem, czyli rozbijanie niekompatybilnej zmiany na kompatybilne (między sobą) etapy ;)
S9
@Afish pracuje w Amazonach a milczy :(
BA
  • Rejestracja:ponad 4 lata
  • Ostatnio:prawie 2 lata
  • Postów:8
4

mam projekt gdzie jest pure event sourcing, do utrzymania kontraktu korzystamy z avro i schema registry, dodatkowo mamy osobne repozytorium do wersjonowania schematow i poki co sie sprawdza;)

edytowany 2x, ostatnio: bartekq
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:17 dni
2

@Aleksander32: Nie napiszę nic odkrywczego, większość już padła w tym temacie.

Przede wszystkim trzeba zadbać, żeby dało się wprowadzać zmiany. Czyli jeżeli są jakieś nowe pola w strukturze, to muszą one zostać zachowane, nawet jeżeli obecny kod ich nie rozumie. Czyli parsowanie jsona na jakieś nasze DTO na 99% nie przejdzie, bo w naszej klasie nie będzie zmiennych na nowe pola, więc potem je stracimy. Nieznane pola dobrze jest sygnalizować w aplikacji czy logach, ale nie wolno ich tracić.

Po drugie, przy wprowadzaniu zmian robimy okres przejściowy, gdy kod rozpoznaje obie wersje wiadomości (starą i nową). Może to robić przez osobny topic, przez osobny typ, albo po prostu ifologią, podejść jest wiele, każde ma wady i zalety. Ważne jest, żeby w okresie przejściowym przemigrować wszystkie dane, czyli jeżeli trzeba, to idziemy do bazy danych i robimy update na każdym rekordzie, żeby był w nowym formacie czy co tam jest potrzebne. Możemy też robić to na bieżąco, ale wtedy rzadko dotykane rekordy prawdopodobnie zostaną w starym formacie na bardzo długo. Tu dobrze jest stosować podejście z krokowym wdrażaniem aplikacji, mamy setkę maszyn, to wrzucamy nową wersję aplikacji tylko na jedną maszynę i patrzymy, czy wszystko działa. Trzymamy to na produkcji przez chwilę i dopiero potem lecimy z podmianą dalej.

Po trzecie, hashmapa w evencie jest bardzo przydatna. Robimy zwykły słownik ze stringa na stringa i tam możemy wrzucać wszystkie rzeczy „na chwilę” lub w przypadku nieprzewidzianych sytuacji.

Dalej dochodzą mniejsze sztuczki, na przykład aliasy w enumach mapowane na tę samą wartość, jakiś sidecar tłumaczący wiadomości, scentralizowanie tworzenia wiadomości do jakiegoś serwisu, aby ten zajął się dbaniem o strukturę i tym podobne. Zależy od skali, konkretnego zastosowania i czasu.

Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:około godziny
  • Postów:1873
1

Poczytaj o AVRO schema


”Engineering is easy. People are hard.” Bill Coughran
WhiteLightning
@Charles_Ray: a tak w kilku slowach co to robi?
superdurszlak
Avro to taki binarny protokół (de)serializacji, pozwala do pewnego stopnia ogarnąć zmiany schematu, w szczególności rozjazdy między writer's schema i reader's schema https://avro.apache.org/docs/current/spec.html#Schema+Resolution
FE
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 3 lata
0

@Charles_Ray: Dokładnie.

Sposobów na to jest wiele i raczej nie ma złotego graala, czasami poświęcasz latency, czasami flexibility, czasami coś innego. Warto zobaczyć jak to jest rozwiązane w popularnych protokołach - np. Protobuff, Avro, Thrift. Ogólnie jest to dość problematyczne, szczególnie jeżeli musisz zapewnić możliwość odtwarzania starych wiadomości (czasami nawet trzeba mieć sposób na powiązanie wersji kodu z wersją message z danego momentu).

Alternatywnie, w zależności od systemu, może da się wprowadzić 'negocjowanie' schema.

Oczywiście można stosować podejścia rodem z RESTa ale uciekałbym się do nich tylko w ostateczności.


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)