Czy właściwie ustawiamy się w kolejce i serializujemy?

13

Przetwarzamy wiadomości za pośrednictwem różnych usług (jedna wiadomość dotyka prawdopodobnie 9 usług przed ich wykonaniem, każda pełni określoną funkcję związaną z We / Wy). W tej chwili mamy kombinację najgorszego przypadku (serializacja kontraktu danych XML) i najlepszego przypadku (MSMQ w pamięci) pod względem wydajności.

Charakter wiadomości oznacza, że ​​nasze serializowane dane kończą się około 12-15 kilobajtami, a my przetwarzamy około 4 milionów wiadomości tygodniowo. Trwałe wiadomości w MSMQ były dla nas zbyt wolne, a gdy dane rosną, odczuwamy presję ze strony plików mapowanych w pamięci MSMQ. Serwer korzysta z 16 GB pamięci i rośnie, tylko do kolejkowania. Wydajność spada również, gdy użycie pamięci jest wysokie, ponieważ urządzenie zaczyna wymieniać. Już przeprowadzamy samoczyszczące działanie MSMQ.

Czuję, że jest coś, co robimy źle. Próbowałem użyć RavenDB do utrwalenia wiadomości i umieszczenia w kolejce identyfikatora, ale wydajność była bardzo niska (najlepiej 1000 wiadomości na minutę). Nie jestem pewien, czy to wynik użycia wersji programistycznej, czy co, ale zdecydowanie potrzebujemy wyższej przepustowości [1]. Koncepcja działała bardzo dobrze w teorii, ale wydajność nie była wystarczająca.

Wzorzec użycia ma jedną usługę działającą jak router, która wykonuje wszystkie odczyty. Inne usługi dołączą informacje na podstawie haka innej firmy i przekażą je z powrotem do routera. Większość obiektów jest dotykana 9-12 razy, chociaż około 10% jest zmuszonych do zapętlania się w tym systemie przez jakiś czas, aż strony trzecie zareagują odpowiednio. Usługi właśnie to uwzględniają i mają odpowiednie zachowanie podczas snu, ponieważ z tego powodu wykorzystujemy pole priorytetu wiadomości.

Tak więc, moje pytanie, jaki jest idealny stos do przekazywania wiadomości między maszynami z dyskretną obsługą sieci LAN w środowisku C # / Windows? Normalnie zaczynałbym od BinaryFormatter zamiast serializacji XML, ale to wielka dziura, jeśli lepszym sposobem jest przeniesienie serializacji do magazynu dokumentów. Stąd moje pytanie.

[1]: Charakter naszej firmy oznacza, że ​​im szybciej przetwarzamy wiadomości, tym więcej zarabiamy. Udowodniliśmy empirycznie, że przetwarzanie wiadomości w późniejszym tygodniu oznacza mniejsze prawdopodobieństwo zarobienia tych pieniędzy. Chociaż wydajność „1000 na minutę” brzmi dość szybko, naprawdę potrzebujemy tej liczby w górę o 10 000 na minutę. To, że podam numery w wiadomościach na tydzień, nie oznacza, że ​​mamy cały tydzień na ich przetworzenie.

=============== edycja:

Dodatkowe informacje

W oparciu o komentarze dodam trochę wyjaśnień:

  • Nie jestem pewien, czy serializacja jest naszym wąskim gardłem. Przeanalizowałem aplikację i chociaż serializacja nie pojawia się na wykresie cieplnym, odpowiada ona jedynie za 2,5-3% wykorzystania procesora przez usługę.

  • Najbardziej martwię się o trwałość naszych wiadomości i potencjalne niewłaściwe użycie MSMQ. Używamy nietransakcyjnych, nietrwałych wiadomości, abyśmy mogli zwiększyć wydajność kolejkowania, i naprawdę chciałbym mieć przynajmniej trwałe wiadomości, aby przetrwały restart.

  • Dodanie większej ilości pamięci RAM jest krokiem naprzód. Maszyna ma już 4 GB -> 16 GB pamięci RAM i coraz trudniej jest ją zdjąć, aby kontynuować dodawanie kolejnych.

  • Ze względu na wzór trasy gwiazdy w aplikacji, połowę czasu, kiedy obiekt jest otwierany, a następnie wypychany do kolejki, nie zmienia się wcale. Pozwala to ponownie (IMO) na przechowywanie go w jakimś sklepie z kluczowymi wartościami i przekazywanie identyfikatorów wiadomości.

  • Wzór trasy gwiazdy jest integralną częścią aplikacji i nie ulega zmianie. Nie możemy go stonizować, ponieważ każdy element po drodze działa asynchronicznie (w trybie odpytywania) i chcemy scentralizować zachowanie ponownych prób w jednym miejscu.

  • Logika aplikacji jest napisana w języku C #, obiekty są niezmiennymi POCO, docelowym środowiskiem wdrażania jest system Windows Server 2012, a my możemy stanąć na dodatkowych maszynach, jeśli dane oprogramowanie jest obsługiwane tylko w systemie Linux.

  • Moim celem jest utrzymanie bieżącej przepustowości przy jednoczesnym zmniejszeniu zużycia pamięci i zwiększeniu odporności na uszkodzenia przy minimalnym nakładzie kapitału.

Bryan Boettcher
źródło
Komentarze zostały oczyszczone, gdy odpowiednie pytania zostały włączone do pytania.
ChrisF
Sensowne byłoby rozwiązanie najpilniejszego problemu przed zmartwieniem o zamianie podsystemów kolejkowania (choć w końcu może to nadal być warte). Fakt, że pamięć wymyka się spod kontroli, sugeruje, że gdzieś wciąż są wycieki. Jakie (jeśli w ogóle) profilowanie pamięci zostało wykonane?
Dan Lyons,
@DanLyons: jedynym wzrostem pamięci jest MSMQ. Nikt tak naprawdę o tym nie mówi, ale wydaje się, że dzieje się tak z powodu nietrwałych komunikatów, które wszystkie są zmapowane w pamięci. Ponieważ serializujemy wiele danych, zachowuje znaczną ilość przydzielonej pamięci. Pamięć jest (ostatecznie) odzyskiwana, gdy wiadomości są konsumowane, a wewnętrzne czyszczenie MSMQ działa.
Bryan Boettcher

Odpowiedzi:

1

Oto niektóre testy porównawcze kolejek, które mogą Cię zainteresować. MSMQ powinien być w stanie obsłużyć 10 000 komunikatów na sekundę. Może to być problem z konfiguracją, a może klienci nie nadążają z czytaniem kolejki? Zauważ też, jak niesamowicie szybki jest ZeroMQ w tych testach porównawczych (około 100 000 wiadomości na sekundę), nie oferuje opcji trwałości, ale powinien doprowadzić cię tam, gdzie chcesz pod względem wydajności.

kamieniste
źródło
4

Kilka lat temu mieliśmy nieco podobną sytuację z kolejkowym systemem wiadomości (w naszym przypadku odciski palców audio). Mocno doceniliśmy trwałość kolejkowanych pakietów danych, ale odkryliśmy, że kolejkowanie wszystkiego na dysk i zużywanie kolejki z dysku było bardzo kosztowne.

Jeśli przełączyliśmy się na kolejki oparte na pamięci, wydajność była wyjątkowa, ale mieliśmy poważny problem. Od czasu do czasu konsumenci kolejek stali się niedostępni przez dłuższy czas (elementy konsumenta i producenta w naszym przypadku są połączone przez WAN), więc kolejka producenta rosła do tego stopnia, że ​​stała się niemożliwa do zarządzania i podobna do twojej, gdy zużycie pamięci było bardzo wysokie, nadmierne psucie pamięci podczas wymiany doprowadziło system do pełnego przeszukiwania.

Zaprojektowaliśmy kolejkę, którą ochrzciliśmy VMQueue (dla Virtual Memory Queue, bardzo zła nazwa z perspektywy czasu). Ideą tej kolejki jest to, że jeśli proces konsumencki działa na równi, innymi słowy, przetwarza wystarczająco szybko, aby móc utrzymać liczbę kolejkowanych elementów poniżej pewnego poziomu, wówczas ma zasadniczo taką samą wydajność pamięci kolejka oparta. Jednak gdy konsument zwolni lub stanie się niedostępny, a kolejka producenta osiągnie określony rozmiar, kolejka rozpocznie automatycznie stronicowanie elementów na dysk iz powrotem (przy użyciuBinaryFormatterprzy okazji serializacja). Proces ten zapewnia całkowitą kontrolę wykorzystania pamięci, a proces stronicowania jest szybki lub co najmniej znacznie szybszy niż zamiana pamięci wirtualnej występująca podczas dużego obciążenia pamięci. Gdy konsumentowi uda się opróżnić kolejkę poniżej progu, wznawia działanie jako kolejka oparta wyłącznie na pamięci

Jeśli system ulegnie awarii lub uruchomi się ponownie, kolejka będzie w stanie odzyskać wszystkie elementy stronicowane, które były zapisane na dysku, utracą tylko elementy, które były jeszcze przechowywane w pamięci przed awarią. Jeśli możesz sobie pozwolić na utratę ograniczonej liczby pakietów podczas awarii lub ponownego uruchomienia, kolejka ta może być pomocna.

Jeśli jesteś zainteresowany, mogę udostępnić VMQueuekod źródłowy klasy, abyś mógł się nim bawić. Kolejka zaakceptuje każdą klasę oznaczoną jako Serializable. Po utworzeniu kolejki ustalasz rozmiar strony w liczbie elementów. Interfejs klasy jest praktycznie taki sam jak standardowa klasa kolejki. Kod jest jednak bardzo stary (.net 1.1), więc niestety nie istnieje ogólny interfejs.

Wiem, że przejście od sprawdzonej technologii MSMQ to ogromny wybór, jednak ta kolejka działa niezawodnie od prawie 6 lat i pozwoliła nam przetrwać i odzyskać siły po scenariuszach, w których maszyna producenta była offline przez kilka tygodni! Proszę dać mi znać, jeśli jesteś zainteresowany. :)

sgorozco
źródło
1

System HP ProLiant ML350G5 pobiera 82 tys. Transakcji na minutę - tzn. Ma ponad 8-krotność wspomnianej przez ciebie przepustowości „10 tys / min”.

Wydajność: 82 774 tpmC

Ponadto, szczerze mówiąc, właśnie wybrałbym 64 lub nawet 128 GB pamięci RAM - RAM jest tani. Greenspun zwraca uwagę na różnicę między „rzucaniem RAM na to” a „zdobyciem inteligentnego faceta z wykształceniem MIT w celu optymalizacji”, a RAM wygrywa.

Skończył z maszyną SQL Server wyposażoną w 64 GB pamięci RAM i garść front-endowych maszyn obsługujących strony ASP.NET ... Witryna swaptree.com obsługuje obecnie ponad 400 000 użytkowników (szybko rośnie) bez trudności...

Uwaga: „maszyna osiągnęła już 16 GB pamięci RAM” jest daleka od wystarczającej, w artykule wskazującym na serwer, który obsługiwał 400 000 użytkowników na 64 GB pamięci RAM.

Marcel Popescu
źródło