{"id":31124,"date":"2019-10-31T21:39:36","date_gmt":"2019-10-31T18:39:36","guid":{"rendered":"https:\/\/prohoster.info\/blog\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\/"},"modified":"2019-10-31T21:39:36","modified_gmt":"2019-10-31T18:39:36","slug":"stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","title":{"rendered":"Elementy buduj\u0105ce aplikacje rozproszone. Drugie podej\u015bcie","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Og\u0142oszenie<\/strong><\/p>\n<p><\/p>\n<p><em>Kole\u017canki i koledzy, w \u015brodku lata planuj\u0119 opublikowa\u0107 kolejny cykl artyku\u0142\u00f3w na temat projektowania system\u00f3w obs\u0142ugi masowej: \u201eEksperyment VTrade\u201d \u2013 pr\u00f3ba stworzenia frameworka dla system\u00f3w handlowych. W cyklu om\u00f3wimy teori\u0119 i praktyk\u0119 budowy gie\u0142dy, aukcji i sklepu. Na ko\u0144cu artyku\u0142u proponuj\u0119 zag\u0142osowa\u0107 na najciekawsze dla Was tematy.<br \/>\n<\/em><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Elementy buduj\u0105ce aplikacje rozproszone. Drugie podej\u015bcie\" src=\"\/wp-content\/uploads\/2019\/04\/358996733e805327b587176f4f992aea.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To ko\u0144cowy artyku\u0142 cyklu o rozproszonych aplikacjach reaktywnych na Erlang\/Elixir. W <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">pierwszym artykule<\/a><\/noindex> mo\u017cna znale\u017a\u0107 teoretyczne podstawy architektury reaktywnej. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446108\/\">Drugi artyku\u0142<\/a><\/noindex> ilustruje g\u0142\u00f3wne wzorce i mechanizmy budowy podobnych system\u00f3w.<\/p>\n<p><\/p>\n<p>Dzi\u015b poruszymy kwestie rozwoju bazy kodu i projekt\u00f3w jako ca\u0142o\u015bci. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"organizaciya-servisov\">Organizacja us\u0142ug<\/h2>\n<p><\/p>\n<p>W rzeczywisto\u015bci, przy projektowaniu us\u0142ugi cz\u0119sto trzeba \u0142\u0105czy\u0107 kilka wzorc\u00f3w interakcji w jednym kontrolerze. Na przyk\u0142ad, us\u0142uga users, kt\u00f3ra zajmuje si\u0119 zarz\u0105dzaniem profilami u\u017cytkownik\u00f3w projektu, powinna odpowiada\u0107 na zapytania req-resp i informowa\u0107 o aktualizacjach profili poprzez pub-sub. Ten przypadek jest do\u015b\u0107 prosty: za messagingiem stoi jeden kontroler, kt\u00f3ry realizuje logik\u0119 us\u0142ugi i publikuje aktualizacje.<\/p>\n<p><\/p>\n<p>Sytuacja komplikuje si\u0119, gdy potrzebujemy wdro\u017cy\u0107 odporn\u0105 na b\u0142\u0119dy rozproszon\u0105 us\u0142ug\u0119. Za\u0142\u00f3\u017cmy, \u017ce wymagania wobec users si\u0119 zmieni\u0142y: <\/p>\n<p><\/p>\n<ol>\n<li>teraz us\u0142uga musi obs\u0142ugiwa\u0107 zapytania na 5 w\u0119z\u0142ach klastra, <\/li>\n<li>mie\u0107 mo\u017cliwo\u015b\u0107 wykonywania zada\u0144 w tle, <\/li>\n<li>a tak\u017ce umie\u0107 dynamicznie zarz\u0105dza\u0107 listami subskrypcyjnymi na aktualizacje profili.<\/li>\n<\/ol>\n<p><\/p>\n<p><em>Uwaga:<\/em> Kwestia sp\u00f3jnego przechowywania i replikacji danych nie jest przez nas rozpatrywana. Zak\u0142adamy, \u017ce te kwestie zosta\u0142y rozwi\u0105zane wcze\u015bniej i w systemie ju\u017c istnieje niezawodna i skalowalna warstwa przechowywania, a przetwarzacze maj\u0105 mechanizmy interakcji z ni\u0105.<\/p>\n<p><\/p>\n<p>Formalny opis us\u0142ugi users sta\u0142 si\u0119 bardziej skomplikowany. Z perspektywy programisty, dzi\u0119ki zastosowaniu messagingu, zmiany s\u0105 minimalne. Aby spe\u0142ni\u0107 pierwsze wymaganie, musimy skonfigurowa\u0107 balansowanie na punkcie wymiany req-resp. <\/p>\n<p><\/p>\n<p>Wym\u00f3g przetwarzania zada\u0144 w tle wyst\u0119puje cz\u0119sto. W przypadku u\u017cytkownik\u00f3w mog\u0105 to by\u0107 weryfikacje dokument\u00f3w u\u017cytkownik\u00f3w, przetwarzanie przes\u0142anego multimedia lub synchronizacja danych z sieciami spo\u0142eczno\u015bciowymi. Te zadania musz\u0105 by\u0107 w jaki\u015b spos\u00f3b podzielone w ramach klastra i kontrolowane. Dlatego mamy dwa warianty rozwi\u0105zania: albo skorzysta\u0107 ze wzorca przydzielania zada\u0144 z poprzedniego artyku\u0142u, albo, je\u015bli si\u0119 nie nadaje, napisa\u0107 niestandardowy harmonogram zada\u0144, kt\u00f3ry b\u0119dzie w odpowiedni spos\u00f3b zarz\u0105dza\u0142 pul\u0105 przetwarzaj\u0105cych. <\/p>\n<p><\/p>\n<p>Punkt 3 wymaga rozszerzenia wzorca pub-sub. Aby to zrealizowa\u0107, po utworzeniu punktu wymiany pub-sub, musimy dodatkowo uruchomi\u0107 kontroler tego punktu w naszym serwisie. W ten spos\u00f3b jakby wyjmujemy logik\u0119 przetwarzania subskrypcji i wypisania z warstwy messaging do implementacji u\u017cytkownik\u00f3w.<\/p>\n<p><\/p>\n<p>W wyniku tego, dekompozycja zadania pokaza\u0142a, \u017ce aby spe\u0142ni\u0107 wymagania, musimy uruchomi\u0107 na r\u00f3\u017cnych w\u0119z\u0142ach 5 egzemplarzy serwisu i stworzy\u0107 dodatkow\u0105 encj\u0119 \u2013 kontroler pub-sub, odpowiedzialny za subskrycj\u0119.<br \/>\nAby uruchomi\u0107 5 przetw\u00f3rc\u00f3w, nie ma potrzeby zmiany kodu serwisu. Jedynym dodatkowym dzia\u0142aniem jest konfiguracja zasad r\u00f3wnowa\u017cenia na punkcie wymiany, o czym porozmawiamy nieco p\u00f3\u017aniej.<br \/>\nPojawi\u0142a si\u0119 tak\u017ce dodatkowa z\u0142o\u017cono\u015b\u0107: kontroler pub-sub i niestandardowy harmonogram zada\u0144 musz\u0105 dzia\u0142a\u0107 w pojedynczym egzemplarzu. Znowu, serwis messaging, jako fundament, powinien dostarcza\u0107 mechanizm wyboru lidera.<\/p>\n<p><\/p>\n<h3 id=\"vybor-lidera\">Wyb\u00f3r lidera<\/h3>\n<p><\/p>\n<p>W systemach rozproszonych wyb\u00f3r lidera to procedura wyznaczania jednego procesu, kt\u00f3ry odpowiada za planowanie rozproszonego przetwarzania jakiego\u015b obci\u0105\u017cenia. <\/p>\n<p><\/p>\n<p>W systemach, kt\u00f3re nie s\u0105 sk\u0142onne do centralizacji, stosowane s\u0105 uniwersalne algorytmy i algorytmy oparte na konsensie, na przyk\u0142ad Paxos lub Raft.<br \/>\nPoniewa\u017c messaging to broker i centralny element, to wie o wszystkich kontrolerach serwisu \u2013 kandydatach na lider\u00f3w. Messaging mo\u017ce wyznacza\u0107 lidera bez przeprowadzania g\u0142osowania.<\/p>\n<p><\/p>\n<p>Wszystkie serwisy po starcie i po\u0142\u0105czeniu z punktem wymiany otrzymuj\u0105 wiadomo\u015b\u0107 systemow\u0105 <code>#'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}<\/code>. Je\u015bli <code>LeaderPid<\/code> jest zgodny z <code>pid<\/code> bie\u017c\u0105cego procesu, zostaje on wyznaczony liderem, a lista <code>Servers<\/code> zawiera wszystkie w\u0119z\u0142y i ich parametry.<br \/>\nW momencie pojawienia si\u0119 nowego i wy\u0142\u0105czenia dzia\u0142aj\u0105cego w\u0119z\u0142a klastra, wszystkie kontrolery us\u0142ug otrzymuj\u0105 <code>#'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts}<\/code> i <code>#'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts}<\/code> odpowiednio.<\/p>\n<p><\/p>\n<p>Dzi\u0119ki temu wszystkie komponenty s\u0105 \u015bwiadome wszystkich zmian, a w klastrze w ka\u017cdym momencie czasu jest gwarantowany jeden lider.<\/p>\n<p><\/p>\n<h2 id=\"posredniki\">Po\u015brednicy<\/h2>\n<p><\/p>\n<p>Aby zrealizowa\u0107 z\u0142o\u017cone rozproszone procesy przetwarzania oraz w zadaniach optymalizacji ju\u017c istniej\u0105cej architektury, wygodnie jest stosowa\u0107 po\u015brednik\u00f3w.<br \/>\nAby nie zmienia\u0107 kodu us\u0142ug i rozwi\u0105zywa\u0107 na przyk\u0142ad problemy z dodatkowym przetwarzaniem, trasowaniem lub logowaniem wiadomo\u015bci, przed us\u0142ug\u0105 mo\u017cna w\u0142\u0105czy\u0107 proxy, kt\u00f3re wykona ca\u0142\u0105 dodatkow\u0105 prac\u0119.<\/p>\n<p><\/p>\n<p>Klasycznym przyk\u0142adem optymalizacji pub-sub jest rozproszona aplikacja z rdzeniem biznesowym, generuj\u0105cym zdarzenia aktualizacji, na przyk\u0142ad zmian\u0119 ceny na rynku, oraz warstw\u0105 dost\u0119pu \u2014 N serwerami, kt\u00f3re oferuj\u0105 websocket API dla klient\u00f3w webowych.<br \/>\nJe\u015bli podej\u015b\u0107 do tego \"wprost\", to obs\u0142uga klienta wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<p><\/p>\n<ul>\n<li>klient nawi\u0105zuje po\u0142\u0105czenie z platform\u0105. Po stronie serwera, kt\u00f3ry ko\u0144czy ruch, uruchamiany jest proces obs\u0142uguj\u0105cy to po\u0142\u0105czenie.<\/li>\n<li>w kontek\u015bcie procesu obs\u0142uguj\u0105cego nast\u0119puje autoryzacja i subskrypcja aktualizacji. Proces wywo\u0142uje metod\u0119 subskrybuj dla temat\u00f3w.<\/li>\n<li>po wygenerowaniu zdarzenia w rdzeniu jest ono dostarczane do proces\u00f3w obs\u0142uguj\u0105cych po\u0142\u0105czenia.<\/li>\n<\/ul>\n<p><\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce mamy 50000 subskrybent\u00f3w na temat \"news\". Subskrybenci s\u0105 r\u00f3wnomiernie rozdzieleni na 5 serwer\u00f3w. W rezultacie ka\u017cda aktualizacja, docieraj\u0105c do punktu wymiany, b\u0119dzie replikowana 50000 razy: 10000 razy na ka\u017cdy serwer, zgodnie z liczb\u0105 subskrybent\u00f3w na nim. Nieco nieefektywna schemat, prawda?<br \/>\nAby poprawi\u0107 sytuacj\u0119, wprowadzimy proxy, kt\u00f3re ma t\u0119 sama nazw\u0119 co punkt wymiany. Rejestrator globalnych nazw powinien by\u0107 w stanie zwraca\u0107 najbli\u017cszy proces na podstawie nazwy, co jest istotne.<\/p>\n<p><\/p>\n<p>Uruchomimy to proxy na serwerach warstwy dost\u0119pu, a wszystkie nasze procesy obs\u0142uguj\u0105ce websocket API b\u0119d\u0105 si\u0119 do niego subskrybowa\u0107, a nie do oryginalnego punktu wymiany pub-sub w rdzeniu. Proxy subskrybuje rdze\u0144 tylko w przypadku unikalnej subskrypcji i replikowana otrzyman\u0105 wiadomo\u015b\u0107 dla wszystkich swoich subskrybent\u00f3w.<br \/>\nW rezultacie mi\u0119dzy rdzeniem a serwerami dost\u0119pu zostanie przes\u0142anych 5 wiadomo\u015bci, zamiast 50000.<\/p>\n<p><\/p>\n<h2 id=\"marshrutizaciya-i-balansirovka\">Trasowanie i balansowanie<\/h2>\n<p><\/p>\n<h3 id=\"req-resp\">Req-Resp<\/h3>\n<p><\/p>\n<p>W obecnej realizacji messaging istnieje 7 strategii rozdzielania zapyta\u0144:<\/p>\n<p><\/p>\n<ul>\n<li><code>default<\/code>. \u017b\u0105danie jest przesy\u0142ane do wszystkich kontroler\u00f3w.<\/li>\n<li><code>round-robin<\/code>. Wykonywana jest iteracja i cykliczne rozdzielanie \u017c\u0105da\u0144 mi\u0119dzy kontrolerami.<\/li>\n<li><code>konsensus<\/code>. Kontrolery obs\u0142uguj\u0105ce us\u0142ug\u0119 dziel\u0105 si\u0119 na lidera i podw\u0142adnych. \u017b\u0105dania s\u0105 przesy\u0142ane tylko do lidera.<\/li>\n<li><code>konsensus &amp; round-robin<\/code>. W grupie jest lider, ale \u017c\u0105dania s\u0105 rozdzielane mi\u0119dzy wszystkich cz\u0142onk\u00f3w.<\/li>\n<li><code>sticky<\/code>. Obliczany jest hash, kt\u00f3ry jest przypisany do konkretnego przetwarzacza. Kolejne \u017c\u0105dania z tym samym sygnatur\u0105 trafiaj\u0105 do tego samego przetwarzacza.<\/li>\n<li><code>sticky-fun<\/code>. Podczas inicjalizacji punktu wymiany dodatkowo przekazywana jest funkcja obliczania hash dla <code>sticky<\/code> r\u00f3wnowa\u017cenia.<\/li>\n<li><code>fun<\/code>. Analogicznie do sticky-fun, ale dodatkowo mo\u017cna przekierowa\u0107, odrzuci\u0107 lub wst\u0119pnie przetworzy\u0107 go. <\/li>\n<\/ul>\n<p><\/p>\n<p>Strategia rozdzielania jest okre\u015blana podczas inicjalizacji punktu wymiany.<\/p>\n<p><\/p>\n<p>Opr\u00f3cz r\u00f3wnowa\u017cenia, messaging pozwala na oznaczanie encji. Rozwa\u017cmy rodzaje tag\u00f3w w systemie:<\/p>\n<p><\/p>\n<ul>\n<li>Tag po\u0142\u0105czenia. Pozwala zrozumie\u0107, przez jakie po\u0142\u0105czenie przychodz\u0105 zdarzenia. U\u017cywany, gdy proces kontrolera \u0142\u0105czy si\u0119 z jednym punktem wymiany, ale z r\u00f3\u017cnymi kluczami routingu. <\/li>\n<li>Tag us\u0142ugi. Pozwala dla jednej us\u0142ugi grupowa\u0107 przetwarzacze i rozszerza\u0107 mo\u017cliwo\u015bci routingu i r\u00f3wnowa\u017cenia. Dla wzorca req-resp routing jest liniowy. Wysy\u0142amy \u017c\u0105danie do punktu wymiany, a ten nast\u0119pnie przekazuje je do us\u0142ugi. Ale je\u015bli musimy podzieli\u0107 przetwarzacze na logiczne grupy, podzia\u0142 odbywa si\u0119 za pomoc\u0105 tag\u00f3w. Po wskazaniu taga, \u017c\u0105danie zostanie skierowane do konkretnej grupy kontroler\u00f3w.<\/li>\n<li>Tag \u017c\u0105dania. Pozwala odr\u00f3\u017cnia\u0107 odpowiedzi. Poniewa\u017c nasz system jest asynchroniczny, przy przetwarzaniu odpowiedzi us\u0142ugi trzeba mie\u0107 mo\u017cliwo\u015b\u0107 wskazania RequestTag podczas wysy\u0142ania \u017c\u0105dania. Na jego podstawie mo\u017cemy zrozumie\u0107, kt\u00f3ra odpowied\u017a na jakie \u017c\u0105danie do nas przysz\u0142a.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"pub-sub\">Pub-sub<\/h3>\n<p><\/p>\n<p>Dla pub-sub jest nieco pro\u015bciej. Mamy punkt wymiany, na kt\u00f3ry publikowane s\u0105 wiadomo\u015bci. Punkt wymiany rozdziela wiadomo\u015bci mi\u0119dzy subskrybent\u00f3w, kt\u00f3rzy zapisali si\u0119 na odpowiednie klucze routingu (mo\u017cna powiedzie\u0107, \u017ce to odpowiednik temat\u00f3w).<\/p>\n<p><\/p>\n<h2 id=\"masshtabiruemost-i-otkazoustoychivost\">Skalowalno\u015b\u0107 i odporno\u015b\u0107 na awarie<\/h2>\n<p><\/p>\n<p>Skalowalno\u015b\u0107 systemu w ca\u0142o\u015bci zale\u017cy od stopnia skalowalno\u015bci warstw i komponent\u00f3w systemu:<\/p>\n<p><\/p>\n<ul>\n<li>Us\u0142ugi skaluj\u0105 si\u0119 poprzez dodawanie dodatkowych w\u0119z\u0142\u00f3w z obs\u0142uguj\u0105cymi ten serwis do klastra. W trakcie eksploatacji mo\u017cliwe jest wybranie optymalnej polityki r\u00f3wnowa\u017cenia obci\u0105\u017cenia.<\/li>\n<li>Sam serwis messaging w ramach oddzielnego klastra w og\u00f3lnym przypadku skalowa\u0107 si\u0119 mo\u017ce albo poprzez przeniesienie szczeg\u00f3lnie obci\u0105\u017conych punkt\u00f3w wymiany na oddzielne w\u0119z\u0142y klastra, albo poprzez dodawanie proces\u00f3w proxy do szczeg\u00f3lnie obci\u0105\u017conych stref klastra.<\/li>\n<li>Skalowalno\u015b\u0107 ca\u0142ego systemu jako cecha zale\u017cy od elastyczno\u015bci architektury i mo\u017cliwo\u015bci scalania poszczeg\u00f3lnych klastr\u00f3w w jedn\u0105 wsp\u00f3ln\u0105 jednostk\u0119 logiczn\u0105.<\/li>\n<\/ul>\n<p><\/p>\n<p>Sukces projektu cz\u0119sto zale\u017cy od prostoty i szybko\u015bci skalowania. Messaging w obecnym wydaniu ro\u015bnie razem z aplikacj\u0105. Nawet je\u015bli brakuje nam klastra z 50-60 maszyn, mo\u017cna zastosowa\u0107 federacj\u0119. Niestety, temat federacji wykracza poza zakres tego artyku\u0142u.<\/p>\n<p><\/p>\n<h2 id=\"rezervirovanie\">Rezerwa<\/h2>\n<p><\/p>\n<p>Podczas omawiania r\u00f3wnowa\u017cenia obci\u0105\u017cenia ju\u017c rozmawiali\u015bmy o rezerwowaniu kontroler\u00f3w us\u0142ug. Jednak messaging r\u00f3wnie\u017c musi by\u0107 zarezerwowany. W przypadku awarii w\u0119z\u0142a lub maszyny, messaging musi automatycznie si\u0119 odbudowa\u0107, i to w jak najkr\u00f3tszym czasie.<\/p>\n<p><\/p>\n<p>W swoich projektach wykorzystuj\u0119 dodatkowe w\u0119z\u0142y, kt\u00f3re przejmuj\u0105 obci\u0105\u017cenie w przypadku awarii. W Erlangu istnieje standardowa implementacja trybu rozproszonego dla aplikacji OTP. Tryb rozproszony dokonuje odbudowy w przypadku awarii poprzez uruchomienie usuni\u0119tej aplikacji na innym wcze\u015bniej uruchomionym w\u0119\u017ale. Proces jest przezroczysty, po awarii aplikacja automatycznie przechodzi na w\u0119ze\u0142 failover. Mo\u017cna przeczyta\u0107 o tej funkcjonalno\u015bci wi\u0119cej. <noindex><a rel=\"nofollow\" href=\"http:\/\/erlang.org\/doc\/design_principles\/distributed_applications.html\">tutaj<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"proizvoditelnost\">Wydajno\u015b\u0107<\/h2>\n<p><\/p>\n<p>Spr\u00f3bujmy chocia\u017c w przybli\u017ceniu por\u00f3wna\u0107 wydajno\u015b\u0107 rabbitmq i naszego dostosowanego messaging.<br \/>\nZnalaz\u0142em <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.openstack.org\/developer\/performance-docs\/test_results\/mq\/rabbitmq\/cmsm\/index.html\">oficjalne wyniki<\/a><\/noindex> testowania rabbitmq przez zesp\u00f3\u0142 openstack.<\/p>\n<p><\/p>\n<p>W punkcie 6.14.1.2.1.2.2 oryginalnego dokumentu przedstawiono wynik RPC CAST:<br \/>\n<img decoding=\"async\" alt=\"Elementy buduj\u0105ce aplikacje rozproszone. Drugie podej\u015bcie\" src=\"\/wp-content\/uploads\/2019\/04\/95f615d241d70a4523fe3c400179b8e6.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wst\u0119pnie nie b\u0119dziemy wprowadza\u0107 \u017cadnych dodatkowych ustawie\u0144 do j\u0105dra OS lub erlang VM. Warunki do testowania:<\/p>\n<p><\/p>\n<ul>\n<li>erl opts: +A1 +sbtu.<\/li>\n<li>Test w ramach jednego w\u0119z\u0142a erlang uruchamiany jest na laptopie ze starym i7 w mobilnej wersji.<\/li>\n<li>Testy klastrowe odbywaj\u0105 si\u0119 na serwerach z sieci\u0105 10G.<\/li>\n<li>Kod dzia\u0142a w kontenerach docker. Sie\u0107 w trybie NAT.<\/li>\n<\/ul>\n<p><\/p>\n<p>Kod testu:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">req_resp_bench(_) -&gt;\n  W = perftest:comprehensive(10000,\n    fun() -&gt;\n      messaging:request(?EXCHANGE, default, ping, self()),\n      receive\n        #'$msg'{message = pong} -&gt; ok\n      after 5000 -&gt;\n        throw(timeout)\n      end\n    end\n  ),\n  true = lists:any(fun(E) -&gt; E &gt;= 30000 end, W),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p><em>Scenariusz 1:<\/em> Test uruchamiany jest na laptopie z nieco starszym procesorem i7 w wersji mobilnej. Test, messaging i serwis dzia\u0142aj\u0105 na jednym w\u0119\u017ale w jednym kontenerze dockerowym:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Sekwencyjne 10000 cykli w ~0 sekund (26987 cykli\/s)\nSekwencyjne 20000 cykli w ~1 sekund (26915 cykli\/s)\nSekwencyjne 100000 cykli w ~4 sekund (26957 cykli\/s)\nR\u00f3wnoleg\u0142e 2 100000 cykli w ~2 sekund (44240 cykli\/s)\nR\u00f3wnoleg\u0142e 4 100000 cykli w ~2 sekund (53459 cykli\/s)\nR\u00f3wnoleg\u0142e 10 100000 cykli w ~2 sekund (52283 cykli\/s)\nR\u00f3wnoleg\u0142e 100 100000 cykli w ~3 sekund (49317 cykli\/s)<\/code><\/pre>\n<p><\/p>\n<p><em>Scenariusz 2<\/em>: 3 w\u0119z\u0142y uruchomione na r\u00f3\u017cnych maszynach pod dockerem (NAT).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Sekwencyjne 10000 cykli w ~1 sekund (8684 cykli\/s)\nSekwencyjne 20000 cykli w ~2 sekund (8424 cykli\/s)\nSekwencyjne 100000 cykli w ~12 sekund (8655 cykli\/s)\nR\u00f3wnoleg\u0142e 2 100000 cykli w ~7 sekund (15160 cykli\/s)\nR\u00f3wnoleg\u0142e 4 100000 cykli w ~5 sekund (19133 cykli\/s)\nR\u00f3wnoleg\u0142e 10 100000 cykli w ~4 sekund (24399 cykli\/s)\nR\u00f3wnoleg\u0142e 100 100000 cykli w ~3 sekund (34517 cykli\/s)<\/code><\/pre>\n<p><\/p>\n<p>W ka\u017cdym przypadku wykorzystanie CPU nie przekracza\u0142o 250%<\/p>\n<p><\/p>\n<h2 id=\"itogi\">Podsumowanie<\/h2>\n<p><\/p>\n<p>Mam nadziej\u0119, \u017ce ten cykl nie wygl\u0105da jak strumie\u0144 \u015bwiadomo\u015bci i moje do\u015bwiadczenie przyniesie realne korzy\u015bci zar\u00f3wno badaczom system\u00f3w rozproszonych, jak i praktykom, kt\u00f3rzy s\u0105 na pocz\u0105tku drogi w budowaniu rozproszonych architektur dla swoich system\u00f3w biznesowych i z zainteresowaniem przygl\u0105daj\u0105 si\u0119 Erlangowi\/Elixirowi, ale maj\u0105 w\u0105tpliwo\u015bci, czy warto&#8230;<\/p>\n<p><\/p>\n<p>Zdj\u0119cie <noindex><a rel=\"nofollow\" href=\"https:\/\/unsplash.com\/photos\/Q4bmoSPJM18\">@chuttersnap<\/a><\/noindex><\/p>\n<p class=\"for_users_only_msg\">Tylko zarejestrowani u\u017cytkownicy mog\u0105 bra\u0107 udzia\u0142 w ankiecie. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Zaloguj si\u0119<\/a><\/noindex>, prosz\u0119.<\/p>\n<h2 class=\"default-block__polling-title\">Jakie tematy powinienem szczeg\u00f3\u0142owo om\u00f3wi\u0107 w cyklu \u201eEksperyment VTrade\u201d?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Teoria: Rynki, zlecenia i czas ich realizacji: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Ksi\u0119ga zlece\u0144. Teoria i praktyka realizacji ksi\u0119gi z grupowaniami<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Wizualizacja handlu: Tick, s\u0142upki, rozdzielczo\u015bci. Jak przechowywa\u0107 i jak \u0142\u0105czy\u0107<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Back-office. Planowanie i rozw\u00f3j. Kontrola pracownik\u00f3w i badanie incydent\u00f3w<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    API. Zrozumienie, jakie interfejsy s\u0105 potrzebne i jak je zrealizowa\u0107<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Przechowywanie informacji: PostgreSQL, Timescale, Tarantool w systemach handlowych<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Reaktywno\u015b\u0107 w systemach handlowych<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Inne. Napisz\u0119 w komentarzach<\/p>\n<\/li>\n<\/ul>\n<p>    W g\u0142osowaniu wzi\u0119\u0142o udzia\u0142 6 u\u017cytkownik\u00f3w. 4 u\u017cytkownik\u00f3w wstrzyma\u0142o si\u0119.<br \/>\n<br \/>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446344\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u0412 \u0446\u0438\u043a\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d\u0430 \u0442\u0435\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0431\u0438\u0440\u0436\u0438, \u0430\u0443\u043a\u0446\u0438\u043e\u043d\u0430 \u0438 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430. \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u0442\u044c \u0437\u0430 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0432\u0430\u043c \u0442\u0435\u043c\u044b. \u042d\u0442\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0446\u0438\u043a\u043b\u0430 \u043f\u043e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":23092,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-31124","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0412\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:39:36+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:39:36+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Elementy sk\u0142adowe aplikacji rozproszonych. Drugie podej\u015bcie | ProHoster","description":"Zapowied\u017a Kole\u017canki, w po\u0142owie lata planuj\u0119 opublikowa\u0107 jeszcze jeden cykl artyku\u0142\u00f3w na temat projektowania system\u00f3w obs\u0142ugi masowej: \u201eEksperyment VTrade\u201d \u2014 pr\u00f3ba napisania frameworka dla handlu.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0412\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster","og:description":"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:39:36+00:00","article:modified_time":"2019-10-31T18:39:36+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"31124","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 04:39:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:22:34","updated":"2026-01-21 04:39:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/31124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=31124"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/31124\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/23092"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=31124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=31124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=31124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}