Jak efektywny może być Meteor, dzieląc się ogromną kolekcją wśród wielu klientów?
Wyobraź sobie następujący przypadek:
1,000 klienci są podłączeni do strony Meteor wyświetlającej zawartość kolekcji "Somestuff".
"Somestuff" to kolekcja licząca 1000 pozycji.
-
Ktoś wstawia nowy przedmiot do kolekcji" Somestuff "
Co się stanie:
- Wszystkie
Meteor.Collection
s na klientach zostaną zaktualizowane, tzn. wstawianie przekazane do wszystkich z nich (co oznacza, że jedna wiadomość wstawiania wysłana do 1000 klienci)
Jaki jest koszt procesora dla serwera, aby określić, który klient musi zostać zaktualizowany?
Czy to prawda, że tylko wstawiona wartość zostanie przekazana do klientów, a nie cała lista?
Jak to działa w prawdziwym życiu? Czy są dostępne jakieś benchmarki lub eksperymenty o takiej skali?4 answers
Krótka odpowiedź jest taka, że tylko nowe dane są wysyłane w dół przewodu. Oto jak to działa.
Istnieją trzy ważne części serwera Meteor, które zarządzają subskrypcji: funkcja publish , która definiuje logikę tego, co dane, które dostarcza abonament; Mongo driver , który ogląda bazy danych dla zmian; oraz pole scalania , które łączy wszystkie aktywnych abonamentów klienta i wysyła je przez sieć do na klient.
Publikuj funkcje
Za każdym razem, gdy klient Meteor subskrybuje kolekcję, serwer uruchamia
funkcja publikowania . Zadaniem funkcji publish jest ustalenie zbioru
dokumentów, które klient powinien posiadać i przesłać do każdego dokumentu
do skrzynki połączeniowej. Uruchamia się raz dla każdego nowego klienta subskrybującego. Ty
może umieścić dowolny JavaScript, który chcesz w funkcji publikowania, takich jak
dowolnie skomplikowana Kontrola dostępu za pomocą this.userId
. The publish
funkcja wysyła danych do pola scalania poprzez wywołanie this.added
, this.changed
oraz
this.removed
. Zobacz też
pełna dokumentacja publikacji dla
więcej szczegółów.
Większość funkcji publikowania nie musi się wygłupiać z niskimi poziomami
added
, changed
i removed
API. Jeśli funkcja publish zwróci Mongo
kursor, Serwer Meteor automatycznie łączy wyjście Mongo
kierowca (insert
, update
, i removed
wywołania zwrotne) na wejście
merge box (this.added
, this.changed
i this.removed
). Jest całkiem zgrabna.
że możesz zrobić wszystkie Kontrola uprawnień z góry w funkcji publikowania i
następnie bezpośrednio podłącz sterownik bazy danych do pola scalania bez żadnego użytkownika
kod na drodze. A kiedy autopublish jest włączony, nawet ten mały kawałek jest
Ukryty: serwer automatycznie ustawia zapytanie dla wszystkich dokumentów w każdym
kolekcja i popycha je do pola scalania.
Z drugiej strony, nie ograniczasz się do publikowania zapytań do bazy danych.
Na przykład możesz napisać funkcję publikowania, która odczytuje pozycję GPS
z urządzenia wewnątrz Meteor.setInterval
, lub sonduje starsze REST API
z innego serwisu internetowego. W takich przypadkach emitujesz zmiany w
połącz pole wywołując low-level added
, changed
i removed
DDP API.
Kierowca Mongo
Mongo driver ' s zadaniem jest obserwowanie bazy danych Mongo pod kątem zmian w
zapytania NA ŻYWO. Zapytania te działają w sposób ciągły i zwracają aktualizacje jako
wyniki zmieniają się poprzez wywołanie added
, removed
, i changed
wywołania zwrotne.
added
, removed
, oraz changed
zdarzenia opisujące różnicę. W przypadku rejestracji wielu rozmówców
wywołania zwrotne dla tego samego zapytania NA ŻYWO, sterownik ogląda tylko jedną kopię
zapytanie, wywołanie każdego zarejestrowanego połączenia zwrotnego z tym samym wynikiem.
Za każdym razem, gdy serwer aktualizuje kolekcję, kierowca przelicza każdy live query on that collection (przyszłe wersje Meteor ujawnią skalowanie API w celu ograniczenia, które zapytania NA ŻYWO przeliczają się po aktualizacji.) The sterownik również sonduje każde zapytanie na żywo na 10 sekund, aby złapać poza-pasmowe aktualizacje bazy danych, które ominęły Serwer Meteor.
The merge box
Zadanie merge box polega na łączeniu wyników (added
, changed
oraz removed
wywołania) wszystkich aktywnych funkcji publikowania klienta w jednym dane
strumień. Dla każdego podłączonego klienta istnieje jedno pole scalania. Posiada
kompletna kopia minimongo cache klienta.
W twoim przykładzie z pojedynczą subskrypcją, pole scalania jest zasadniczo przelot. Ale bardziej złożona aplikacja może mieć wiele subskrypcje, które mogą się pokrywać. Jeśli dwie subskrypcje ustawią ten sam atrybut w tym samym dokumencie, pole scalania decyduje, która wartość ma pierwszeństwo i wysyła to tylko do klienta. Nie ujawniliśmy API dla ustawienie priorytetu subskrypcji jeszcze. Na razie priorytetem jest w zależności od zamówienia klient zapisuje się do zbiorów danych. Pierwszy abonament robi Klient ma najwyższy priorytet, drugi abonament jest następny najwyższy, i tak dalej.
Ponieważ pole merge przechowuje stan klienta, może wysłać minimum ilość danych, aby każdy klient był na bieżąco, bez względu na publikację funkcja go karmi.
Co się dzieje na aktualizacji
Więc teraz ustawiliśmy scenę dla Twojego scenariusz.
Mamy 1000 połączonych klientów. Każdy subskrybuje ten sam live Mongo query (Somestuff.find({})
). Ponieważ zapytanie jest takie samo dla każdego klienta, Sterownik jest
uruchamiam tylko jedno zapytanie na żywo. Istnieje 1000 aktywnych skrzynek scalających. Oraz
funkcja publikowania każdego klienta zarejestrowała added
, changed
, oraz
removed
na tym zapytaniu na żywo, które trafia do jednego z pól scalania.
Nic innego nie jest połączone z polami scalającymi.
Najpierw kierowca Mongo. Gdy jeden z klientów wstawia nowy dokument
w Somestuff
, uruchamia rekomputację. Mongo driver
Zapytanie o wszystkie dokumenty w Somestuff
, porównuje wynik do
poprzedni wynik w pamięci, stwierdza, że istnieje jeden nowy dokument, a
połączenia każdego z 1000 zarejestrowanych połączeń insert
.
Następnie funkcje publikowania. Niewiele się tu dzieje: każdy
z 1000 insert
wywołań wypycha dane do pola scalania przez
wywołanie added
.
Na koniec każde pole scalania sprawdza te nowe atrybuty pod kątem its
Kopia pamięci podręcznej klienta. W każdym przypadku stwierdza się, że
wartości nie są jeszcze na kliencie i nie cienią istniejącej wartości. Więc
pole merge emituje komunikat DDP DATA
na połączeniu SockJS z jego
klienta i aktualizuje jego kopię w pamięci po stronie serwera.
Całkowity koszt procesora to koszt zróżnicowania jednego zapytania Mongo, plus koszt 1000 skrzynek połączeniowych sprawdzających stan swoich klientów i konstruujących nowe Ładunek wiadomości DDP. Jedyne dane przepływające przez przewód to single Obiekt JSON wysłany do każdego z 1000 klientów, co odpowiada nowemu dokument w bazie danych, plus jeden komunikat RPC do serwera z klient, który wykonał oryginalną wkładkę.
Optymalizacje
Oto, co na pewno zaplanowaliśmy.Bardziej wydajny sterownik Mongo. My zoptymalizowano sterownik w 0.5.1 uruchamianie tylko jednego obserwatora na osobne zapytanie.
Nie każda zmiana DB powinna wywołać rekomputacja zapytania. My może wprowadzić pewne zautomatyzowane ulepszenia, ale najlepszym podejściem jest API pozwala to programiście określić, które zapytania mają być ponownie uruchamiane. Na przykład, jest oczywiste dla programisty, że wstawianie Wiadomości do jeden czat nie powinien unieważniać zapytania na żywo dla wiadomości w drugi pokój.
Sterownik Mongo, funkcja publikowania i pole scalania nie muszą być uruchamiane w tym samym procesie, a nawet na tej samej maszynie. Niektóre aplikacje run complex live zapytań i potrzeba więcej procesora do oglądania bazy danych. Inne mają tylko kilka odrębnych zapytań (wyobraź sobie silnik bloga), ale prawdopodobnie wielu podłączonych klientów-potrzebują one więcej procesora do scalania pudełka. Rozdzielenie tych elementów pozwoli nam skalować każdy kawałek niezależnie.
Wiele baz danych obsługuje wyzwalacze, które uruchamiają się, gdy wiersz jest aktualizowany i podaj stare i nowe wiersze. Dzięki tej funkcji sterownik bazy danych może zarejestrować WYZWALACZ zamiast ankiety na zmiany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 23:19:01
Z mojego doświadczenia wynika, że korzystanie z wielu klientów podczas dzielenia się ogromną kolekcją w Meteorze jest zasadniczo niewykonalne, począwszy od wersji 0.7.0.1. Postaram się wyjaśnić dlaczego.
Jak opisano w powyższym poście, a także w https://github.com/meteor/meteor/issues/1821 serwer meteor musi przechowywać kopię opublikowanych danych dla każdego klienta w polumerge . To właśnie pozwala na magię meteorów, ale także powoduje, że wszelkie duże wspólne bazy danych są wielokrotnie przechowywane w pamięci procesu węzła. Nawet przy zastosowaniu ewentualnej optymalizacji dla zbiorów statycznych, takich jak w (czy istnieje sposób, aby powiedzieć meteorowi, że zbiór jest statyczny (nigdy się nie zmieni)?), doświadczyliśmy ogromnego problemu z wykorzystaniem procesora i pamięci procesu węzła.
W naszym przypadku publikowaliśmy każdemu klientowi zbiór 15 tysięcy dokumentów, który był całkowicie statyczny. Problem polega na tym, że kopiowanie tych dokumentów do skrzynki merge klienta (w pamięci) po połączenie zasadniczo doprowadziło proces węzła do 100% CPU na prawie sekundę i spowodowało duże dodatkowe wykorzystanie pamięci. Jest to z natury nie do przecenienia, ponieważ każdy łączący się klient powali serwer na kolana (a jednoczesne połączenia będą blokować się nawzajem), a zużycie pamięci wzrośnie liniowo w liczbie klientów. W naszym przypadku każdy klient powodował dodatkowe ~60MB pamięci, mimo że przesyłane surowe dane wynosiły tylko około 5MB.
W naszym sprawa, ponieważ kolekcja była statyczna, rozwiązaliśmy ten problem wysyłając wszystkie dokumenty jako plik .json
, który został gzipowany przez nginx i ładując je do anonimowej kolekcji, co skutkowało tylko ~ 1MB transferem danych bez dodatkowego PROCESORA lub pamięci w procesie węzła i znacznie szybszym czasem ładowania. Wszystkie operacje na tej kolekcji były wykonywane przy użyciu _id
S ze znacznie mniejszych publikacji na serwerze, co pozwoliło zachować większość zalet Meteor. Pozwoliło to aplikacji na skaluj do wielu innych klientów. Ponadto, ponieważ nasza aplikacja jest głównie tylko do odczytu, dodatkowo poprawiliśmy skalowalność, uruchamiając wiele instancji Meteor za nginx z równoważeniem obciążenia (choć z jednym Mongo), ponieważ każda instancja węzła jest jednowątkowa.
Jednak problem dzielenia się dużymi, zapisywalnymi kolekcjami pomiędzy wielu klientów jest problemem inżynieryjnym, który musi zostać rozwiązany przez Meteor. Prawdopodobnie istnieje lepszy sposób niż przechowywanie kopii wszystkiego dla każdego klienta, ale wymaga to poważnego przemyślenia jako problemu systemów rozproszonych. Obecne problemy z masowym wykorzystaniem procesora i pamięci po prostu nie będą skalowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:09:34
Eksperyment, którego możesz użyć, aby odpowiedzieć na to pytanie:
- Zainstaluj test meteor:
meteor create --example todos
- uruchom go pod Webkit inspector (WKI).
- zbadaj zawartość XHR wiadomości poruszających się po przewodzie.
- zauważ, że cały zbiór nie jest przesuwany po drucie.
Aby dowiedzieć się, jak używać WKI, zapoznaj się z tym artykułem. To trochę nieaktualne, ale w większości nadal aktualne, szczególnie w przypadku tego pytania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-24 20:36:21
To jest jeszcze rok i dlatego myślę, że wiedza sprzed"Meteor 1.0", więc może coś się znowu zmieniło? Wciąż się tym zajmuję. http://meteorhacks.com/does-meteor-scale.html prowadzi do "jak skalować meteoryt?"artykuł http://meteorhacks.com/how-to-scale-meteor.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-05 00:39:37