Wpis z mikrobloga

Mirki, potrzeba architekta, który zna się na chmurach

Mam dosyć specyficzną architekturę systemu w startupie, w którym pracuje. Otóż rozwinął się ostatnio mocno i zaczynamy rozkminiać jak niektóre rzeczy zrobić dobrze, żeby działały długoterminowo.

Obracamy się w kontekście AWS.

Mamy na produkcji 3 maszyny EC2, nazwijmy je Alpha, Beta, Gamma.

Na każdej z nich stoi (prawie) dokładnie to samo REST API (w 99% jest to samo, moze sie minimalnie różnić, to bez znaczenia)

Powiedzmy, że chcemy udostępnić zunifikowane API naszym klientom pod 1 domeną. Userzy mogą lets say pobierać/dodawac/modyfikować zamówienia.
będzie to wyglądało np tak:

GET https://api.example/orders/111/products
POST https://api.example/orders/222/products
PATCH https://api.example/orders/333/products

czy coś w stym stylu.

Problem polega na tym, że za order 111 odpowiada EC2 Alpha, za order 222 odpowiada EC2 Beta, a za order 333 odpowiada Gamma.

W związku z czym chciałbym aby:

GET https://api.example/orders/111/products -> pobrało i zwróciło wynik z API z Alphy
POST https://api.example/orders/222/products -> pobrało i zwróciło wynik z API z Bety
PATCH https://api.example/orders/333/products -> pobrało i zwróciło wynik z API z Gammy

Informacje, który order jest obsługiwany przez którą maszyne trzymamy w bazie sqlowej w AWS, takze dostep jest do tego prosty.

Mam kilka pomysłów jak to zrobić, ale chciałbym zapytać czy być może ktoś się spotkał z tego typu problemami i ma pomysł jak to rozwiązać tak, żeby na pewno żaden purysta się do tego nie doczepił.

Moje 2 pomysły to:
1. Skorzystanie z API Gateway + AWS Lambda. Stawiamy API gateway, wystawiamy go pod api.example, gdy przyjdzie request to odpala się lambda, wyciąga order_id z requestu, szuka przypisania orderu z bazy i robi jakiegos curla na tym konkretnym EC2 i zwraca wynik. Boję się, że to będzie wolne i drogie
2. Postawienie 3x API Gateway(per EC2) + Load balancer. W load balancerze definiujemy rules typu jak w path jest "orders/111" to przekieruj na API Gateway Alpha etc.. Orderów nie ma dużo więc takich zasad dużo również by nie było. Wada taka, że jak w systemie pojawi się order to trzeba dodać do load balancera nowy rules, a to jest kolejny kod, który trzeba napisac i utrzymywać.

Jakieś inne pomysły?

#programista15k #programista25k #programowanie #it #pracait
  • 20
  • Odpowiedz
Problem polega na tym, że za order 111 odpowiada EC2 Alpha, za order 222 odpowiada EC2 Beta, a za order 333 odpowiada Gamma.


@Gofer33: ale czemu chcesz tak to robic?
  • Odpowiedz
  • 0
@afuera: Taka jest architektura systemu i to jest niezmienialne. Cały system stoi na takim założeniu. Podałem w przykładach, że chodzi o ordery, tak na prawde to są inne encje, dużo bardziej skomplikowane i to ma swój sens, ale nie chciałem komplikować dlatego przedstawiłem to na przykładzie orderów.
  • Odpowiedz
@Gofer33: Są różne opcje, ale dobrze kombinujesz.

1) Użyć Kong/Openresty jak gatewaya - coś w stylu https://openresty.org/en/dynamic-routing-based-on-redis.html / https://konghq.com/blog/engineering/how-to-dynamically-route-requests-with-kong-enterprise
2) (imo najlepsza opcja) Zacząć generować IDki zamówień tak żeby Alpha zawsze generowała id zaczynające się od 1, beta od 2 itd. Wtedy bardzo łatwo skonfigurujesz sobie API Gatewaya żeby matchował "/1*", "/2*" itd.
3) Napisać osobny serwis który zwróci lokalizację danego zamówienia i proxy uderzy po nie. Nginx ma taki feature
  • Odpowiedz
  • 0
@PanJanuszTrzeci: Dzięki za podpowiedzi! 2 niestety odpada, właściwie kiedyś tak było, że w identyfikarze zamówienia w pierwszym znaku zaszyta była informacja o maszynie EC2, tzn dokładnie alpha się zaczynała od 1 itd. Niestety okazało się to mega problematyczne, bo czasami migrujemy encje między serverami tzn przerzucamy z alphy do bety i się okazywało, że zmiana identyfikatora kluczowej encji dla systemu to katastrofa.
  • Odpowiedz
@Gofer33 ja bym tymczasowo poszedł w opcje nr 1 a w międzyczasie bym przepisał ec2 na lambdy. Jak Lambdy zostaną napisane zgodnie ze sztuką to nie będzie wolno. Będzie bardziej elastycznie, a czy drożej to trzeba policzyć bo wcale niekoniecznie. Macie monitoring ile requestow wpada aktualnie więc easy. Ja zawsze jak działam w trybie request->response to idę w lambdy i serverless. Ec2 to dobre do obliczeń są czy trzymania websocketow a nie
  • Odpowiedz
Mirki, potrzeba architekta, który zna się na chmurach

Taka jest architektura systemu i to jest niezmienialne.


@Gofer33: To na #!$%@? wam architekt skoro wiecie lepiej?
  • Odpowiedz
@Gofer33: napisałbym serwer, który działa jako proxy. Jako, że proxy wymaga bazy (którą fajnie byłoby cachować w serwisie i/lub in-mem cache) to raczej gotowiec odpada.

Lambda tu raczej się nie sprawdzi, bo chcesz trzymać połączenia pomiędzy proxy a serwisem dla minimalizowania opóżnień.

Co do technologii to pewnie wybrałbym Rust (lepiej), Go (gorzej) lub cokolwiek w miarę wydajnego. Jak to będzie prosta przelotka, która przepisuje headery i streamuje message to narzut CPU/Mem
  • Odpowiedz
@Gofer33: Wow. Kto wam coś takiego wymyślił? Aż się za głowę złapałem. Przecież to aż się prosi o awarię, do tego gdzie HA?

Jak już chcesz robić na ec2 to powinieneś mieć jedną do której się łączy i ona pobiera sobie dane z konkretnej maszyny.
  • Odpowiedz
@Gofer33: ta architektura jest strasznie głupia, właściwie to eliminacje większość korzyści chmury.

1) Użyć Kong/Openresty jak gatewaya - coś w stylu

@PanJanuszTrzeci:
słabo się znam na AWS, ale po co takie customowe rozwiązania na AWS stosować? to chyba sensowniej API gateway + lambda + redis.
  • Odpowiedz
@Gofer33
Serwer proxy który pyta bazę i wie do jakiego serwera uderzyć. Jeśli dane są duże to zamiast przekazywać dane zwraca redirect 3xx na odpowiedni serwer docelowy. Większość klientów http automatycznie to obsługuje ale robi drugi request. Jeśli dane są małe to nie opłaca się nawiązywać osobnego połączenia przez klienta.

Sam kiedyś miałem podobną architekturę ale dynamiczną i nie po http. Mieliśmy Master serwer który non stop monitorwał wszystkie inne serwery(był do
  • Odpowiedz
@Gofer33: Wystawcie proxy które odpyta wszystkie 3 API jednocześnie i zwróci te dane, gdzie odpowiedź zakończyła się sukcesem ( ͡° ͜ʖ ͡°) rozwiązanie będzie na poziomie obecnej architektury
  • Odpowiedz
@BreathDeath

też się za łeb złapałem, ależ #!$%@?

tam coś nielogicznego na bank jest robione, jeszcze z tą bazą danych, która trzyma order id - id maszynki xD

ciekawe, jak skalowanie by ogarnęli, pompując maszynki w kosmos wertykalnie?

aha, jeszcze widzę tu gagatków, którzy mówią, że "po #!$%@? coś customowego na EC2, używaj lambdów!" "zrób X, czy drożej, to się później policzy" - widać, kto zajmuje się kosztami chmury w firmie, a
  • Odpowiedz
lol, byle jakie L7 Proxy z header routingiem


@ksos: tylko jak powiesz proxy jaki order ma iść do jakiego serwera. Gdzieś musisz mieć kod, który wyciąga informację z bazy i coś z nią robi. Może to być proxy, może to być konfiguracja load balancera, ale coś to musi być
  • Odpowiedz
Większość klientów http automatycznie to obsługuje ale robi drugi request. Jeśli dane są małe to nie opłaca się nawiązywać osobnego połączenia przez klienta.


@zibizz1: to byłoby najprostrze, ale trochę słabe z punktu widzenia UX jak i wydajności. Raz, że klient może nie obsługiwać redirectów (jak np. curl bez odpowiedniej flagi). Dwa, że to dodatkowe blokujące zapytanie na które trzeba poczekać
  • Odpowiedz
@Gofer33: ktoś wyżej dobrze napisał, mapowanie między orderem a maszyną powinno być trzymane w jakimś cache'u, bo sięganie do relacyjnej bazy co request to operacja wolniejsza o rząd wielkości.

jeśli cache "mapujący" odpada, ale dane końcowe nie zmieniają się zbyt często, to można ew. pomyśleć o cachowaniu ostatecznego wyniku poprzez CDN z jakimś sensownym max-age.

ogólnie ciężko powiedzieć co będzie najlepsze, takimi decyzjami powinny sterować metryki i priorytety architektoniczne. dużo zależy
kernelpan1c - @Gofer33: ktoś wyżej dobrze napisał, mapowanie między orderem a maszyną...

źródło: bob-budowniczy-kto-panu-tak-spierdolil

Pobierz
  • Odpowiedz