5

Potrzebuję nawiązać dwukierunkową komunikację między wydawcą a subskrybentem. Ma to ułatwić frontendową aplikację MVC3 definiującą subskrypcję z filtrem korelacji, a następnie umieszczając wiadomość w temacie. Wreszcie kontroler MVC3 wywołuje BeginReceive() na SubscriptionClient i czeka na odpowiedź.Magistrala usług Azure - dwukierunkowe wyzwanie dotyczące wydajności komunikacji

Wydaje się, że problem polega na utworzeniu i usunięciu tych obiektów subskrypcji. Narzut jest ogromny i spowalnia działanie aplikacji. Nie wspominając o różnych ograniczeniach do obejścia, takich jak nie więcej niż 2000 subskrypcji w temacie.

Jaka jest najlepsza praktyka dla ustanowienia tego rodzaju dwukierunkowej komunikacji między Wydawcą a subskrybentem? Chcemy, aby aplikacja MVC3 opublikowała komunikat, a następnie czekała na odpowiedź na ten dokładny komunikat (za pośrednictwem właściwości CorrelationId i CorrelationFilter). Pamięć podręczna NamespaceManager i MessagingFactory jest już buforowana, ponieważ są one również zbyt drogie, pod względem zasobów, a także dlatego, że zostaliśmy poinformowani, że usługa Service Bus używa jawnego modelu udostępniania, w którym oczekuje się, że przed rozpoczęciem tworzenia większości tych rzeczy będzie uruchamiany podczas uruchamiania roli.

To stawia nas przed wyzwaniem polegającym na korelacji żądania i odpowiedzi, a także na olbrzymim obciążeniu związanym z tworzeniem i usuwaniem subskrypcji. Czy istnieje lepsza praktyka? Czy powinniśmy przechowywać pamięć podręczną subskrybentów SubscriptionClients i zamieniać filtr za każdym razem? Co robią inni? Potrzebuję przepustowości żądań od 5 do 10 tysięcy żądań MVC3 na sekundę w klastrze ról internetowych. Już używamy AsyncController i stosujemy asynchroniczny BeginReceive() na SubscriptionClient. Wydaje się, że jest to tworzenie i usuwanie Subskrypcji przez tysiące osób, które dławią system w tym momencie.

UPDATE1: oparciu o wielkiej zaleceń podanych tutaj, zaktualizowaliśmy to rozwiązanie, aby utrzymać pamięci podręcznej obiektów SubscriptionClient na każdej instancji roli internetowej. Ponadto przeszliśmy na podejście zorientowane na sesję MessageSession.

Jednak nadal nie jest to skalowanie. Wydaje się, że AcceptMessageSession() jest bardzo kosztowną operacją. Czy obiekty MessageSession powinny być również buforowane i ponownie używane? Czy każdy otwarty obiekt MessageSession zużywa połączenie z magistralą usług? Jeśli tak, czy jest to wliczane do kwoty równoczesnego połączenia subskrypcji?

Wielkie dzięki. Myślę, że się tam dostaliśmy. Większość przykładowego kodu w sieci pokazuje: Utwórz temat(), następnie CreateSubscription(), następnie CreateSubscriptionClient(), następnie BeginReceive() na kliencie, a następnie odrzuć wszystkie obiekty. Mogę tylko powiedzieć, że gdybyś zrobił to w prawdziwym życiu, twój serwer zostałby zmiażdżony, a ty miałbyś max na połączenia w krótkim czasie.

Musimy przez to przesłać tysiące żądań na sekundę i jest oczywiste, że obiekty te muszą być buforowane i ponownie wykorzystywane w dużym stopniu. Czy MessageSession jest kolejnym elementem do buforowania? Będzie miło się z tym bawić, ponieważ będziemy musieli wdrożyć mechanizm liczenia odwołań, w którym można podać tylko jedno odwołanie do MessageSession na raz, ponieważ dotyczy to żądania/odpowiedzi specyficznej dla żądania HTTP, a my nie możemy mieć innego subskrybenci korzystający jednocześnie z obiektów MessageSession.

Update2: OK, to nie jest możliwe, aby cache MessageSession do ponownego użycia, gdyż tylko żyć tak długo, jak LockDuration od abonamentu. To jest bummer, ponieważ maksymalna LockDuration to 5 minut. Wygląda na to, że mają krótki czas publikacji pub/sub, a nie długotrwałe procesy rozproszone. Wygląda na to, że musimy powrócić do odpytywania tabel Azure.

STRESZCZENIE/KOMENTARZ Staraliśmy się budować na magistrali usług ze względu na skalę potencjalnych i jego trwałość i dostawczych semantyki. Wydaje się jednak, że są wśród nich sytuacje, które nie są do nich dostosowane. Część wydawnicza działa świetnie, a rywalizacja z klientami na zapleczu jest świetna, ale posiadanie frontowego żądania czeka na określoną, pojedynczą odpowiedź konsumenta, w ogóle nie skaluje się, ponieważ MessageSessions trwa zbyt długo, aby Utwórz za pomocą AcceptMessageSession() lub BeginAcceptMessageSession() i ponieważ nie są one odpowiednie do buforowania.

Jeśli ktoś ma alternatywny widok, bardzo chciałbym go usłyszeć.

+1

Brzmi jak coś, z czym ZeroMQ jest dobre. http://www.zeromq.org/ –

+0

Dzięki za link. To wygląda bardzo interesująco. –

+0

OK, to bardzo stare pytanie, ale widzę, że obecnie istnieje metoda 'RenewLock' na sesjach, więc może teraz są one buforowalne. –

Odpowiedz

4

Ten scenariusz jest klasycznym żądaniem/odpowiedzią i dobrym kandydatem do używania sesji. To kolejny mechanizm korelacji. Utwórz prostą kolejkę żądań i kolejkę odpowiedzi. Każdy wątek roli WWW tworzy unikatowy identyfikator sesji dla żądania i umieszcza tę wartość we właściwości "ReplyToSessionID" komunikatu brokered. Również ten wątek wywołuje AcceptMessageSession w kolejce odpowiedzi z wartością sessionid, więc blokuje ją. Wywołana wiadomość jest wysyłana do kolejki żądań, a wszystkie role pracowników rywalizują o wiadomości. Gdy rola pracująca otrzymuje żądanie, przetwarza ją, tworzy komunikat odpowiedzi i ustawia właściwość sessionid w komunikacie odpowiedzi = replytosessinid żądania. jest to następnie wysyłane do kolejki odpowiedzi i będzie dostarczane tylko do wątku, który zablokował ten identyfikator sesji. Szczegółowa próbka using sessions is here. Dostępne są 2 dodatkowe próbki z wykorzystaniem Queues i Topics w celu uzyskania korelacji odpowiedzi żądania.

+0

Dziękuję! To jest doskonałe i było to "brakujące ogniwo", którego potrzebowałem. Czy w takim przypadku nie będę już potrzebował filtrów korelacji? Wygląda na to, że mogę po prostu użyć Sesji bez względu na Korelację. –

+0

Zaimplementowałem to, najpierw w formie blokowania, za pomocą SubscriptionClient.AcceptMessageSession(). Wydajność jest niedopuszczalna, ponieważ wydaje się zużywać wątki IIS. Tak, przeniosłem się do SubscriptionClient.BeginAcceptMessageSession(). Problem polega na tym, że w mojej metodzie zwrotnej parametr IAsyncResult jest przekazywany do mojego SubscriptionClient, więc mogę wywołać EndAcceptMessageSession(). Większe wyzwanie polega na tym, że w przeciwieństwie do AcceptMessageSession(), która zwraca sesję MessageSession, MessageSession nie jest dostępna. Nie ma go w AsyncManager.Parameters, którego liczba wynosi 0 ani nigdzie indziej. –

+0

Wywołanie asynchroniczne: subClient.BeginAcceptMessageSession (sessionId, TimeSpan.FromSeconds (30), (ar) => {ProcessAcceptMessageSession (ar);}, subClient); UWAGA: Wewnątrz ProcessAcceptMessageSession (ar), nie mogę znaleźć sesji w dowolnym miejscu w zakresie, a dokumentacja jest skąpa. –

1

Dla pojedynczego nadawcy i odbiorcy potrzebujesz tylko jednego tematu/subskrypcji. Możesz ustawić kilka correlation filters w tej samej subskrypcji, dzięki czemu wszystkie odpowiedzi, które potrzebujesz, będą wyświetlane w tej samej subskrypcji. Obecnie obsługujemy do 100,000 instancji filtra korelacji w jednej subskrypcji i można je dodawać/usuwać (w razie potrzeby w transakcjach) wraz z operacjami wysyłania/odbierania wiadomości na temat/subskrypcję.

Ponadto można użyć reguł z operacjami, aby oznaczyć wiadomość dodatkowymi właściwościami w razie potrzeby w zależności od tego, który filtr jest zgodny.

+0

A co z sytuacją z 12 instancjami w roli internetowej (wydawca) i 6 instancjami w roli pracownika (subskrybent). Potrzebujemy, aby każda prośba internetowa była łatwo powiązana z jej skorelowaną odpowiedzią. Co się dzieje, gdy instancja internetowa umieszcza komunikat na magistrali usług, oznaczony za pomocą ID korelacji, który subskrybent używa do oznaczenia wiadomości odpowiedzi.W jaki sposób jeden wątek z interfejsu WWW może uzyskać skorelowaną odpowiedź? Jeśli temat przekierowuje wszystkie dopasowania do subskrypcji, czy wywołanie funkcji BeginReceive() nie będzie otrzymywać żadnego ze skorelowanych komunikatów, a nie konkretnego? –

1

Alternatywnym podejściem jest korelowanie komunikatów w instancji roli internetowej przy użyciu słownika identyfikatorów korelacji i delegatów wywołań zwrotnych.

Każda instancja roli internetowej (wydawcy) ma jedną subskrypcję, przefiltrowaną przez pojedynczy identyfikator subskrypcji, do tematu odpowiedzi.

Przed wysłaniem wiadomości zwrotne dla tej wiadomości jest rejestrowane w słowniku z identyfikatorem korelacji jako kluczem. Identyfikator korelacji i identyfikator subskrypcji są przesyłane razem z komunikatem w taki sposób, że odpowiedź może zostać wysłana z powrotem do prawidłowej subskrypcji wraz z identyfikatorem korelacji.

Każda instancja roli sieci Web monitoruje pojedynczą subskrypcję, a po otrzymaniu odpowiedzi usuwa wpis słownika i wywołuje wywołanie zwrotne.

+0

Dzięki. Czy możesz zapewnić wgląd w to, jak działałby kontroler AsyncController w MVC3? Nie mogłem używać SubscriptionClient.Receive(), ponieważ blokuje to wątek IIS, więc używam SubscriptionClient.BeginReceive(). Dostarczam funkcję oddzwaniania do BeginReceive(), która jest wywoływana, gdy asynchroniczny otrzyma otrzyma wiadomość lub przekroczy limit czasu. Nie rozumiem, w jaki sposób, kiedy otrzymam wiadomość od EndReceive(), dlaczego miałbym wykonać inne wywołanie zwrotne i jak byłby związany z pierwotnym żądaniem w IIS, ponieważ IIS po prostu chwyta każdy stary wątek do obsługi, chyba że I zadzwoń Sync(). –

+0

Jaki jest więc cel wywołania zwrotnego w słowniku? To jest związek, którego nie mogę w tym momencie zrobić w mojej głowie. –

+0

Klient subskrypcji będzie otrzymywać wiadomości we własnym wątku i po wyszukaniu identyfikatora korelacji w słowniku, wywołaj wywołanie zwrotne do oczekującego wątku IIS. W ten sposób zwalniając oczekujący wątek IIS i dostarczając mu odpowiedzi. – hocho

Powiązane problemy