2013-01-03 12 views
11

Jakie jest najlepsze rozwiązanie technologiczne (framework/approach), aby kolejka żądań przed usługą REST. , dzięki czemu można zwiększyć liczbę wystąpień usługi REST w celu zwiększenia dostępności i umieszczając kolejkę żądania z przodu, aby utworzyć granicę usługi/transakcji dla klienta usługi.Kolejka żądań przed usługą REST

  1. muszę dobry i lekki Technologie/wybór ramową kolejki żądań (Java)
  2. podejścia do wdrażania konkurencyjnych konsumenta z nim.
+3

Czy można użyć systemu równoważenia obciążenia? – Henry

+0

Co znalazłeś do tej pory? – miku

+2

@Henry może być tym, czego chce, to utrzymywanie kolejki zgłoszeń połączonych. Nawet jeśli wszystkie serwery są zajęte, żadne żądania nie powinny zostać odrzucone, powinny być w puli, czekając na swoją kolej. – Subin

Odpowiedz

7

Istnieje kilka problemów, w zależności od celów.

Po pierwsze, promuje tylko dostępność zasobów na zapleczu. Zastanów się, czy masz 5 serwerów obsługujących żądania kolejek na zapleczu. Jeśli jeden z tych serwerów ulegnie awarii, oczekujące żądanie powinno wrócić do kolejki i zostać ponownie dostarczone do jednego z pozostałych 4 serwerów.

Podczas gdy te serwery zaplecza są przetwarzane, serwery frontonu trzymają się faktycznych, inicjujących żądań. Jeśli jeden z tych serwerów frontowych zakończy się niepowodzeniem, połączenia te zostaną całkowicie utracone, a pierwotny klient będzie musiał ponownie przesłać żądanie.

Założeniem może być to, że prostsze systemy front end są mniej narażone na awarie, a to z pewnością odnosi się do awarii oprogramowania. Ale karty sieciowe, zasilacze, dyski twarde itp. Są dość agnostyczne wobec takich fałszywych nadziei dla człowieka i karą wszystkich jednakowo. Rozważ to, mówiąc o ogólnej dostępności.

W zakresie projektowania, back-end jest prostym procesem czekającym na kolejkę komunikatów JMS i przetwarzającym każdy komunikat w momencie jego pojawienia się. Istnieje wiele przykładów tego, a każdy serwer JMS będzie odpowiadał na wysokim poziomie. Wszystko, czego potrzebujesz, to zapewnienie, że obsługa komunikatów jest transakcyjna, tak więc jeśli przetwarzanie komunikatu nie powiedzie się, wiadomość pozostaje w kolejce i może zostać ponownie dostarczona do innej procedury obsługi wiadomości.

Głównym wymogiem kolejki JMS jest możliwość utworzenia klastra. Sam serwer JMS jest pojedynczym punktem awarii w systemie. Zgubiłem serwer JMS, a twój system jest prawie martwy w wodzie, więc musisz mieć możliwość połączenia serwera z serwerem i umożliwienia konsumentom i producentom odpowiedniego przełączenia awaryjnego. Ponownie, jest to specyficzny serwer JMS, większość robi to, ale jest dość rutyna w świecie JMS.

Na samym początku sprawy stają się nieco trudniejsze, ponieważ serwery frontowe są mostem od synchronicznego świata żądania REST do asynchronicznego świata procesorów back-end. Żądanie REST jest zgodne z typowym schematem RPC zużywającym ładunek żądania z gniazda, utrzymującym połączenie otwartym, przetwarzającym wyniki i dostarczającym wyniki z powrotem do początkowego gniazda.

Aby zamanifestować to rozdanie, należy spojrzeć na asynchroniczny serwlet obsługujący wprowadzony serwlet 3.0 i jest dostępny w Tomcat 7, najnowszym Jetty (nie jestem pewien, która wersja), Glassfish 3.x i inne.

W tym przypadku, co należy zrobić, gdy przychodzi żądanie, konwertuj nominalnie synchroniczne wywołanie serwletu do wywołania asynchronicznego za pomocą HttpServletRequest.startAsync(HttpServletRequest request, HttpServletResponse response).

Zwraca AsynchronousContext, a po uruchomieniu pozwala serwerowi zwolnić wątek przetwarzania. Następnie robisz kilka rzeczy.

  1. Wyodrębnij parametry z żądania.
  2. Utwórz unikalny identyfikator dla żądania.
  3. Utwórz nowy ładunek zlecenia z powrotem ze swoich parametrów.
  4. Powiąż identyfikator z AsyncContext i zachowaj kontekst (np. Umieszczając go na mapie aplikacji).
  5. Prześlij żądanie z powrotem do kolejki JMS.

W tym momencie początkowe przetwarzanie jest wykonywane, a użytkownik po prostu wraca z programu doGet (lub usługi lub cokolwiek innego). Ponieważ nie wywołałeś AsyncContext.complete(), serwer nie zamknie połączenia z serwerem. Ponieważ masz magazyn AsyncContext na mapie według identyfikatora, jest on na razie przydatny do bezpiecznego przechowywania.

Teraz, po przesłaniu wniosku do kolejki JMS, zawiera on: identyfikator żądania (który został wygenerowany), wszelkie parametry dotyczące żądania oraz identyfikację faktycznego serwera, który wysłał żądanie. Ten ostatni fragment jest ważny, ponieważ wyniki przetwarzania muszą powrócić do swojego źródła. Początek jest identyfikowany przez identyfikator żądania i identyfikator serwera.

Po uruchomieniu serwera frontowego uruchomiono także wątek, którego zadaniem jest odsłuchanie kolejki odpowiedzi JMS. Po skonfigurowaniu połączenia JMS może ustawić filtr taki jak "Daj mi tylko wiadomości dla ID serwera ABC123". Można też utworzyć unikalną kolejkę dla każdego serwera frontonu, a serwer zaplecza użyje identyfikatora serwera do określenia kolejki, na którą ma zwrócić odpowiedź.

Gdy procesory zaplecza pobierają komunikat, pobierają identyfikator żądania i parametry, wykonują pracę, a następnie pobierają wynik i umieszczają je w kolejce odpowiedzi JMS. Gdy wynik zostanie zwrócony, doda oryginalny identyfikator serwera i oryginalny identyfikator żądania jako właściwości wiadomości.

Tak więc, jeśli pierwotnie otrzymano żądanie dla serwera Front End Server ABC123, procesor zaplecza będzie zwracał wyniki do tego serwera. Następnie wątek tego odbiorcy zostanie powiadomiony, gdy pojawi się komunikat. Zadanie wątków odbiornika polega na pobraniu tego komunikatu i umieszczeniu go w wewnętrznej kolejce na serwerze frontonu.

Ta wewnętrzna kolejka jest wspierana przez pulę wątków, której zadaniem jest przesłać żądanie z powrotem do oryginalnego połączenia. Czyni to poprzez wyodrębnienie oryginalnego ID żądania z komunikatu, przeglądając Asynchroniczny kontekst z omawianej wcześniej mapy wewnętrznej, a następnie wysyłając wyniki do HttpServletResponse powiązanego z Asynchronicznym Kontekstem. Na koniec wywołuje AsyncContext.complete() (lub podobną metodę), aby poinformować serwer, że skończyłeś i zezwolić na zwolnienie połączenia.

Do utrzymania porządku powinieneś mieć inny wątek na serwerze frontonu, którego zadaniem jest wykrywanie, kiedy żądania oczekują na mapie zbyt długo. Częścią oryginalnej wiadomości powinien być czas rozpoczęcia żądania. Wątek ten może się obudzić co sekundę, przeskanować mapę pod kątem żądań, a za każdą, która była tam zbyt długo (np. 30 sekund), może skierować żądanie do kolejnej wewnętrznej kolejki, zużywanej przez kolekcję programów obsługi mających na celu informowanie klient, którego czas upłynął.

Chcesz te wewnętrzne kolejki, aby główna logika przetwarzania nie utknęła, czekając na klienta, aby zużyć dane. Może to być powolne połączenie lub coś takiego, więc nie chcesz blokować wszystkich innych oczekujących żądań, aby poradzić sobie z nimi jeden po drugim.

Na koniec musisz wziąć pod uwagę, że możesz otrzymać komunikat z kolejki odpowiedzi dla żądania, które nie istnieje już na twojej wewnętrznej mapie. Po pierwsze, żądanie mogło przekroczyć limit czasu, więc nie powinno już tam być. Po drugie, ten serwer frontonu mógł zostać zatrzymany i zrestartowany, więc wewnętrzna mapa oczekującego żądania będzie po prostu pusta. W tym momencie, jeśli wykryjesz, że masz odpowiedź na żądanie, które już nie istnieje, powinieneś po prostu go odrzucić (dobrze, zaloguj się, a następnie odrzuć).

Nie można ponownie użyć tych żądań, nie ma czegoś takiego, jak system równoważenia obciążenia wracający do klienta. Jeśli klient zezwala na wykonywanie wywołań zwrotnych za pośrednictwem opublikowanych punktów końcowych, to z pewnością można po prostu zamówić inną procedurę obsługi wiadomości JMS. Ale to nie jest coś typu REST, REST na tym poziomie dyskusji jest bardziej klient/serwer/RPC.

Co do obsługi ramek Asynchroniczne serwlety na wyższym poziomie niż surowe serwlety (takie jak Jersey dla JAX-RS lub coś podobnego), nie mogę powiedzieć. Nie wiem, jakie ramy wspierają go na tym poziomie. Wydaje się, że jest to cecha Jersey 2.0, która nie jest jeszcze dostępna. Mogą być i inni, musicie się rozejrzeć. Nie naprawiaj także w Servlet 3.0. Servlet 3.0 to po prostu standaryzacja technik stosowanych w poszczególnych pojemnikach przez pewien czas (w szczególności Jetty), więc warto przyjrzeć się opcjom specyficznym dla kontenera poza serwletem 3.0.

Ale koncepcje są takie same. Duży wybór na wynos to odbiornik kolejki odpowiedzi z odfiltrowanym połączeniem JMS, wewnętrzna mapa żądań do AsyncContext oraz wewnętrzne kolejki i pule wątków do rzeczywistej pracy w aplikacji.

+0

co jeśli muszę uruchomić 5 mikro-usług (wbudowany kontener/molo), które są podłączone do kolejki tak, że konkurują między sobą (dla lepszej przepustowości) i moja biblioteka klienta jest odpowiedzialna tylko do kolejki (żądanie/odpowiedź). – TheWhiteRabbit

+0

W skrócie Interakcja asynchroniczna musi być ukryta przy użyciu biblioteki klienta, którą wysyłam z każdą usługą, szukając wyboru technologii dla tej biblioteki klienta, która pośredniczy w żądaniu/odpowiedzi HTTP od klienta usługi. – TheWhiteRabbit

+0

Nie rozumiem. Klient wykonujący wywołanie REST nie będzie asynchronizowany, REST nie jest systemem opartym na asynchronizacji. –

2

Jeśli rozluźnisz swoje wymaganie, że musi być w Javie, możesz rozważyć HAProxy. Jest bardzo lekki, bardzo standardowy i ma wiele dobrych rzeczy (żądanie łączenia/keepalives/queuing).

Zastanów się dwa razy zanim zaimplementujesz kolejkowanie żądań. O ile ruch nie jest bardzo bolesny, nie spowoduje to uszkodzenia wydajności systemu.

Załóżmy, że Twój system obsługuje 100 żądań na sekundę. Twój serwer HTTP ma ograniczoną pulę wątków roboczych. Jedynym sposobem, w jaki pula żądań może pomóc, jest to, że otrzymujesz więcej niż 100 żądań na sekundę. Po zapełnieniu puli wątków roboczych żądania zaczynają gromadzić się w puli systemów równoważenia obciążenia. Ponieważ przybywają szybciej, niż możesz sobie z nimi poradzić, kolejka staje się większa ... i większa ... i większa. W końcu albo ta pula się zapełni, albo skończy się pamięć RAM, a moduł równoważenia obciążenia (a więc i cały system) mocno się zawiesi.

Jeśli serwer sieciowy jest zbyt zajęty, zacznij odrzucać żądania i uzyskać dodatkową pojemność w trybie online.

Żądanie grupowania z pewnością może pomóc, jeśli możesz uzyskać dodatkową pojemność w czasie, aby obsłużyć żądania. Może również bardzo źle cię zranić. Przeanalizuj konsekwencje przed włączeniem dodatkowej puli żądań przed pulą wątków roboczych serwera HTTP.

0

Konstrukcja używamy jest interfejs REST otrzymania wszystkich prośbę i wysyłając je do wiadomości w kolejce (czyli RabbitMQ)

Następnie pracownicy słuchać komunikatów i realizują je po pewnych zasad. Jeśli wszystko pójdzie w dół, nadal będziesz mieć taką prośbę w MQ i jeśli masz dużą liczbę zgłoszeń, możesz po prostu dodać pracowników ...

Sprawdź to hasło, to pokazuje siłę tego pojęcia!

http://www.springsource.org/SpringOne2GX2012

+0

, ale w jaki sposób dopasował się model zapytania/odpowiedzi? czy pasuje do modelu synchronicznego req/resp (z punktu widzenia klienta)? lub klient musi sondować wait/listenens (dla zdarzenia) dla odpowiedzi? – TheWhiteRabbit

+1

Istnieje wiele opcji w REST dla tego. Oznacza to, że jeśli zadzwonię do usługi, a żądanie nie zostanie przetworzone, serwer zwróci: 202 Zaakceptowane. Oznacza to, że "Wniosek został zaakceptowany do przetwarzania, ale przetwarzanie nie zostało zakończone." – moskiteau

Powiązane problemy