Kolejka jako zewnętrzne API systemu

0

Interesuje mnie co sądzicie o takim podejściu do integracji. Jest sobie system, pojawiają się w nim jakieś zmiany danych. Te delty powinny znaleźć się jak najszybciej w systemie klienta. Pomysł jest taki, że stawiam sobie jakiś serwer kolejkowy, jak pojawi się jakaś delta, jest pakowana strukturyzowaną wiadomość i wrzucana do kolejki "export", do kolejki jest podpięty po stronie klienta klient, który dostaje asynchronicznie wiadomość o tym, że coś się pojawiło, robi peek, lock, ack i przejmuje odpowiedzialność za dostarczenie danych. Z mojego punktu widzenia sprawa prosta i czysta, załadowałem dane do kolejki "granicznej", klient potwierdził ich otrzymanie, nie ma tworzenia ekstra komponentów, otwierania portów po stronie klienta, zbędnych zapytań "masz coś dla mnie", opóźnień transmisji itd.
Tylko jest to podejście mniej popularne, niż np. REST. Widzicie jakieś problemy (np. bezpieczeństwo) z takim udostępnianiem danych? Dostawialibyście do tego jakiś APIGateway i próbowali tę komunikację zmieniać z AMQP (Azure Service Bus) na jakieś WebSockets itp?

1

Hej,

Popularny, znany i sprawdzony system tzw. Messeging Queue. Co do security to są oczywiście kanały szyfrowane itp.

Miłego dnia!

1

Najszybciej (trzeba by zdefiniować co to oznacza) i najpewniej jak ta deltę wyślesz synchronicznie na jakieś api drugiego systemu. Kolejka jest ok jak chcesz przesunąć odpowiedzialność na stronę odbiorcy i nie interesuje cię co się stanie z danymi. Jak masz być 100 % pewny że to się tam znalazło to nie spełnia to tych wymagań.

0

Ja miałem tylko sytuację odwrotną czyli klient wysyłał informację na AMQP (w zasadzie to podobno była Kafka, obudowana tak żeby implementowała AMQP). Plusów oczywiście jest mnóstwo w porównaniu z synchronicznym restem. Tylko zastanawiam się czy to są plusy na których ci zależy? No bo co jednak będzie szybsze, prosty rest czy skomplikowaną kolejka (wczale nie sugeruje tu odpowiedzi :P ). W systemie używaliśmy kolejki dla powolnych danych których może być mnóstwo, kafka ogarniała za nas skalowanie (w zasadzie to zamiast skalowac naszą aplikację w pierwszej kolejności to musielismy skalowac kafkę w pierwszej kolejności :D )

UPDATE a skalowałeś słownik? Tak, przed pierwszą kawą to ja nie wiem co to ortografia. Po pierwszej coś sobie przypominam. BTW przeczytałem a skasowałeś słownik i to w zasadzie prawda bo mam angielski ustawiony jako język w rezultacie tekst wygląda ta XD
Screenshot 2022-11-14 083322.png

1

To co @S4t plus pytanie jaka skala tych wiadomości i czy potrzebujesz potwierdzenia dostarczenia/konsumpcji takiej wiadomości i obsługi fallbacków (co gdy wiadomość jednak nie dotrze)? Kolejki są fajne do przetwarzania dużych wolumenów wiadomości asynchronicznie (wrzucam na kolejkę i mam to gdzieś co się stanie).

nie ma tworzenia ekstra komponentów

klient musi sobie kolejkę i takiego listenera na stworzyć

otwierania portów po stronie klienta

w jaki sposób klient wystawi kolejkę na świat? Kolejki często mają mniej popularne porty skonfigurowane niż 443 czy 80, które są otwarte by default.

Tylko jest to podejście mniej popularne, niż np. REST.

Bo trudniejsze -> wymaga postawienia, konfiguracji i utrzymywania message brokera

zbędnych zapytań "masz coś dla mnie"

Skorzystaj z HTTP i web hooków - działa podobnie do kolejki, po prostu w momencie pojawienia się danych pakujesz je w wiadomośc HTTP i wysyłasz pod wskazany przez klienta adres. Tam już sobie jest listener, który odbiera wiadomość i zwraca status. W przypadku gdy status jest 500 to możesz przetrzymać wiadomość po swojej stronie i spróbować ponownie za jakiś czas (Retry Pattern). Jak po kilku razach się nie uda to pasujesz (Circuit Breaker Pattern).

W dodatku kolejki często mają limit na wielkość wiadomości. Można go zmienić, ale trzeba się liczyć z tym, że im większy payload będzie się pchać na kolejkę tym jej wydajność będzie spadać i trzeba będzie ją w jakiś sposób skalować.

0

@S4t: Żeby wysłać synchronicznie "gdzieś", to "gdzieś" musiałoby implementować i udostępniać API, czyli wymagałbym od klienta wystawienia na świat jakiegoś endpointa, uwierzytelniać się jakoś przechowywać dane do tego uwierzytelniania itd. Dlatego webhook nie jest fajny.
,
Zależy mi na pewności, że "dane nie zginęły bez wieści", tych danych nie jest dużo (dane wprowadzane przez użytkowników), czas poinformowania drugiej strony liczony w sekundach, nie w milisekundach.
Dlatego wyobrażam sobie to tak, że mam system, który zapewnia, że dane trafią do kolejki (powiedzmy kilkanaście, może kilkadziesiąt kB).

Oczywiście nie wiem co klient zrobi z tymi danymi, bo to już nie mój system, nie moja odpowiedzialność, ale liczy się to, że dałem mu:

  • powiadomienie, że coś jest na kolejce

  • możliwość odczytania+lock wiadomości

  • możliwość potwierdzenia (usunięcia) wiadomości z kolejki

  • w razie problemów (odrzucenie, albo niepotwierdzenie wiadomości w jakimś tam czasie) ponowną próbę dostarczenia wiadomości

  • magazynowanie wiadomości, które pomimo X prób nie zostały "przejęte" (czyli deadletter)

    @markone_dev TO nie klient sobie twory kolejki, one są już dostęne po stronie serwera. Klient ma jakiś tam trochę pokrętny hanshake, ale ostatecznie dostaje Azure SAS, podłącza się na nasłuch, jak coś dostanie, to robi z tym co chce (nie moja odpowiedzialność).

    Web hooks mają tę wadę, że klient (customer), musiałby stworzyć taki endpoint i wystawić go na świat, maszyna na której jest ten endpoint musi mieć też dostęp (jakoś) do potencjalnie dość krytycznych systemów.

1

Interfejs jak interfejs.

Jedyne co mi przychodzi do głowy, to gdyby ktoś miał wysłać tyle wiadomości na topic że przewyższy to możliwość obsłużenia ich przez Twoje consumery na instancji, ale to samo chyba też jest w REST, który wrzuca na kolejkę.

0

Jedyne zalety które widzę to prostsza implementacja u ciebie (jak chcesz zrobić webhooki z retryami to i tak pewnie będzie tam jakaś kolejka) i dobra logika obsługi błędów tj. rejectów i błędów po stronie klientów. Wady jakie widzę:

  • bardziej skomplikowane, im prościej tym lepiej jeśli nie ma oczywistych zalet
  • nie ma złotego standardu dla brokerów. Wspomniana kolejka z Azure używa jakiegoś AMQP 1.0, który jest całkowicie niekompatybilny z wersją używaną przez Rabbita. Dobre API powinno być proste i lepiej jest dostarczyć taki produkt, który nie będzie wymagał długiego studiowania przez devów po drugiej stronie
  • tak się historycznie złożyło, że takie wiadomości idą przez HTTP calle.
  • łatwiejsze testowanie po stronie klienta. Utworzenie wiadomości testowej to będzie jedno zapytanie HTTP vs czytanie jak się stawia daną kolejkę lokalnie i inne tego typu zabawy
0

@slsy: No trochę zalet jest:

  • Pewność, że podjęta zostanie przynajmniej 1 próba dostarczenia wiadomości (albo 10..)
  • Potwierdzenie, że wiadomość została odebrana
  • Uproszczenie middleware
  • Bezpieczeństwo - klient nie musi miec żadnego otwartego portu, brak zabawy z IPsec itp.

Klient ma dostęp do środowiska testowego, więc nie ma też problemu z testami.

Ogólnie, dla mnie bardzo wygodna jest sytuacja, w której wiadomość albo siedzi sobie w kolejce i czeka (co można też monitorować), albo wysyła ack i przejmuje za nią odpowiedzialność. Jak coś się wysypie w tym procesie, to następuje kolejna próba dostarczenia wg. jakiegoś tam parametru. Jak to się nie powiedzie, to wiadomość nie ginie. Czyli jakiś tam w miarę pewny model dostarczania danych.

1

Jeżeli z biznesowego punktu widzenia komunikacja asynchroniczna nie tworzy żadnych problemów, to MQ powinno być domyślnym rozwiązaniem. Ustaw sobie Kafke po swojej stronie i jesteś w 100% niezależny od klienta. Jak oni mają awarię, to jest to ich problem, jeżeli będziesz komunikował się synchroniczne to jest to Twój problem także. Ustaw długą 'pamięć/retention' na temacie Kafkowym i klient za darmo dostanie 'przywracanie po awarii'. Kafka da Ci obraz, tego co się działo w Twoich systemach - nawet, jeżeli klient weźmie sobie wiadomość zapisze offset i mu się aplikacja wysypie to będziesz miał dowód, że Ty swoją pracę wykonałeś. Ogólnie dostaniesz za darmo wszystkie benefity z Event Sourcingu.

Ustaw sobie kontrakty danych z AVRO lub JSON i z Rejestrem Schematów(Schema Registry) i jeżeli spróbujesz zmienić swój schemat danych w niekompatybilny sposób SR Ci nie pozwoli tego zrobić.

Upewnij się, że:

  • Klient rozumie, że może te sama wiadomość dostać kilka razy(W REST jest tak samo)
  • Wy rozumiecie, że na poziomie producenta Kafki można łatwo stracić kolejność wiadomości.

EDIT.Co do tych punktów:

powiadomienie, że coś jest na kolejce - To dostajesz za darmo w Kafce. Klient ma subskrybenta na "temacie" lub np. Lambdę w AWS jak coś się pojawi na temacie.

możliwość odczytania+lock wiadomości - Automat.

możliwość potwierdzenia (usunięcia) wiadomości z kolejki - Nie musi tej wiadomości usuwać, jeżeli jego subskrybent zapisze offset to drugi raz jej nie przeczyta. Przeczyta tylko te które przyszły po niej.

w razie problemów (odrzucenie, albo niepotwierdzenie wiadomości w jakimś tam czasie) ponowną próbę dostarczenia wiadomości - To jest problem klienta. Ty dostarczyłeś wiadomość zgodnie z kontraktem technicznym i danych.

magazynowanie wiadomości, które pomimo X prób nie zostały "przejęte" (czyli deadletter) - To jest problem klienta. Ty dostarczyłeś wiadomość zgodnie z kontraktem technicznym i danych.

0
dmw napisał(a):

Jeżeli z biznesowego punktu widzenia komunikacja asynchroniczna nie tworzy żadnych problemów, to MQ powinno być domyślnym rozwiązaniem.

Dlaczego?

3
S4t napisał(a):
dmw napisał(a):

Jeżeli z biznesowego punktu widzenia komunikacja asynchroniczna nie tworzy żadnych problemów, to MQ powinno być domyślnym rozwiązaniem.

Dlaczego?

Chociażby dlatego, że masz całą masą wzorców integracyjnych dla tego podejścia i wiele rzeczy ogarniesz na brokerze, bez konieczności dotykania aplikacji.

0
dmw napisał(a):

Ustaw sobie kontrakty danych z AVRO lub JSON i z Rejestrem Schematów(Schema Registry) i jeżeli spróbujesz zmienić swój schemat danych w niekompatybilny sposób SR Ci nie pozwoli tego zrobić.

Nie ten przypadek - jest jakaś opasła dokumentacja branżowa dla tego typu danych. Ale słuszna uwaga, u mnie po prostu mniej roboty, bo wystarcza sprawdzenie ze schemą.

Upewnij się, że:

  • Klient rozumie, że może te sama wiadomość dostać kilka razy(W REST jest tak samo)
  • Wy rozumiecie, że na poziomie producenta Kafki można łatwo stracić kolejność wiadomości.

Kolejka, nie topic, więc klient musi świadomie zrobić ack i usunąć wiadomść z kolejki. Oczywiście kolejność wiadomości nie musi być zachowana w trakcie całego procesu i konieczne jest zachowanei idempotencji wiadomości.

EDIT.Co do tych punktów:

powiadomienie, że coś jest na kolejce - To dostajesz za darmo w Kafce. Klient ma subskrybenta na "temacie" lub np. Lambdę w AWS jak coś się pojawi na temacie.

Tak, to jest na poziomie samego protokołu.

możliwość odczytania+lock wiadomości - Automat.

Dokładnie, "bo to kolejka". Odpada np. konieczność zastanawiania się jak zasymulować peek&lock/ack bez kolejki.

możliwość potwierdzenia (usunięcia) wiadomości z kolejki - Nie musi tej wiadomości usuwać, jeżeli jego subskrybent zapisze offset to drugi raz jej nie przeczyta. Przeczyta tylko te które przyszły po niej.

Znowu - nie kafka (topics), tylko kolejka.

w razie problemów (odrzucenie, albo niepotwierdzenie wiadomości w jakimś tam czasie) ponowną próbę dostarczenia wiadomości - To jest problem klienta. Ty dostarczyłeś wiadomość zgodnie z kontraktem technicznym i danych.

I tak i nie. Moją odpowiedzialnością jest sprawić, żeby dane nie zginęły i umożliwić klientowi zadbanie, żeby dane w drodze nie zginęły. Czyli można zbudować klienta w ten sposób:

msg = firstPeekAndLock()
try{
secure(msg)//przejęcie odpowiedzialności
acknowledge(msg)
}
catch{
release(msg)
}

magazynowanie wiadomości, które pomimo X prób nie zostały "przejęte" (czyli deadletter) - To jest problem klienta. Ty dostarczyłeś wiadomość zgodnie z kontraktem technicznym i danych.

Moim problemem jest udowodnić, że jakaś tam porcja danych była przetwarzana i nastąpiła próba (lub próby) dostarczenia wiadomości. No i kwestia praktyczna - jak coś, to łatwo przejrzeć co zostało odrzucone, potwierdzić odrzucenie, albo zrobić resend.

1

@piotrpo: Dlaczego musisz tę wiadomość usunąć? To jest jakiś biznesowy wymóg? Jak potem robicie replay danych? Z systemów źródłowych?

re: I tak i nie. Moją odpowiedzialnością jest sprawić, żeby dane nie zginęły i umożliwić klientowi zadbanie, żeby dane w drodze nie zginęły. (..)

W momencie w którym wiadomość ląduje w Kafce, ty już wiesz wykonałeś swoją pracę. Jeżeli klient nie jest w stanie przetwarzać danych w taki sposób żeby nie zginęły, to jest to jego problem. Ja pracując na projektach integracyjnych zawsze wyznaczam linie do której jestem odpowiedzialny za dane. W wielu wypadkach jest to Kafka z długą retencją wiadomości. Jeżeli klient przychodź i mówi że nie otrzymał wiadomości to pokazuje mu, że ta wiadomość istnieje w Kafce i to jest koniec dyskusji z mojej strony. Takie sytuacje się zdarzają - głównie dlatego że niektórzy eksperci polecają np. używanie auto-commit na subskrybencie Kafki i nagle 'delivery semantics' zmienia się z 'at least once' do 'maybe once' jak się aplikacja wysypie a offset już zapisany.

0
S4t napisał(a):
dmw napisał(a):

Jeżeli z biznesowego punktu widzenia komunikacja asynchroniczna nie tworzy żadnych problemów, to MQ powinno być domyślnym rozwiązaniem.

Dlaczego?

Dlatego, ze np:
Klientowi może paść baza danych i nie jest w stanie w tym momencie zapisać tych danych. Dlaczego u Ciebie praca ma się nawarstwiać kiedy wszystko u Ciebie dobrze działa?
Klient może wywoływać zewnętrzne API które właśnie nie działa, dlaczego Ciebie miałoby to interesować?A jak zewnętrzne API wywołuje następne API?Skąd wiesz, że tak nie jest?
Ogólnie rzecz biorąc, nie wiesz co robi klient, nie znasz jego kodu, praktyk itd. i nie możesz opierać stabilności swojego systemu o zewnętrzne czynniki. Dlaczego nagle mają u Ciebie się włączyć wszystkie alarmy, i Twój zespół musi oderwać się od swojej pracy i zobaczyć co się dzieje, kiedy problemem jest API które wywołuje klient?

https://gist.github.com/chitchcock/1281611 - przeczytaj proszę tego posta i historię z nim związana, dotyka w pewien sposób tematu o którym dyskutujemy na większą skalę.

1

Pamietaj ze Kafke trzeba postawic i pozniej utrzymac, robic security fixy itp. Wiec warto sie upewnic ze macie kogos kto to ogarnie. Przy duzych klastrachi duzym ruchu jest to nietrywialne.

2
WhiteLightning napisał(a):

Pamietaj ze Kafke trzeba postawic i pozniej utrzymac, robic security fixy itp. Wiec warto sie upewnic ze macie kogos kto to ogarnie. Przy duzych klastrachi duzym ruchu jest to nietrywialne.

Przy dużym ruchu zwykłe wysyłanie przez HTTP z ponowieniami i deadletteringiem też może być nietrywialne i się skończy na tym, że albo będziesz robił swoją kolejkę na bazie danych (bo chcesz ponawiać wysyłanie wiadomości przez X czasu z rosnącymi interwałami) albo skorzystasz z kolejki tak czy siak ;)

0
some_ONE napisał(a):
WhiteLightning napisał(a):

Pamietaj ze Kafke trzeba postawic i pozniej utrzymac, robic security fixy itp. Wiec warto sie upewnic ze macie kogos kto to ogarnie. Przy duzych klastrachi duzym ruchu jest to nietrywialne.

Przy dużym ruchu zwykłe wysyłanie przez HTTP z ponowieniami i deadletteringiem też może być nietrywialne

Jaki to jest duży ruch? Kiedy warto komplikować coś kolejką, a kiedy nie?

1
dmw napisał(a):

@piotrpo: Dlaczego musisz tę wiadomość usunąć? To jest jakiś biznesowy wymóg? Jak potem robicie replay danych? Z systemów źródłowych?

Chyba za bardzo się przywiązałeś do Kafki w tej dyskusji. Kolejka na ASB może zostać skonfigurowana tak, że:

  • klient robi peek&lock wiadomości
  • jeżeli zrobi na tej wiadomości ack - wiadomość znika z kolejki
  • jeżeli tego nie zrobi, po określonym czasie wiadomość ma zdejmowanego locka
  • jeżeli nastąpi ileś tam (do ustawienia) prób pobrania wiadomości nie zakończonych ack, to wiadomość jest oznaczana jako niemożliwa do dostarczenia

Czyli:
klient ma możliwość pobrania, zabezpieczenia wiadomości, zanim zostanie ona "skonsumowana"
ja mogę podejrzeć taką wiadomość i coś z nią zrobić, np. c&p na główną kolejkę

re: I tak i nie. Moją odpowiedzialnością jest sprawić, żeby dane nie zginęły i umożliwić klientowi zadbanie, żeby dane w drodze nie zginęły. (..)

W momencie w którym wiadomość ląduje w Kafce, ty już wiesz wykonałeś swoją pracę. Jeżeli klient nie jest w stanie przetwarzać danych w taki sposób żeby nie zginęły, to jest to jego problem. Ja pracując na projektach integracyjnych zawsze wyznaczam linie do której jestem odpowiedzialny za dane. W wielu wypadkach jest to Kafka z długą retencją wiadomości. Jeżeli klient przychodź i mówi że nie otrzymał wiadomości to pokazuje mu, że ta wiadomość istnieje w Kafce i to jest koniec dyskusji z mojej strony. Takie sytuacje się zdarzają - głównie dlatego że niektórzy eksperci polecają np. używanie auto-commit na subskrybencie Kafki i nagle 'delivery semantics' zmienia się z 'at least once' do 'maybe once' jak się aplikacja wysypie a offset już zapisany.

Ale to jest moja kafka :) moją odpowiedzialnością jest nie tylko dostarczenie wiadomości na kolejkę, ale również zapewnienie możliwości bezpiecznego jej odebrania przez klienta.

1 użytkowników online, w tym zalogowanych: 0, gości: 1