{"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\/de\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","title":{"rendered":"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/7ef485e452075775ce317b557671274c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Im letzten <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">Artikel<\/a><\/noindex> Wir haben die theoretischen Grundlagen der reaktiven Architektur er\u00f6rtert. Jetzt ist es an der Zeit, \u00fcber Datenstr\u00f6me, Implementierungswege von reaktiven Erlang\/Elixir-Systemen und die Muster des Nachrichtenaustauschs zu sprechen:<\/p>\n<p><\/p>\n<ul>\n<li>Anfrage-Antwort<\/li>\n<li>Anfrage-Chunked Antwort<\/li>\n<li>Antwort mit Anfrage<\/li>\n<li>Ver\u00f6ffentlichen-Abonnieren<\/li>\n<li>Umgekehrtes Ver\u00f6ffentlichen-Abonnieren<\/li>\n<li>Taskverteilung<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"soa-msa-i-obmen-soobscheniyami\">SOA, MSA und Nachrichtenaustausch<\/h2>\n<p><\/p>\n<p>SOA, MSA \u2013 Systemarchitekturen, die die Regeln f\u00fcr den Aufbau von Systemen definieren, w\u00e4hrend Messaging primitives f\u00fcr deren Implementierung bereitstellt.<\/p>\n<p><\/p>\n<p>Ich m\u00f6chte keine bestimmte Architektur propagieren. Ich bin f\u00fcr die Anwendung von m\u00f6glichst effektiven und n\u00fctzlichen Praktiken f\u00fcr das jeweilige Projekt und Unternehmen. Welche Paradigmen wir auch w\u00e4hlen, Systemkomponenten sollten im Sinne des Unix-Ways erstellt werden: Komponenten mit minimaler Kopplung, die f\u00fcr einzelne Entit\u00e4ten verantwortlich sind. API-Methoden f\u00fchren die einfachsten Aktionen mit Entit\u00e4ten aus.<\/p>\n<p><\/p>\n<p>Messaging \u2012 wie der Name schon sagt \u2012 ist ein Nachrichtenbroker. Sein Hauptziel ist es, Nachrichten entgegenzunehmen und zu \u00fcbermitteln. Er sorgt f\u00fcr Schnittstellen zur Informations\u00fcbertragung, die Bildung logischer \u00dcbertragungskan\u00e4le innerhalb des Systems, Routing und Lastverteilung sowie die systemweite Fehlermanagement.<br \/>\nDas entwickelte Messaging-System soll nicht mit RabbitMQ konkurrieren oder es ersetzen. Seine Hauptmerkmale sind:<\/p>\n<p><\/p>\n<ul>\n<li>Dezentralisierung.<br \/>\nAustauschpunkte k\u00f6nnen an allen Knoten des Clusters erstellt werden, so nah wie m\u00f6glich am Code, der sie verwendet.<\/li>\n<li>Benutzerfreundlichkeit.<br \/>\nFokus auf Minimierung von Boilerplate-Code und Benutzerfreundlichkeit.<\/li>\n<li>Hervorragende Leistung.<br \/>\nWir versuchen nicht, die Funktionalit\u00e4t von RabbitMQ zu replizieren, sondern heben nur die Architektur- und Transportschicht hervor, die wir m\u00f6glichst einfach in OTP integrieren, um die Kosten zu minimieren.<\/li>\n<li>Flexibilit\u00e4t.<br \/>\nJeder Service kann zahlreiche Austauschmuster kombinieren.<\/li>\n<li>Fehlertoleranz, die in das Design integriert ist.<\/li>\n<li>Skalierbarkeit.<br \/>\nMessaging w\u00e4chst mit der Anwendung. Bei zunehmender Last k\u00f6nnen Austauschpunkte auf separate Maschinen verlagert werden.<\/li>\n<\/ul>\n<p><\/p>\n<p><em>Hinweis.<\/em> Aus Sicht der Code-Organisation sind Meta-Projekte f\u00fcr komplexe Systeme in Erlang\/Elixir gut geeignet. Der gesamte Projektcode befindet sich in einem Repository \u2013 einem \u00fcbergeordneten Projekt. Dabei sind Mikroservices maximal isoliert und f\u00fchren einfache Operationen aus, die eine separate Entit\u00e4t betreffen. Mit diesem Ansatz l\u00e4sst sich die API des gesamten Systems einfach warten, \u00c4nderungen sind leicht umzusetzen, und es ist bequem, Unit- und Integrationstests zu schreiben.<\/p>\n<p><\/p>\n<p>Die Komponenten des Systems interagieren direkt oder \u00fcber einen Broker. Aus der Perspektive des Messaging hat jeder Service mehrere Lebensphasen:<\/p>\n<p><\/p>\n<ul>\n<li>Initialisierung des Services.<br \/>\nIn dieser Phase erfolgt die Konfiguration und der Start des ausf\u00fchrenden Service-Prozesses und der Abh\u00e4ngigkeiten.<\/li>\n<li>Erstellung eines Austauschpunkts.<br \/>\nDer Service kann einen statischen Austauschpunkt verwenden, der in der Knoten-Config festgelegt ist, oder Austauschpunkte dynamisch erstellen. <\/li>\n<li>Registrierung des Services.<br \/>\nDamit der Service Anfragen bedienen kann, muss er am Austauschpunkt registriert werden.<\/li>\n<li>Normale Funktionalit\u00e4t.<br \/>\nDer Service f\u00fchrt n\u00fctzliche Arbeit aus.<\/li>\n<li>Beendigung der Arbeit.<br \/>\nEs sind zwei Arten des Herunterfahrens m\u00f6glich: regul\u00e4r und notfallm\u00e4\u00dfig. Bei einer regul\u00e4ren Abschaltung wird der Dienst vom Austauschpunkt getrennt und gestoppt. In Notf\u00e4llen f\u00fchrt das Messaging eines der Ausfallszenarien aus.<\/li>\n<\/ul>\n<p><\/p>\n<p>Es sieht ziemlich kompliziert aus, aber im Code ist nicht alles so schlimm. Beispielcodes mit Kommentaren werden im Template-Review etwas sp\u00e4ter bereitgestellt.<\/p>\n<p><\/p>\n<h2 id=\"exchanges\">Austausche<\/h2>\n<p><\/p>\n<p>Der Austauschpunkt ist ein Messaging-Prozess, der die Logik der Interaktion mit Komponenten im Rahmen des Nachrichtenaustausch-Templates implementiert. In allen unten pr\u00e4sentierten Beispielen interagieren die Komponenten \u00fcber Austauschpunkte, deren Kombination das Messaging bildet.<\/p>\n<p><\/p>\n<h2 id=\"message-exchange-patterns-meps\">Message Exchange Patterns (MEPs)<\/h2>\n<p><\/p>\n<p>Global betrachtet lassen sich Austausch-Templates in bidirektionale und unidirektionale unterteilen. Erstere unterstellen eine Antwort auf die empfangene Nachricht, letztere nicht. Ein klassisches Beispiel f\u00fcr ein bidirektionales Template in der Client-Server-Architektur ist das Anfrage-Antwort-Template. Lassen Sie uns das Template und seine Modifikationen betrachten.<\/p>\n<p><\/p>\n<h3 id=\"requestresponse-ili-rpc\">Anfrage-Antwort oder RPC<\/h3>\n<p><\/p>\n<p>RPC wird verwendet, wenn wir eine Antwort von einem anderen Prozess ben\u00f6tigen. Dieser Prozess kann auf demselben Knoten oder auf einem anderen Kontinent ausgef\u00fchrt werden. Im Folgenden finden Sie das Schema der Interaktion zwischen dem Client und <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/de\/server\/dts-los-angeles\/\"   title=\"Server\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"3483\">Server<\/a> \u00fcber Messaging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/091725fc108d6ce1a5fc9ae866e2c395.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Da Messaging vollst\u00e4ndig asynchron ist, wird der Austausch in zwei Phasen unterteilt f\u00fcr den Client:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Anfrage senden<\/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 ein einzigartiger Name f\u00fcr den Austausch<br \/>\n<em>ResponseMatchingTag<\/em> \u2012 ein lokales Tag zur Verarbeitung der Antwort. Zum Beispiel, wenn mehrere identische Anfragen gesendet werden, die verschiedenen Benutzern geh\u00f6ren.<br \/>\n<em>RequestDefinition<\/em> \u2012 der Inhalt der Anfrage<br \/>\n<em>HandlerProcess<\/em> \u2012 PID des Handlers. Dieser Prozess erh\u00e4lt die Antwort vom Server.<\/p>\n<p>\n<\/li>\n<li>\n<p>Antwortverarbeitung<\/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 die Serverantwort.<\/p>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>F\u00fcr den Server besteht der Prozess auch aus zwei Phasen:<\/p>\n<p><\/p>\n<ol>\n<li>Initialisierung des Austauschnodes<\/li>\n<li>Verarbeitung eingehender Anfragen<\/li>\n<\/ol>\n<p><\/p>\n<p>Veranschaulichen wir dieses Muster mit Code. Angenommen, wir m\u00fcssen einen einfachen Dienst implementieren, der eine einzige Methode zur genauen Zeit bereitstellt.<\/p>\n<p><\/p>\n<h4 id=\"kod-servera\">Servercode<\/h4>\n<p><\/p>\n<p>Lassen Sie uns die Definition der API des Dienstes in api.hrl auslagern:<\/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>Definieren Sie den Service-Controller in time_controller.erl<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% Das Beispiel zeigt nur den relevanten Code. Durch Einf\u00fcgen in die Vorlage gen_server kann ein funktionierender Service erstellt werden.\n\n%% Initialisierung von gen_server\ninit(Args) -&gt;\n  %% Verbindung zur Austauschstelle herstellen\n  messaging:monitor_exchange(req_resp, ?EXCHANGE, default, self())\n  {ok, #{}}.\n\n%% Verarbeitung des Ereignisses beim Verlust der Verbindung zur Austauschstelle. Dieses Ereignis wird auch gesendet, wenn die Austauschstelle noch nicht gestartet ist.\nhandle_info(#exchange_die{exchange = ?EXCHANGE}, State) -&gt;\n  erlang:send(self(), monitor_exchange),\n  {noreply, State};\n\n%% Verarbeitung der 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%% Beendigung des 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\">Client-Code<\/h4>\n<p><\/p>\n<p>Um eine Anfrage an den Service zu senden, kann in jedem Teil des Clients die Messaging-Request-API aufgerufen werden:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">Messaging-Anfrage: request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) von\n    ok -&gt; ok;\n    _ -&gt; %% Wiederhol- oder Fehlermeldung\nend<\/code><\/pre>\n<p><\/p>\n<p>In einem verteilten System kann die Konfiguration der Komponenten sehr unterschiedlich sein und zur Zeit der Messaging-Anfrage m\u00f6glicherweise noch nicht gestartet sein oder der Dienstcontroller ist m\u00f6glicherweise nicht bereit, die Anfrage zu bearbeiten. Daher m\u00fcssen wir die Antwort der Messaging \u00fcberpr\u00fcfen und den Fall eines Fehlers behandeln.<br \/>\nNach dem erfolgreichen Versand erh\u00e4lt der Kunde eine Antwort oder eine Fehlermeldung vom Dienst.<br \/>\nWir behandeln beide F\u00e4lle in 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\">Anfrage-Chunked Antwort<\/h3>\n<p><\/p>\n<p>Es ist besser, die \u00dcbertragung gro\u00dfer Nachrichten zu vermeiden. Das h\u00e4ngt von der Reaktionsf\u00e4higkeit und stabilen Funktionsweise des gesamten Systems ab. Wenn die Antwort auf eine Anfrage viel Speicher ben\u00f6tigt, ist eine Aufteilung in Teile erforderlich.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/bd60742a933a8e4e3eeaf7f4adf00f2a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ich werde ein paar Beispiele f\u00fcr solche F\u00e4lle anf\u00fchren:<\/p>\n<p><\/p>\n<ul>\n<li>Komponenten tauschen bin\u00e4re Daten aus, beispielsweise Dateien. Die Aufteilung der Antwort in kleine Teile hilft, effizient mit Dateien beliebiger Gr\u00f6\u00dfe zu arbeiten und \u00dcberl\u00e4ufe zu vermeiden.<\/li>\n<li>Listen. Zum Beispiel m\u00fcssen wir alle Eintr\u00e4ge aus einer gro\u00dfen Tabelle in der Datenbank ausw\u00e4hlen und an eine andere Komponente weiterleiten.<\/li>\n<\/ul>\n<p><\/p>\n<p>Ich nenne solche Antworten einen Zug. Auf jeden Fall sind 1024 Nachrichten mit je 1 MB besser als eine einzige Nachricht mit 1 GB. <\/p>\n<p><\/p>\n<p>In einem Erlang-Cluster erzielen wir einen zus\u00e4tzlichen Vorteil \u2012 die Belastung des Austauschpunktes und des Netzwerks wird reduziert, da die Antworten sofort an den Empf\u00e4nger gesendet werden, ohne den Austauschpunkt zu passieren.<\/p>\n<p><\/p>\n<h3 id=\"response-with-request\">Antwort mit Anfrage<\/h3>\n<p><\/p>\n<p>Das ist eine eher seltene Modifikation des RPC-Musters zur Erstellung dialogorientierter Systeme.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" 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 (Datenverteilungshierarchie)<\/h3>\n<p><\/p>\n<p>Ereignisgesteuerte Systeme liefern Daten an Verbraucher, sobald sie bereit sind. Dadurch tendieren die Systeme eher zu einem Push-Modell als zu Pull oder Poll. Diese Eigenschaft verhindert, dass Ressourcen verschwendet werden, indem st\u00e4ndig nach Daten gefragt und darauf gewartet wird.<br \/>\nDas Diagramm zeigt den Prozess der Nachrichtenverbreitung an Verbraucher, die sich auf ein bestimmtes Thema abonniert haben.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/e211d5dcfeb5ce8513699eac8e3b6d84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Klassische Beispiele f\u00fcr die Verwendung dieser Vorlage sind die Verbreitung des Zustands: der virtuelle Spielwelt in Computerspielen, der Marktdaten an B\u00f6rsen und n\u00fctzlicher Informationen in Data Feeds.<\/p>\n<p><\/p>\n<p>Betrachten wir den Code des Abonnenten:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">init(_Args) -&gt;\n  %% wir abonnieren den Broker, Schl\u00fcssel = key\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {ok, #{}}.\n\nhandle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) -&gt;\n  %% wenn der Broker nicht verf\u00fcgbar ist, versuchen wir Neuverbindung\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {noreply, State};\n\n%% Verarbeitung eingehender Nachrichten\nhandle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) -&gt;\n  ?debugVal(Msg),\n  {noreply, State};\n\n%% Bei Beendigung des Verbrauchers - Trennung vom Broker\nterminate(_Reason, _State) -&gt;\n  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p>Die Quelle kann die Funktion zur Ver\u00f6ffentlichung von Nachrichten an beliebiger Stelle aufrufen:<\/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 Name des Brokers,<br \/>\n<em>Schl\u00fcssel<\/em> \u2012 Routing-Schl\u00fcssel<br \/>\n<em>Nachricht<\/em> \u2012 Nutzlast<\/p>\n<p><\/p>\n<h2 id=\"inverted-publish-subscribe\">Umgekehrtes Ver\u00f6ffentlichen-Abonnieren<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/2ef7cd7de459455937bdcfa8a11fd028.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Durch die Implementierung von pub-sub kann ein Pattern erstellt werden, das sich gut f\u00fcr das Logging eignet. Die Kombination aus Quellen und Verbrauchern kann v\u00f6llig unterschiedlich sein. Im Bild ist ein Fall mit einem Verbraucher und vielen Quellen dargestellt.<\/p>\n<p><\/p>\n<h2 id=\"task-distribution-pattern\">Taskverteilungsmuster<\/h2>\n<p><\/p>\n<p>In nahezu jedem Projekt entstehen Aufgaben der verz\u00f6gerten Verarbeitung, wie die Erstellung von Berichten, die Zustellung von Benachrichtigungen und das Abrufen von Daten aus externen Systemen. Die Kapazit\u00e4t des Systems, das diese Aufgaben ausf\u00fchrt, l\u00e4sst sich leicht skalieren, indem weitere Bearbeiter hinzugef\u00fcgt werden. Alles, was wir tun m\u00fcssen, ist, einen Cluster von Bearbeitern zu bilden und die Aufgaben gleichm\u00e4\u00dfig zwischen ihnen zu verteilen.<\/p>\n<p><\/p>\n<p>Betrachten wir die auftretenden Situationen am Beispiel von 3 Bearbeitern. Bereits in der Phase der Aufgabenverteilung stellt sich die Frage nach der Fairness der Verteilung und der \u00dcberlastung der Bearbeiter. Die Fairness wird durch eine round-robin Verteilung gew\u00e4hrleistet, und um \u00dcberlastungen der Bearbeiter zu vermeiden, f\u00fchren wir eine Einschr\u00e4nkung ein <em>prefetch_limit<\/em>. In \u00dcbergangsmodi <em>prefetch_limit<\/em> wird kein Bearbeiter alle Aufgaben erhalten.<\/p>\n<p><\/p>\n<p>Messaging verwaltet die Warteschlangen und die Priorit\u00e4t der Verarbeitung. Bearbeiter erhalten die Aufgaben, sobald sie eintreffen. Die Ausf\u00fchrung einer Aufgabe kann erfolgreich abgeschlossen werden oder auch fehlschlagen:<\/p>\n<p><\/p>\n<ul>\n<li><code>messaging:ack(Tack)<\/code> \u2012 wird im Falle einer erfolgreichen Verarbeitung der Nachricht aufgerufen<\/li>\n<li><code>messaging:nack(Tack)<\/code> \u2012 wird in allen Notfallsituationen aufgerufen. Nach der R\u00fcckgabe der Aufgabe wird Messaging sie an einen anderen Handler \u00fcbergeben.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bausteine verteilter Anwendungen. Erste Ann\u00e4herung\" src=\"\/wp-content\/uploads\/2019\/04\/c2c632b6411247ee8b0dcfb3250a4503.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Angenommen, beim Verarbeiten von drei Aufgaben trat ein komplexer Fehler auf: Handler 1 ist nach Erhalt der Aufgabe abgest\u00fcrzt, ohne etwas an den Austauschpunkt zu melden. In diesem Fall wird der Austauschpunkt nach Ablauf des Ack-Timeouts die Aufgabe an einen anderen Handler \u00fcbergeben. Handler 3 hat aus irgendeinem Grund die Aufgabe abgelehnt und ein Nack gesendet, deswegen wurde die Aufgabe ebenfalls an einen anderen Handler \u00fcbergeben, der sie erfolgreich ausgef\u00fchrt hat.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnyy-itog\">Vorl\u00e4ufiges Fazit<\/h2>\n<p><\/p>\n<p>Wir haben die grundlegenden Bausteine verteilter Systeme betrachtet und ein grundlegendes Verst\u00e4ndnis ihrer Anwendung in Erlang\/Elixir gewonnen.<\/p>\n<p><\/p>\n<p>Durch die Kombination grundlegender Muster k\u00f6nnen komplexe Paradigmen zur L\u00f6sung auftretender Aufgaben entwickelt werden.<\/p>\n<p><\/p>\n<p>Im abschlie\u00dfenden Teil des Zyklus werden wir allgemeine Fragen zur Organisation von Diensten, Routing und Lastverteilung betrachten und \u00fcber die praktische Seite der Skalierbarkeit und Ausfallsicherheit von Systemen sprechen.<\/p>\n<p><\/p>\n<p>Ende des zweiten Teils.<\/p>\n<p><\/p>\n<p>Foto <noindex>Marius Christensen<\/noindex><br \/>\nIllustrationen erstellt mit websequencediagrams.com<\/p>\n<p>Quelle: <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 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\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\" \/>\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\/de\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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:description\" content=\"\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\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/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\udd47Bausteine verteilter Anwendungen. Erste Ann\u00e4herung | ProHoster","description":"In unserem letzten Artikel haben wir die theoretischen Grundlagen der reaktiven Architektur behandelt. Jetzt ist es an der Zeit, \u00fcber Datenstr\u00f6me, Implementierungsm\u00f6glichkeiten f\u00fcr reaktive Erlang\/Elixir-Systeme und die Messaging-Muster zu sprechen: Anfrage-Antwort, Anfrage-Chunked Antwort, Antwort mit Anfrage, Publish-Subscribe, Inverted Publish-Subscribe, Aufgabenverteilung. SOA und MSA definieren die Systemarchitekturen, die die Regeln f\u00fcr den Aufbau von Systemen bestimmen, w\u00e4hrend...","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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:description":"\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","og:url":"https:\/\/prohoster.info\/de\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/30908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=30908"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/30908\/revisions"}],"predecessor-version":[{"id":162009,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/30908\/revisions\/162009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/22886"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=30908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=30908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=30908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}