{"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\/fr\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","title":{"rendered":"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/7ef485e452075775ce317b557671274c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dans le pass\u00e9, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">article<\/a><\/noindex> Nous avons explor\u00e9 les bases th\u00e9oriques de l'architecture r\u00e9active. Il est temps de discuter des flux de donn\u00e9es, des m\u00e9thodes de mise en \u0153uvre des syst\u00e8mes Erlang\/Elixir r\u00e9actifs et des mod\u00e8les d'\u00e9change de messages qui les sous-tendent :<\/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 et \u00e9change de messages<\/h2>\n<p><\/p>\n<p>SOA et MSA sont des architectures syst\u00e8mes qui d\u00e9finissent les r\u00e8gles de construction des syst\u00e8mes, tandis que le messaging fournit les primitives pour leur mise en \u0153uvre.<\/p>\n<p><\/p>\n<p>Je ne souhaite pas promouvoir une architecture syst\u00e8me plut\u00f4t qu'une autre. Je pr\u00f4ne l'utilisation de pratiques maximales et utiles pour un projet et une entreprise sp\u00e9cifiques. Quelle que soit la paradigme choisie, il est pr\u00e9f\u00e9rable de construire des blocs syst\u00e8mes en gardant \u00e0 l'esprit l'approche Unix : des composants avec un couplage minimal, responsables d'entit\u00e9s sp\u00e9cifiques. Les m\u00e9thodes API effectuent des actions aussi simples que possible sur les entit\u00e9s.<\/p>\n<p><\/p>\n<p>Le messaging, comme son nom l'indique, est un courtier de messages. Son objectif principal est de recevoir et d'envoyer des messages. Il est responsable des interfaces de transmission d'informations, de la formation de canaux logiques de transmission au sein du syst\u00e8me, du routage et de l'\u00e9quilibrage, ainsi que du traitement des pannes au niveau syst\u00e8me.<br \/>\nLe messaging en d\u00e9veloppement ne cherche pas \u00e0 concurrencer rabbitmq ou \u00e0 le remplacer. Ses principales caract\u00e9ristiques sont :<\/p>\n<p><\/p>\n<ul>\n<li>Distribution.<br \/>\nLes points d'\u00e9change peuvent \u00eatre cr\u00e9\u00e9s sur tous les n\u0153uds du cluster, aussi pr\u00e8s que possible du code qui les utilise.<\/li>\n<li>Simplicit\u00e9.<br \/>\nOrient\u00e9 sur la minimisation du code standard et la facilit\u00e9 d'utilisation.<\/li>\n<li>Meilleure performance.<br \/>\nNous ne tentons pas de r\u00e9pliquer la fonctionnalit\u00e9 de rabbitmq, mais mettons en avant uniquement la couche architecturale et de transport, que nous int\u00e9grons simplement dans l'OTP, minimisant les co\u00fbts.<\/li>\n<li>Flexibilit\u00e9.<br \/>\nChaque service peut combiner plusieurs mod\u00e8les d'\u00e9change.<\/li>\n<li>R\u00e9silience, int\u00e9gr\u00e9e dans le design.<\/li>\n<li>Scalabilit\u00e9.<br \/>\nLe messaging \u00e9volue avec l'application. \u00c0 mesure que la charge augmente, les points d'\u00e9change peuvent \u00eatre d\u00e9plac\u00e9s sur des machines s\u00e9par\u00e9es.<\/li>\n<\/ul>\n<p><\/p>\n<p><em>Remarque.<\/em> En termes d'organisation du code, les m\u00e9ta-projets conviennent bien pour les syst\u00e8mes complexes en Erlang\/Elixir. Tout le code du projet est situ\u00e9 dans un seul r\u00e9f\u00e9rentiel \u2012 un projet umbrella. Dans ce cadre, les microservices sont maximement isol\u00e9s et effectuent des op\u00e9rations simples, responsables d'une entit\u00e9 distincte. Avec cette approche, il est facile de maintenir l'API de l'ensemble du syst\u00e8me, d'apporter des modifications simplement et d'\u00e9crire facilement des tests unitaires et d'int\u00e9gration.<\/p>\n<p><\/p>\n<p>Les composants du syst\u00e8me interagissent directement ou via un courtier. Du point de vue du messaging, chaque service a plusieurs phases de vie :<\/p>\n<p><\/p>\n<ul>\n<li>Initialisation du service.<br \/>\n\u00c0 ce stade, la configuration et le d\u00e9marrage du processus d'ex\u00e9cution du service et de ses d\u00e9pendances ont lieu.<\/li>\n<li>Cr\u00e9ation d'un point d'\u00e9change.<br \/>\nLe service peut utiliser un point d'\u00e9change statique d\u00e9fini dans la configuration du n\u0153ud, ou cr\u00e9er des points d'\u00e9change dynamiquement. <\/li>\n<li>Enregistrement du service.<br \/>\nPour que le service puisse traiter des requ\u00eates, il doit \u00eatre enregistr\u00e9 au point d'\u00e9change.<\/li>\n<li>Fonctionnement normal.<br \/>\nLe service effectue un travail utile.<\/li>\n<li>Fin de service.<br \/>\nIl existe 2 types de fin de service : ordinaire et exceptionnel. Dans le cas ordinaire, le service se d\u00e9connecte du point d'\u00e9change et s'arr\u00eate. En cas de situations d'urgence, le messaging ex\u00e9cute l'un des sc\u00e9narios de traitement des pannes.<\/li>\n<\/ul>\n<p><\/p>\n<p>Cela peut sembler complexe, mais dans le code, ce n'est pas si effrayant. Des exemples de code avec des commentaires seront fournis dans l'analyse des mod\u00e8les un peu plus tard.<\/p>\n<p><\/p>\n<h2 id=\"exchanges\">Exchanges<\/h2>\n<p><\/p>\n<p>Le point d'\u00e9change \u2012 processus de messaging, r\u00e9alisant la logique d'interaction avec les composants dans le cadre du mod\u00e8le d'\u00e9change de messages. Dans tous les exemples pr\u00e9sent\u00e9s ci-dessous, les composants interagissent via des points d'\u00e9change, dont la combinaison forme le messaging.<\/p>\n<p><\/p>\n<h2 id=\"message-exchange-patterns-meps\">Mod\u00e8les d'\u00e9change de messages (MEPs)<\/h2>\n<p><\/p>\n<p>Globalement, les mod\u00e8les d'\u00e9change peuvent \u00eatre class\u00e9s en bidirectionnels et unidirectionnels. Les premiers impliquent une r\u00e9ponse au message re\u00e7u, tandis que les seconds non. Un exemple classique de mod\u00e8le bidirectionnel dans l'architecture client-serveur est le mod\u00e8le Request-response. Examinons le mod\u00e8le et ses modifications.<\/p>\n<p><\/p>\n<h3 id=\"requestresponse-ili-rpc\">Request-response ou RPC<\/h3>\n<p><\/p>\n<p>Le RPC est utilis\u00e9 lorsque nous avons besoin d'obtenir une r\u00e9ponse d'un autre processus. Ce processus peut \u00eatre ex\u00e9cut\u00e9 sur le m\u00eame n\u0153ud ou se trouver sur un autre continent. Ci-dessous, un sch\u00e9ma d'interaction entre le client et <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/fr\/server\/dts-los-angeles\/\"   title=\"de serveurs\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"3483\">de serveurs<\/a> via messaging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/091725fc108d6ce1a5fc9ae866e2c395.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Puisque le messaging est enti\u00e8rement asynchrone, pour le client, l'\u00e9change se divise en 2 phases :<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Envoi de la requ\u00eate<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).<\/code><\/pre>\n<p><\/p>\n<p><em>\u00c9change<\/em> \u2012 nom unique du point d'\u00e9change<br \/>\n<em>ResponseMatchingTag<\/em> \u2012 \u00e9tiquette locale pour le traitement de la r\u00e9ponse. Par exemple, dans le cas de l'envoi de plusieurs requ\u00eates identiques appartenant \u00e0 diff\u00e9rents utilisateurs.<br \/>\n<em>RequestDefinition<\/em> \u2012 corps de la requ\u00eate<br \/>\n<em>HandlerProcess<\/em> \u2012 PID du gestionnaire. Ce processus recevra la r\u00e9ponse du serveur.<\/p>\n<p>\n<\/li>\n<li>\n<p>Traitement de la r\u00e9ponse<\/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 r\u00e9ponse du serveur.<\/p>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Pour le serveur, le processus se compose \u00e9galement de 2 phases :<\/p>\n<p><\/p>\n<ol>\n<li>Initialisation du point d'\u00e9change<\/li>\n<li>Traitement des requ\u00eates entrantes<\/li>\n<\/ol>\n<p><\/p>\n<p>Illustrons ce mod\u00e8le par du code. Supposons que nous devions impl\u00e9menter un service simple fournissant une m\u00e9thode pour obtenir l'heure exacte.<\/p>\n<p><\/p>\n<h4 id=\"kod-servera\">Code du serveur<\/h4>\n<p><\/p>\n<p>D\u00e9pla\u00e7ons la d\u00e9finition de l'API du service dans api.hrl :<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% =====================================================\n%%  entit\u00e9s\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%%  m\u00e9thodes\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>D\u00e9finissons le contr\u00f4leur du service dans time_controller.erl<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% L'exemple montre seulement le code significatif. En l'ins\u00e9rant dans le mod\u00e8le gen_server, vous pouvez obtenir un service fonctionnel.\n\n%% initialisation du gen_server\ninit(Args) -&gt;\n  %% connexion au point d'\u00e9change\n  messaging:monitor_exchange(req_resp, ?EXCHANGE, default, self())\n  {ok, #{}}.\n\n%% traitement de l'\u00e9v\u00e9nement de perte de connexion avec le point d'\u00e9change. Cet \u00e9v\u00e9nement se produit \u00e9galement si le point d'\u00e9change n'a pas encore d\u00e9marr\u00e9.\nhandle_info(#exchange_die{exchange = ?EXCHANGE}, State) -&gt;\n  erlang:send(self(), monitor_exchange),\n  {noreply, State};\n\n%% traitement de l'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%% fin de travail du 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\">Code client<\/h4>\n<p><\/p>\n<p>Pour envoyer une requ\u00eate au service, vous pouvez appeler l'API de requ\u00eate messaging de n'importe quel endroit du client :<\/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; %% logique de r\u00e9p\u00e9tition ou d'\u00e9chec\nend<\/code><\/pre>\n<p><\/p>\n<p>Dans un syst\u00e8me distribu\u00e9, la configuration des composants peut \u00eatre tr\u00e8s vari\u00e9e et, au moment de la requ\u00eate, messaging peut ne pas encore \u00eatre en cours d'ex\u00e9cution, ou le contr\u00f4leur du service peut ne pas \u00eatre pr\u00eat \u00e0 traiter la requ\u00eate. Il est donc n\u00e9cessaire de v\u00e9rifier la r\u00e9ponse de messaging et de g\u00e9rer le cas d'\u00e9chec.<br \/>\nApr\u00e8s l'envoi r\u00e9ussi, le service renverra une r\u00e9ponse ou une erreur au client.<br \/>\nTraitons les deux cas dans 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>Il est pr\u00e9f\u00e9rable d'\u00e9viter de transmettre d'\u00e9normes messages. Cela affecte la r\u00e9activit\u00e9 et la stabilit\u00e9 de l'ensemble du syst\u00e8me. Si la r\u00e9ponse \u00e0 une demande occupe beaucoup de m\u00e9moire, il est n\u00e9cessaire de la diviser en parties.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/bd60742a933a8e4e3eeaf7f4adf00f2a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Je vais donner quelques exemples de ces cas:<\/p>\n<p><\/p>\n<ul>\n<li>Les composants \u00e9changent des donn\u00e9es binaires, comme des fichiers. Diviser la r\u00e9ponse en petites parties permet de traiter efficacement les fichiers de toute taille, sans provoquer de d\u00e9bordement de m\u00e9moire.<\/li>\n<li>Listages. Par exemple, nous devons s\u00e9lectionner toutes les entr\u00e9es d'une immense table dans la base de donn\u00e9es et les transmettre \u00e0 un autre composant.<\/li>\n<\/ul>\n<p><\/p>\n<p>J'appelle ces r\u00e9ponses des trains. En tout cas, 1024 messages de 1 Mo sont pr\u00e9f\u00e9rables \u00e0 un seul message de 1 Go. <\/p>\n<p><\/p>\n<p>Dans un cluster Erlang, nous obtenons un avantage suppl\u00e9mentaire - une r\u00e9duction de la charge sur le point d'\u00e9change et le r\u00e9seau, car les r\u00e9ponses sont imm\u00e9diatement envoy\u00e9es au destinataire, contournant le point d'\u00e9change.<\/p>\n<p><\/p>\n<h3 id=\"response-with-request\">Response with Request<\/h3>\n<p><\/p>\n<p>C'est une modification plut\u00f4t rare du mod\u00e8le RPC pour construire des syst\u00e8mes de dialogue.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" 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\">Publication-abonnement (arbre de distribution de donn\u00e9es)<\/h3>\n<p><\/p>\n<p>Les syst\u00e8mes orient\u00e9s \u00e9v\u00e9nements livrent les donn\u00e9es aux consommateurs d\u00e8s qu'elles sont pr\u00eates. Ainsi, les syst\u00e8mes sont plus enclins \u00e0 un mod\u00e8le de push qu'\u00e0 un mod\u00e8le de pull ou de poll. Cette caract\u00e9ristique \u00e9vite de gaspiller des ressources en interrogeant constamment et en attendant des donn\u00e9es.<br \/>\nLe diagramme illustre le processus de diffusion d'un message aux consommateurs abonn\u00e9s \u00e0 un sujet particulier.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/e211d5dcfeb5ce8513699eac8e3b6d84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Des exemples classiques de l'utilisation de ce mod\u00e8le incluent la diffusion de l'\u00e9tat : monde de jeu dans les jeux vid\u00e9o, donn\u00e9es de march\u00e9 sur les bourses, informations utiles dans les flux de donn\u00e9es.<\/p>\n<p><\/p>\n<p>Examinons le code du souscripteur :<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">init(_Args) -&gt;\n  %% nous nous abonnissons \u00e0 l'\u00e9change, cl\u00e9 = key\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {ok, #{}}.\n\nhandle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) -&gt;\n  %% si le point d'\u00e9change n'est pas disponible, nous essayons de nous reconnecter\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {noreply, State};\n\n%% nous traitons les messages re\u00e7us\nhandle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) -&gt;\n  ?debugVal(Msg),\n  {noreply, State};\n\n%% lors de l'arr\u00eat du consommateur - nous nous d\u00e9connectons du point d'\u00e9change\nterminate(_Reason, _State) -&gt;\n  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p>La source peut appeler la fonction de publication de message \u00e0 tout moment :<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">messaging:publish_message(Exchange, Key, Message).<\/code><\/pre>\n<p><\/p>\n<p><em>\u00c9change<\/em> \u2012 nom du point d'\u00e9change,<br \/>\n<em>Cl\u00e9<\/em> \u2012 cl\u00e9 de routage<br \/>\n<em>Message<\/em> \u2012 charge utile<\/p>\n<p><\/p>\n<h2 id=\"inverted-publish-subscribe\">Inverted Publish-subscribe<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/2ef7cd7de459455937bdcfa8a11fd028.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En d\u00e9ployant pub-sub, on peut obtenir un mod\u00e8le pratique pour la journalisation. L'ensemble des sources et des consommateurs peut \u00eatre compl\u00e8tement diff\u00e9rent. L'illustration montre un cas avec un seul consommateur et plusieurs sources.<\/p>\n<p><\/p>\n<h2 id=\"task-distribution-pattern\">Mod\u00e8le de distribution de t\u00e2ches<\/h2>\n<p><\/p>\n<p>Dans presque chaque projet, des t\u00e2ches de traitement diff\u00e9r\u00e9 se pr\u00e9sentent, telles que la g\u00e9n\u00e9ration de rapports, l'envoi de notifications, ou l'acquisition de donn\u00e9es depuis des syst\u00e8mes tiers. La capacit\u00e9 du syst\u00e8me ex\u00e9cutant ces t\u00e2ches peut \u00eatre facilement \u00e9volu\u00e9e en ajoutant des gestionnaires. Tout ce qu'il nous reste \u00e0 faire, c'est de former un cluster de gestionnaires et de r\u00e9partir \u00e9quitablement les t\u00e2ches entre eux.<\/p>\n<p><\/p>\n<p>Consid\u00e9rons les situations qui se pr\u00e9sentent avec 3 gestionnaires. D\u00e8s la phase de r\u00e9partition des t\u00e2ches, la question de l'\u00e9quit\u00e9 de la distribution et de la surcharge des gestionnaires se pose. L'\u00e9quit\u00e9 sera g\u00e9r\u00e9e par une distribution round-robin, et pour \u00e9viter la saturation des gestionnaires, nous introduirons une limite <em>prefetch_limit<\/em>. En modes transitoires, <em>prefetch_limit<\/em> cela emp\u00eachera un gestionnaire de recevoir toutes les t\u00e2ches.<\/p>\n<p><\/p>\n<p>Messaging g\u00e8re les files d'attente et la priorit\u00e9 de traitement. Les gestionnaires re\u00e7oivent les t\u00e2ches au fur et \u00e0 mesure de leur arriv\u00e9e. L'ex\u00e9cution d'une t\u00e2che peut se terminer par un succ\u00e8s ou un \u00e9chec :<\/p>\n<p><\/p>\n<ul>\n<li><code>messaging:ack(Tack)<\/code> \u2012 est appel\u00e9 en cas de traitement r\u00e9ussi du message<\/li>\n<li><code>messaging:nack(Tack)<\/code> \u2012 est appel\u00e9 dans toutes les situations anormales. Apr\u00e8s le retour d'une t\u00e2che, messaging la transmettra \u00e0 un autre gestionnaire.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Les blocs de construction des applications distribu\u00e9es. Premi\u00e8re approche\" src=\"\/wp-content\/uploads\/2019\/04\/c2c632b6411247ee8b0dcfb3250a4503.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Supposons qu'en traitant trois t\u00e2ches, une d\u00e9faillance complexe se soit produite : le gestionnaire 1 est tomb\u00e9 apr\u00e8s avoir re\u00e7u une t\u00e2che, sans avoir eu le temps de communiquer quoi que ce soit au point d'\u00e9change. Dans ce cas, le point d'\u00e9change, apr\u00e8s le d\u00e9passement du d\u00e9lai d'ack, transmettra la t\u00e2che \u00e0 un autre gestionnaire. Le gestionnaire 3 a refus\u00e9 la t\u00e2che pour une raison quelconque et a envoy\u00e9 un nack, en cons\u00e9quence, la t\u00e2che a \u00e9galement \u00e9t\u00e9 transf\u00e9r\u00e9e \u00e0 un autre gestionnaire qui l'a ex\u00e9cut\u00e9e avec succ\u00e8s.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnyy-itog\">Bilan pr\u00e9liminaire<\/h2>\n<p><\/p>\n<p>Nous avons pass\u00e9 en revue les principaux \u00e9l\u00e9ments des syst\u00e8mes distribu\u00e9s et avons acquis une compr\u00e9hension de base de leur application en Erlang\/Elixir.<\/p>\n<p><\/p>\n<p>En combinant des mod\u00e8les de base, on peut construire des paradigmes complexes pour r\u00e9soudre les t\u00e2ches \u00e9mergentes.<\/p>\n<p><\/p>\n<p>Dans la derni\u00e8re partie de la s\u00e9rie, nous aborderons les questions g\u00e9n\u00e9rales sur l'organisation des services, le routage et l'\u00e9quilibrage, ainsi que la partie pratique de la scalabilit\u00e9 et de la r\u00e9silience des syst\u00e8mes.<\/p>\n<p><\/p>\n<p>Fin de la deuxi\u00e8me partie.<\/p>\n<p><\/p>\n<p>Photo <noindex>Marius Christensen<\/noindex><br \/>\nLes illustrations ont \u00e9t\u00e9 r\u00e9alis\u00e9es avec websequencediagrams.com<\/p>\n<p>Source : <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.2 - 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\/fr\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\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\/fr\/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\udd47Les \u00e9l\u00e9ments fondamentaux des applications distribu\u00e9es. Premi\u00e8re approche | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","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\/fr\/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\/fr\/wp-json\/wp\/v2\/posts\/30908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=30908"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/30908\/revisions"}],"predecessor-version":[{"id":162009,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/30908\/revisions\/162009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/22886"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=30908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=30908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=30908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}