{"id":30908,"date":"2019-10-31T21:38:07","date_gmt":"2019-10-31T18:38:07","guid":{"rendered":"https:\/\/prohoster.info\/blog\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie\/"},"modified":"2019-10-31T21:38:07","modified_gmt":"2019-10-31T18:38:07","slug":"stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","status":"publish","type":"post","link":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","title":{"rendered":"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/7ef485e452075775ce317b557671274c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I den forrige <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">artikel<\/a><\/noindex> Vi har d\u00e6kket de teoretiske grundlag for reaktiv arkitektur. Det er tid til at tale om datastr\u00f8mme, implementeringsveje for reaktive Erlang\/Elixir systemer og meddelelsesm\u00f8nstre i dem:<\/p>\n<p><\/p>\n<ul>\n<li>Request-response<\/li>\n<li>Request-Chunked Response<\/li>\n<li>Response with Request<\/li>\n<li>Publish-subscribe<\/li>\n<li>Inverted Publish-subscribe<\/li>\n<li>Task distribution<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"soa-msa-i-obmen-soobscheniyami\">SOA, MSA og meddelelser<\/h2>\n<p><\/p>\n<p>SOA, MSA - systemarkitekturer, der definerer reglerne for opbygning af systemer, mens messaging giver primitivtilgange til deres implementering.<\/p>\n<p><\/p>\n<p>Jeg \u00f8nsker ikke at fremme en bestemt arkitektur til systemopbygning. Jeg er tilh\u00e6nger af at anvende de mest effektive og nyttige praksisser for det specifikke projekt og forretning. Uanset hvilken paradygme vi v\u00e6lger, er det bedst at skabe systemkomponenter med hensyn til Unix-principperne: komponenter med minimal sammenh\u00e6ng, der er ansvarlige for individuelle enheder. API-metoderne udf\u00f8rer s\u00e5 enkle handlinger som muligt med enheder.<\/p>\n<p><\/p>\n<p>Messaging - som navnet antyder - er en meddelelsesbroker. Dens prim\u00e6re form\u00e5l er at modtage og sende meddelelser. Den h\u00e5ndterer gr\u00e6nseflader til informationsafsendelse, opbygning af logiske informationskanaler inden for systemet, routing og belastningsbalancering, samt fejlh\u00e5ndtering p\u00e5 systemniveau.<br \/>\nDet udviklede messaging fors\u00f8ger ikke at konkurrere med rabbitmq eller erstatte det. Dets prim\u00e6re egenskaber er:<\/p>\n<p><\/p>\n<ul>\n<li>Distribution.<br \/>\nUdvekslingspunkter kan oprettes p\u00e5 alle noder i klyngen, s\u00e5 t\u00e6t som muligt p\u00e5 koden, der bruger dem.<\/li>\n<li>Simplicity.<br \/>\nFokus p\u00e5 at minimere skabelonkode og brugervenlighed.<\/li>\n<li>Bedste ydeevne.<br \/>\nVi fors\u00f8ger ikke at gentage funktionaliteten af rabbitmq, men fremh\u00e6ver blot den arkitektoniske og transportlag, som vi nemt integrerer i OTP, og dermed minimerer omkostningerne.<\/li>\n<li>Fleksibilitet.<br \/>\nHver service kan kombinere flere meddelelsesm\u00f8nstre.<\/li>\n<li>Fejltolerance indbygget i designet.<\/li>\n<li>Skalerbarhed.<br \/>\nMessaging vokser sammen med applikationen. Efterh\u00e5nden som belastningen stiger, kan udvekslingspunkter flyttes til separate maskiner.<\/li>\n<\/ul>\n<p><\/p>\n<p><em>Bem\u00e6rkning.<\/em> N\u00e5r det kommer til organisering af kode, er meta-projekter velegnede til komplekse systemer i Erlang\/Elixir. Al kode for projektet findes i et enkelt repository - et overprojekt. Mikroservices er samtidig maksimalt isolerede og udf\u00f8rer enkle operationer, der svarer til en enkelt enhed. Med denne tilgang er det nemt at vedligeholde API'et for hele systemet, foretage \u00e6ndringer og skrive enheds- og integrationstest.<\/p>\n<p><\/p>\n<p>Systemkomponenter interagerer direkte eller via en broker. Fra et messaging-perspektiv har hver service flere livsfaser:<\/p>\n<p><\/p>\n<ul>\n<li>Initialisering af service.<br \/>\nP\u00e5 dette trin sker konfiguration og opstart af den udf\u00f8rende serviceproces samt afh\u00e6ngigheder.<\/li>\n<li>Oprettelse af en exchange point.<br \/>\nServicen kan bruge et statisk exchange point, der er angivet i nodens konfiguration, eller den kan oprette exchange points dynamisk. <\/li>\n<li>Registrering af service.<br \/>\nFor at en service kan betjene anmodninger, skal den registreres p\u00e5 exchange point.<\/li>\n<li>Normal drift.<br \/>\nServicen udf\u00f8rer nyttigt arbejde.<\/li>\n<li>Afslutning af drift.<br \/>\nDer er 2 former for afslutning: planm\u00e6ssig og n\u00f8dstop. Ved planm\u00e6ssig afslutning frakobles servicen fra exchange point og stoppes. I n\u00f8dssituationer udf\u00f8rer messaging et af nedbrudsh\u00e5ndteringsscenarierne.<\/li>\n<\/ul>\n<p><\/p>\n<p>Det ser ret kompliceret ud, men i koden er det ikke s\u00e5 skr\u00e6mmende. Eksempler p\u00e5 kode med kommentarer vil blive pr\u00e6senteret i gennemgangen af skabeloner lidt senere.<\/p>\n<p><\/p>\n<h2 id=\"exchanges\">Exchanges<\/h2>\n<p><\/p>\n<p>Et exchange point er en messaging-proces, der implementerer logikken for interaktion med komponenter inden for rammerne af messaging skabelonen. I alle de nedenst\u00e5ende eksempler interagerer komponenterne gennem exchange points, og kombinationen af dem danner messaging.<\/p>\n<p><\/p>\n<h2 id=\"message-exchange-patterns-meps\">Message exchange patterns (MEPs)<\/h2>\n<p><\/p>\n<p>Globalt kan m\u00f8nstre for udveksling opdeles i to-vejs og \u00e9n-vejs. De f\u00f8rste indeb\u00e6rer et svar p\u00e5 den modtagne besked, de sidstn\u00e6vnte g\u00f8r ikke. Et klassisk eksempel p\u00e5 et to-vejs m\u00f8nster i klient-server-arkitektur er Request-response m\u00f8nsteret. Lad os se p\u00e5 m\u00f8nsteret og dets modifikationer.<\/p>\n<p><\/p>\n<h3 id=\"requestresponse-ili-rpc\">Request\u2013response eller RPC<\/h3>\n<p><\/p>\n<p>RPC anvendes, n\u00e5r vi har brug for et svar fra en anden proces. Denne proces kan v\u00e6re startet p\u00e5 den samme node eller v\u00e6re placeret p\u00e5 en anden kontinent. Nedenfor er et skema for interaktionen mellem klienten og <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/da\/server\/dts-los-angeles\/\"   title=\"server\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"3483\">server<\/a> gennem messaging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/091725fc108d6ce1a5fc9ae866e2c395.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Da messaging er helt asynkron, opdeles udvekslingen for klienten i 2 faser:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Afsendelse af anmodning<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).<\/code><\/pre>\n<p><\/p>\n<p><em>Exchange<\/em> \u2012 et unikt navn p\u00e5 udvekslingspunktet<br \/>\n<em>ResponseMatchingTag<\/em> \u2012 en lokal m\u00e6rkat til behandling af svaret. For eksempel ved sending af flere ens anmodninger, der tilh\u00f8rer forskellige brugere.<br \/>\n<em>RequestDefinition<\/em> \u2012 anmodningens krop<br \/>\n<em>HandlerProcess<\/em> \u2012 PID for handleren. Denne proces vil modtage svaret fra serveren.<\/p>\n<p>\n<\/li>\n<li>\n<p>Behandling af svaret<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">handle_info(#'$msg'{exchange = EXCHANGE, tag = ResponseMatchingTag,message = ResponsePayload}, State)<\/code><\/pre>\n<p><\/p>\n<p><em>ResponsePayload<\/em> \u2012 serverens svar.<\/p>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>For serveren best\u00e5r processen ogs\u00e5 af 2 faser:<\/p>\n<p><\/p>\n<ol>\n<li>Initialisering af udvekslingspunktet<\/li>\n<li>Behandling af modtagne anmodninger<\/li>\n<\/ol>\n<p><\/p>\n<p>Lad os illustrere denne skabelon med kode. Antag, at vi skal implementere en simpel tjeneste, der giver et enkelt pr\u00e6cist tidspunkt.<\/p>\n<p><\/p>\n<h4 id=\"kod-servera\">Serverkode<\/h4>\n<p><\/p>\n<p>Lad os flytte API-definitionen til tjenesten til api.hrl:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% =====================================================\n%%  entities\n%% =====================================================\n-record(time, {\n  unixtime :: non_neg_integer(),\n  datetime :: binary()\n}).\n\n-record(time_error, {\n  code :: non_neg_integer(),\n  error :: term()\n}).\n\n%% =====================================================\n%%  methods\n%% =====================================================\n-record(time_req, {\n  opts :: term()\n}).\n-record(time_resp, {\n  result :: #time{} | #time_error{}\n}).<\/code><\/pre>\n<p><\/p>\n<p>Defin\u00e9r tjenestens controller i time_controller.erl<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% Eksemplet viser kun den meningsfulde kode. Ved at inds\u00e6tte det i skabelonen gen_server kan vi f\u00e5 en fungerende tjeneste.\n\n%% initialisering af gen_server\ninit(Args) -&gt;\n  %% forbindelse til udvekslingspunktet\n  messaging:monitor_exchange(req_resp, ?EXCHANGE, default, self())\n  {ok, #{}}.\n\n%% behandling af begivenheden for tab af forbindelse til udvekslingspunktet. Den samme begivenhed opst\u00e5r, hvis udvekslingspunktet ikke er startet endnu.\nhandle_info(#exchange_die{exchange = ?EXCHANGE}, State) -&gt;\n  erlang:send(self(), monitor_exchange),\n  {noreply, State};\n\n%% behandling af API\nhandle_info(#time_req{opts = _Opts}, State) -&gt;\n  messaging:response_once(Client, #time_resp{\nresult = #time{ unixtime = time_utils:unixtime(now()), datetime = time_utils:iso8601_fmt(now())}\n  });\n  {noreply, State};\n\n%% afslutning af gen_server\nterminate(_Reason, _State) -&gt;\n  messaging:demonitor_exchange(req_resp, ?EXCHANGE, default, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<h4 id=\"kod-klienta\">Klientkode<\/h4>\n<p><\/p>\n<p>For at sende en anmodning til tjenesten kan vi kalde messaging request API'et hvor som helst i klienten:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">case messaging:request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) of\n    ok -&gt; ok;\n    _ -&gt; %% gentag eller fejllogik\nend<\/code><\/pre>\n<p><\/p>\n<p>I et distribueret system kan komponentkonfigurationen v\u00e6re meget forskellig, og p\u00e5 tidspunktet for anmodningen kan messaging muligvis ikke v\u00e6re startet, eller tjenestens controller vil ikke v\u00e6re klar til at h\u00e5ndtere anmodningen. Derfor skal vi kontrollere svaret fra messaging og h\u00e5ndtere tilfellet for afvisning.<br \/>\nEfter at klienten har sendt anmodningen, vil svaret eller en fejl komme fra tjenesten.<br \/>\nLad os h\u00e5ndtere begge tilf\u00e6lde i handle_info:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">handle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time{unixtime = Utime}}}, State) -&gt;\n  ?debugVal(Utime),\n  {noreply, State};\n\nhandle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time_error{code = ErrorCode}}}, State) -&gt;\n  ?debugVal({error, ErrorCode}),\n  {noreply, State};<\/code><\/pre>\n<p><\/p>\n<h3 id=\"request-chunked-response\">Request-Chunked Response<\/h3>\n<p><\/p>\n<p>Det er bedre ikke at tillade overf\u00f8rsel af store beskeder. Dette afh\u00e6nger af reaktionshastigheden og den stabile drift af hele systemet. Hvis svar p\u00e5 en anmodning kr\u00e6ver meget hukommelse, er det n\u00f8dvendigt at opdele det i dele.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/bd60742a933a8e4e3eeaf7f4adf00f2a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her er et par eksempler p\u00e5 s\u00e5danne tilf\u00e6lde:<\/p>\n<p><\/p>\n<ul>\n<li>Komponenter udveksler bin\u00e6re data, for eksempel filer. At opdele svaret i mindre dele hj\u00e6lper med effektivt at arbejde med filer af enhver st\u00f8rrelse og undg\u00e5 hukommelsesoverl\u00f8b.<\/li>\n<li>Lister. For eksempel skal vi v\u00e6lge alle poster fra en k\u00e6mpestor tabel i databasen og sende den til en anden komponent.<\/li>\n<\/ul>\n<p><\/p>\n<p>Jeg kalder s\u00e5danne svar for en lokomotiv. Under alle omst\u00e6ndigheder er 1024 beskeder p\u00e5 1 MB bedre end en enkelt besked p\u00e5 1 GB. <\/p>\n<p><\/p>\n<p>I et Erlang-kluster opn\u00e5r vi ekstra gevinst \u2012 reduktion af belastningen p\u00e5 udvekslingspunktet og netv\u00e6rket, da svarene sendes direkte til modtageren, omg\u00e5s udvekslingspunktet.<\/p>\n<p><\/p>\n<h3 id=\"response-with-request\">Response with Request<\/h3>\n<p><\/p>\n<p>Dette er en ret sj\u00e6lden modifikation af RPC-m\u00f8nsteret til opbygning af dialogsystemer.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/9b350a0b48ca8acdca973da2f7eadb76.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h3 id=\"publish-subscribe-data-distribution-tree\">Publish-subscribe (data distribution tree)<\/h3>\n<p><\/p>\n<p>Begivenhedsorienterede systemer leverer data til forbrugere, efterh\u00e5nden som de er klar. S\u00e5ledes er systemerne mere tilb\u00f8jelige til en push-model snarere end pull eller poll. Denne egenskab forhindrer un\u00f8dvendig ressourceforbrug ved konstant at anmode om og vente p\u00e5 data.<br \/>\nIllustrationen viser processen med at distribuere meddelelser til forbrugere, der er tilmeldt et bestemt emne.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/e211d5dcfeb5ce8513699eac8e3b6d84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Klassiske eksempler p\u00e5 brug af dette m\u00f8nster er distribution af tilstand: den virtuelle verden i computerspil, markedsdata p\u00e5 b\u00f8rser, nyttige oplysninger i datafeeds.<\/p>\n<p><\/p>\n<p>Lad os overveje abonnentens kode:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">init(_Args) -&gt;\n  %% vi tilmelder os udvekslingen, n\u00f8gle = key\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {ok, #{}}.\n\nhandle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) -&gt;\n  %% hvis udvekslingspunktet ikke er tilg\u00e6ngeligt, s\u00e5 pr\u00f8ver vi at genoprette forbindelsen\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {noreply, State};\n\n%% behandler de modtagne beskeder\nhandle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) -&gt;\n  ?debugVal(Msg),\n  {noreply, State};\n\n%% ved forbrugeren standses - afmelder vi os fra udvekslingspunktet\nterminate(_Reason, _State) -&gt;\n  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p>Kilden kan udl\u00f8se meddelelsespublikationsfunktionen hvor som helst det er praktisk:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">messaging:publish_message(Exchange, Key, Message).<\/code><\/pre>\n<p><\/p>\n<p><em>Exchange<\/em> \u2012 navnet p\u00e5 udvekslingspunktet,<br \/>\n<em>N\u00f8gle<\/em> \u2012 routingn\u00f8glen<br \/>\n<em>Meddelelse<\/em> \u2012 nyttelasten<\/p>\n<p><\/p>\n<h2 id=\"inverted-publish-subscribe\">Inverted Publish-subscribe<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/2ef7cd7de459455937bdcfa8a11fd028.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ved at implementere pub-sub kan man opn\u00e5 et m\u00f8nster, der er praktisk til logning. S\u00e6ttet af kilder og forbrugere kan v\u00e6re helt forskelligt. I diagrammet ses et tilf\u00e6lde med \u00e9n forbruger og mange kilder.<\/p>\n<p><\/p>\n<h2 id=\"task-distribution-pattern\">Opgavedistributionsm\u00f8nster<\/h2>\n<p><\/p>\n<p>I n\u00e6sten hvert projekt opst\u00e5r der opgaver til forsinket behandling, s\u00e5som rapportgenerering, levering af notifikationer, indhentning af data fra tredjepartssystemer. Systemets kapacitet til at udf\u00f8re disse opgaver kan let skaleres ved at tilf\u00f8je behandlere. Det vi skal g\u00f8re, er at danne et cluster af behandlere og j\u00e6vnt fordele opgaverne mellem dem.<\/p>\n<p><\/p>\n<p>Lad os overveje de opst\u00e5ede situationer med tre behandlere som eksempel. Allerede under opgavefordelingen opst\u00e5r sp\u00f8rgsm\u00e5let om retf\u00e6rdig fordeling og overbelastning af behandlere. Retf\u00e6rdigheden vil blive sikret af round-robin fordeling, og for at undg\u00e5 overbelastning af behandlere vil vi indf\u00f8re en begr\u00e6nsning <em>prefetch_limit<\/em>. I overgangstilstande <em>prefetch_limit<\/em> vil det forhindre \u00e9n behandler i at f\u00e5 alle opgaver.<\/p>\n<p><\/p>\n<p>Messaging styrer k\u00f8er og behandlingsprioritet. Behandlere modtager opgaver, efterh\u00e5nden som de kommer ind. Udf\u00f8relsen af en opgave kan enten v\u00e6re vellykket eller mislykkes:<\/p>\n<p><\/p>\n<ul>\n<li><code>messaging:ack(Tack)<\/code> \u2012 kaldes ved vellykket behandling af meddelelsen<\/li>\n<li><code>messaging:nack(Tack)<\/code> \u2012 kaldes i alle unormale situationer. Efter tilbagesendelsen vil messaging videresende opgaven til en anden behandler.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Byggesten til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse.\" src=\"\/wp-content\/uploads\/2019\/04\/c2c632b6411247ee8b0dcfb3250a4503.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os antage, at der opstod en kompleks fejl under behandlingen af tre opgaver: behandler 1 faldt efter at have modtaget opgaven, uden at have sendt noget til udvekslingspunktet. I dette tilf\u00e6lde vil udvekslingspunktet efter udl\u00f8bet af ack timeout sende opgaven til en anden behandler. Behandler 3 forkastede opgaven af en eller anden grund og sendte nack, s\u00e5 opgaven gik ogs\u00e5 til en anden behandler, som lykkedes med at udf\u00f8re den.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnyy-itog\">Forel\u00f8bigt resultat<\/h2>\n<p><\/p>\n<p>Vi har gennemg\u00e5et de grundl\u00e6ggende byggesten i distribuerede systemer og f\u00e5et en grundl\u00e6ggende forst\u00e5else af deres anvendelse i Erlang\/Elixir.<\/p>\n<p><\/p>\n<p>Ved at kombinere de grundl\u00e6ggende skabeloner kan man konstruere komplekse paradigmer til at l\u00f8se de opst\u00e5ende opgaver.<\/p>\n<p><\/p>\n<p>I den afsluttende del af cyklussen vil vi se p\u00e5 generelle sp\u00f8rgsm\u00e5l om organisering af tjenester, routing og load balancing, samt tale om de praktiske aspekter af skalerbarhed og fejltolerance i systemerne.<\/p>\n<p><\/p>\n<p>Slutningen p\u00e5 anden del.<\/p>\n<p><\/p>\n<p>Foto <noindex>Marius Christensen<\/noindex><br \/>\nIllustrationer er forberedt ved hj\u00e6lp af websequencediagrams.com<\/p>\n<p>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446108\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b. \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043e \u043f\u043e\u0442\u043e\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0443\u0442\u044f\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 Erlang\/Elixir \u0441\u0438\u0441\u0442\u0435\u043c \u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u0445 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043d\u0438\u0445: Request-response Request-Chunked Response Response with Request Publish-subscribe Inverted Publish-subscribe Task distribution SOA, MSA \u0438 \u043e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 SOA, MSA \u2013 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0438\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22886,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-30908","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.3 - aioseo.com -->\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\/da\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\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. \u041f\u0435\u0440\u0432\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-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:38:07+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:38:07+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\udd47Byggeklodser til distribuerede applikationer. F\u00f8rste tiln\u00e6rmelse | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","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. \u041f\u0435\u0440\u0432\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster","og:url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-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:38:07+00:00","article:modified_time":"2019-10-31T18:38:07+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30908","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-02-22 15:33:36","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:27:06","updated":"2026-02-22 15:33:36","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/30908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=30908"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/30908\/revisions"}],"predecessor-version":[{"id":162009,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/30908\/revisions\/162009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/22886"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=30908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=30908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=30908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}