{"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\/pt\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","title":{"rendered":"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/7ef485e452075775ce317b557671274c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na parte anterior <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">artigo<\/a><\/noindex> Analisamos as bases te\u00f3ricas da arquitetura reativa. \u00c9 hora de falar sobre fluxos de dados, formas de implementa\u00e7\u00e3o de sistemas reativos Erlang\/Elixir e padr\u00f5es de troca de mensagens neles:<\/p>\n<p><\/p>\n<ul>\n<li>Resposta de requisi\u00e7\u00e3o<\/li>\n<li>Resposta de requisi\u00e7\u00e3o em peda\u00e7os<\/li>\n<li>Resposta com requisi\u00e7\u00e3o<\/li>\n<li>Publicar-assinar<\/li>\n<li>Publica\u00e7\u00e3o-assinatura invertida<\/li>\n<li>Distribui\u00e7\u00e3o de tarefas<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"soa-msa-i-obmen-soobscheniyami\">SOA, MSA e troca de mensagens<\/h2>\n<p><\/p>\n<p>SOA e MSA s\u00e3o arquiteturas de sistemas que definem as regras para a constru\u00e7\u00e3o de sistemas, enquanto a troca de mensagens fornece os primitivos para a sua implementa\u00e7\u00e3o.<\/p>\n<p><\/p>\n<p>N\u00e3o quero promover uma ou outra arquitetura para a constru\u00e7\u00e3o de sistemas. Eu defendo a aplica\u00e7\u00e3o das pr\u00e1ticas mais eficientes e \u00fateis para um projeto e neg\u00f3cio espec\u00edficos. Independentemente da paradigma que escolhermos, \u00e9 melhor criar blocos de sistemas com a vis\u00e3o do modo Unix: componentes com baixa acoplamento, respons\u00e1veis por entidades individuais. Os m\u00e9todos da API executam as a\u00e7\u00f5es mais simples poss\u00edveis com entidades.<\/p>\n<p><\/p>\n<p>Messaging \u2012 como o nome sugere \u2012 \u00e9 um broker de mensagens. Seu objetivo principal \u00e9 receber e enviar mensagens. Ele \u00e9 respons\u00e1vel pelas interfaces de envio de informa\u00e7\u00f5es, forma\u00e7\u00e3o de canais l\u00f3gicos de transmiss\u00e3o de informa\u00e7\u00f5es dentro do sistema, roteamento e balanceamento, bem como no tratamento de falhas em n\u00edvel de sistema.<br \/>\nO messaging em desenvolvimento n\u00e3o tenta competir com o rabbitmq ou substitu\u00ed-lo. Suas principais caracter\u00edsticas s\u00e3o:<\/p>\n<p><\/p>\n<ul>\n<li>Distribui\u00e7\u00e3o.<br \/>\nPontos de troca podem ser criados em todos os n\u00f3s do cluster, o mais pr\u00f3ximo poss\u00edvel do c\u00f3digo que os utiliza.<\/li>\n<li>Simplicidade.<br \/>\nFoco na minimiza\u00e7\u00e3o de c\u00f3digo padr\u00e3o e facilidade de uso.<\/li>\n<li>Melhor desempenho.<br \/>\nN\u00e3o tentamos replicar a funcionalidade do rabbitmq, mas destacamos apenas a camada arquitet\u00f4nica e de transporte, que se integra da maneira mais simples poss\u00edvel no OTP, minimizando os custos.<\/li>\n<li>Flexibilidade.<br \/>\nCada servi\u00e7o pode incorporar v\u00e1rios padr\u00f5es de troca.<\/li>\n<li>Resili\u00eancia, incorporada ao design.<\/li>\n<li>Escalabilidade.<br \/>\nO messaging cresce junto com a aplica\u00e7\u00e3o. \u00c0 medida que a carga aumenta, os pontos de troca podem ser movidos para m\u00e1quinas separadas.<\/li>\n<\/ul>\n<p><\/p>\n<p><em>Observa\u00e7\u00e3o.<\/em> Do ponto de vista da organiza\u00e7\u00e3o do c\u00f3digo, meta-projetos s\u00e3o bem adequados para sistemas complexos em Erlang\/Elixir. Todo o c\u00f3digo do projeto est\u00e1 em um \u00fanico reposit\u00f3rio \u2012 projeto sombrinha. Os microsservi\u00e7os, por sua vez, s\u00e3o maximizados em isolamento e realizam opera\u00e7\u00f5es simples, respons\u00e1veis por uma entidade separada. Com essa abordagem, \u00e9 f\u00e1cil manter a API de todo o sistema, realizar altera\u00e7\u00f5es de forma simples e escrever testes unit\u00e1rios e de integra\u00e7\u00e3o de forma conveniente.<\/p>\n<p><\/p>\n<p>Os componentes do sistema interagem diretamente ou via um broker. Do ponto de vista de messaging, cada servi\u00e7o possui v\u00e1rias fases de vida:<\/p>\n<p><\/p>\n<ul>\n<li>Inicializa\u00e7\u00e3o do servi\u00e7o.<br \/>\nNesta fase, ocorre a configura\u00e7\u00e3o e o in\u00edcio do processo de execu\u00e7\u00e3o do servi\u00e7o e suas depend\u00eancias.<\/li>\n<li>Cria\u00e7\u00e3o de um ponto de troca.<br \/>\nO servi\u00e7o pode usar um ponto de troca est\u00e1tico, definido na configura\u00e7\u00e3o do n\u00f3, ou criar pontos de troca dinamicamente. <\/li>\n<li>Registro do servi\u00e7o.<br \/>\nPara que o servi\u00e7o possa atender a solicita\u00e7\u00f5es, ele precisa ser registrado no ponto de troca.<\/li>\n<li>Funcionamento normal.<br \/>\nO servi\u00e7o realiza trabalho \u00fatil.<\/li>\n<li>Finaliza\u00e7\u00e3o do trabalho.<br \/>\nExistem 2 tipos de finaliza\u00e7\u00e3o: normal e an\u00f4mala. Na finaliza\u00e7\u00e3o normal, o servi\u00e7o se desconecta do ponto de troca e \u00e9 interrompido. Em casos an\u00f4malos, o messaging executa um dos cen\u00e1rios de tratamento de falhas.<\/li>\n<\/ul>\n<p><\/p>\n<p>Parece bastante complexo, mas no c\u00f3digo n\u00e3o \u00e9 t\u00e3o assustador. Exemplos de c\u00f3digo com coment\u00e1rios ser\u00e3o apresentados na an\u00e1lise dos templates um pouco mais adiante.<\/p>\n<p><\/p>\n<h2 id=\"exchanges\">Exchanges<\/h2>\n<p><\/p>\n<p>O ponto de troca \u00e9 um processo de messaging que implementa a l\u00f3gica de intera\u00e7\u00e3o com os componentes dentro do template de troca de mensagens. Em todos os exemplos apresentados abaixo, os componentes interagem atrav\u00e9s de pontos de troca, cuja combina\u00e7\u00e3o forma o messaging.<\/p>\n<p><\/p>\n<h2 id=\"message-exchange-patterns-meps\">Message exchange patterns (MEPs)<\/h2>\n<p><\/p>\n<p>Globalmente, os templates de troca podem ser divididos em bidirecionais e unidirecionais. Os primeiros implicam uma resposta \u00e0 mensagem recebida, enquanto os segundos n\u00e3o. Um exemplo cl\u00e1ssico de template bidirecional na arquitetura cliente-servidor \u00e9 o template Request-response. Vamos considerar este template e suas modifica\u00e7\u00f5es.<\/p>\n<p><\/p>\n<h3 id=\"requestresponse-ili-rpc\">Request\u2013response ou RPC<\/h3>\n<p><\/p>\n<p>RPC \u00e9 utilizado quando precisamos obter uma resposta de outro processo. Esse processo pode estar em execu\u00e7\u00e3o no mesmo n\u00f3 ou em outro continente. Abaixo est\u00e1 o diagrama de intera\u00e7\u00e3o entre o cliente e <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/pt\/server\/dts-los-angeles\/\"   title=\"servidor\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"3483\">servidor<\/a> via messaging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/091725fc108d6ce1a5fc9ae866e2c395.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como o messaging \u00e9 completamente ass\u00edncrono, a troca \u00e9 dividida em 2 fases para o cliente:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Envio de solicita\u00e7\u00e3o<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">mensageria:pedido(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).<\/code><\/pre>\n<p><\/p>\n<p><em>Exchange<\/em> \u2012 nome \u00fanico do ponto de troca<br \/>\n<em>ResponseMatchingTag<\/em> \u2012 etiqueta local para o processamento da resposta. Por exemplo, ao enviar v\u00e1rias solicita\u00e7\u00f5es iguais pertencentes a diferentes usu\u00e1rios.<br \/>\n<em>RequestDefinition<\/em> \u2012 corpo da solicita\u00e7\u00e3o<br \/>\n<em>HandlerProcess<\/em> \u2012 PID do manipulador. Esta \u00e9 a inst\u00e2ncia que receber\u00e1 a resposta do servidor.<\/p>\n<p>\n<\/li>\n<li>\n<p>Processamento da resposta<\/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 resposta do servidor.<\/p>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Para o servidor, o processo consiste em 2 fases:<\/p>\n<p><\/p>\n<ol>\n<li>Inicializa\u00e7\u00e3o do ponto de troca<\/li>\n<li>Processamento das solicita\u00e7\u00f5es recebidas<\/li>\n<\/ol>\n<p><\/p>\n<p>Vamos ilustrar este modelo com c\u00f3digo. Suponha que precisamos implementar um servi\u00e7o simples que fornece um \u00fanico m\u00e9todo para obter a hora exata.<\/p>\n<p><\/p>\n<h4 id=\"kod-servera\">C\u00f3digo do servidor<\/h4>\n<p><\/p>\n<p>Vamos extrair a defini\u00e7\u00e3o da API do servi\u00e7o para api.hrl:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% =====================================================\n%%  entidades\n%% =====================================================\n-gravar(time, {\n  unixtime :: inteiro_nao_negativo(),\n  datetime :: bin\u00e1rio()\n}).\n\n-gravar(time_error, {\n  code :: inteiro_nao_negativo(),\n  erro :: termo()\n}).\n\n%% =====================================================\n%%  m\u00e9todos\n%% =====================================================\n-gravar(time_req, {\n  opts :: termo()\n}).\n-gravar(time_resp, {\n  resultado :: #time{} | #time_error{}\n}).<\/code><\/pre>\n<p><\/p>\n<p>Definiremos o controlador do servi\u00e7o em time_controller.erl<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% O exemplo mostra apenas o c\u00f3digo significativo. Inserindo-o no modelo gen_server podemos obter um servi\u00e7o funcional.\n\n%% inicializa\u00e7\u00e3o do gen_server\ninit(Args) -&gt;\n  %% conex\u00e3o ao ponto de troca\n  mensageria:monitor_exchange(req_resp, ?EXCHANGE, default, self())\n  {ok, #{}}.\n\n%% processamento do evento de perda de conex\u00e3o com o ponto de troca. Este mesmo evento chega se o ponto de troca ainda n\u00e3o tiver sido iniciado.\nhandle_info(#exchange_die{exchange = ?EXCHANGE}, State) -&gt;\n  erlang:send(self(), monitor_exchange),\n  {noreply, State};\n\n%% processamento da API\nhandle_info(#time_req{opts = _Opts}, State) -&gt;\n  mensageria:response_once(Client, #time_resp{\nresultado = #time{ unixtime = time_utils:unixtime(now()), datetime = time_utils:iso8601_fmt(now())}\n  });\n  {noreply, State};\n\n%% finaliza\u00e7\u00e3o do gen_server\nterminate(_Reason, _State) -&gt;\n  mensageria:demonitor_exchange(req_resp, ?EXCHANGE, default, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<h4 id=\"kod-klienta\">C\u00f3digo do cliente<\/h4>\n<p><\/p>\n<p>Para enviar uma solicita\u00e7\u00e3o ao servi\u00e7o, em qualquer lugar do cliente, voc\u00ea pode chamar a API de pedido da mensageria:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">caso mensageria:request(?EXCHANGE, tag, #time_req{opts = #{}} , self()) do\n    ok -&gt; ok;\n    _ -&gt; %% l\u00f3gica de repeti\u00e7\u00e3o ou falha\nfim<\/code><\/pre>\n<p><\/p>\n<p>Em um sistema distribu\u00eddo, a configura\u00e7\u00e3o dos componentes pode ser variada e, no momento da solicita\u00e7\u00e3o, a mensageria pode ainda n\u00e3o ter iniciado ou o controlador do servi\u00e7o pode n\u00e3o estar pronto para atender \u00e0 solicita\u00e7\u00e3o. Portanto, precisamos verificar a resposta da mensageria e tratar o caso de falha.<br \/>\nAp\u00f3s o envio bem-sucedido, o cliente receber\u00e1 uma resposta ou um erro do servi\u00e7o.<br \/>\nVamos lidar com ambos os casos em 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\">Resposta de requisi\u00e7\u00e3o em peda\u00e7os<\/h3>\n<p><\/p>\n<p>\u00c9 melhor evitar o envio de mensagens grandes. Isso afeta a responsividade e a estabilidade de todo o sistema. Se a resposta a uma solicita\u00e7\u00e3o ocupa muita mem\u00f3ria, a fragmenta\u00e7\u00e3o em partes \u00e9 obrigat\u00f3ria.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/bd60742a933a8e4e3eeaf7f4adf00f2a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vou dar alguns exemplos desses casos:<\/p>\n<p><\/p>\n<ul>\n<li>Os componentes trocam dados bin\u00e1rios, como arquivos. Dividir a resposta em partes menores ajuda a trabalhar eficientemente com arquivos de qualquer tamanho e evita estouros de mem\u00f3ria.<\/li>\n<li>Listagens. Por exemplo, precisamos selecionar todos os registros de uma enorme tabela no banco e passar para outro componente.<\/li>\n<\/ul>\n<p><\/p>\n<p>Eu chamo essas respostas de locomotivas. De qualquer forma, 1024 mensagens de 1 MB s\u00e3o melhores do que uma \u00fanica mensagem de 1 GB. <\/p>\n<p><\/p>\n<p>Em um cluster Erlang, obtemos um ganho adicional \u2012 diminui\u00e7\u00e3o da carga no ponto de troca e na rede, j\u00e1 que as respostas s\u00e3o enviadas diretamente ao destinat\u00e1rio, ignorando o ponto de troca.<\/p>\n<p><\/p>\n<h3 id=\"response-with-request\">Resposta com requisi\u00e7\u00e3o<\/h3>\n<p><\/p>\n<p>Esta \u00e9 uma modifica\u00e7\u00e3o bastante rara do padr\u00e3o RPC para construir sistemas de di\u00e1logo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" 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\">Publicar-assinar (\u00e1rvore de distribui\u00e7\u00e3o de dados)<\/h3>\n<p><\/p>\n<p>Sistemas orientados a eventos entregam os dados aos consumidores assim que est\u00e3o prontos. Assim, os sistemas tendem mais para um modelo de push do que para pull ou poll. Essa caracter\u00edstica evita desperdi\u00e7ar recursos pedindo e esperando dados constantemente.<br \/>\nA figura mostra o processo de dissemina\u00e7\u00e3o da mensagem para os consumidores que assinaram um determinado t\u00f3pico.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/e211d5dcfeb5ce8513699eac8e3b6d84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Exemplos cl\u00e1ssicos do uso desse padr\u00e3o incluem a dissemina\u00e7\u00e3o de estado: do mundo do jogo em jogos de computador, dados de mercado em bolsas de valores, informa\u00e7\u00f5es \u00fateis em feeds de dados.<\/p>\n<p><\/p>\n<p>Vamos analisar o c\u00f3digo do assinante:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">init(_Args) -&gt;\n  %% assinamos o ponto de troca, chave = key\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {ok, #{}}.\n\nhandle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) -&gt;\n  %% se o ponto de troca n\u00e3o estiver dispon\u00edvel, tentamos reconectar\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {noreply, State};\n\n%% processamos as mensagens recebidas\nhandle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) -&gt;\n  ?debugVal(Msg),\n  {noreply, State};\n\n%% ao parar o consumidor - desconectamo-nos do ponto de troca\nterminate(_Reason, _State) -&gt;\n  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p>A fonte pode chamar a fun\u00e7\u00e3o de publica\u00e7\u00e3o de mensagem em qualquer lugar conveniente:<\/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 nome do ponto de troca,<br \/>\n<em>Chave<\/em> \u2012 chave de roteamento<br \/>\n<em>Mensagem<\/em> \u2012 carga \u00fatil<\/p>\n<p><\/p>\n<h2 id=\"inverted-publish-subscribe\">Publica\u00e7\u00e3o-assinatura invertida<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/2ef7cd7de459455937bdcfa8a11fd028.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ao implementar pub-sub, obt\u00e9m-se um padr\u00e3o conveniente para registro em log. O conjunto de fontes e consumidores pode ser completamente diferente. A figura apresenta um caso com um consumidor e m\u00faltiplas fontes.<\/p>\n<p><\/p>\n<h2 id=\"task-distribution-pattern\">Padr\u00e3o de distribui\u00e7\u00e3o de tarefas<\/h2>\n<p><\/p>\n<p>Quase em todo projeto, surgem tarefas de processamento atrasado, como gera\u00e7\u00e3o de relat\u00f3rios, envio de notifica\u00e7\u00f5es e obten\u00e7\u00e3o de dados de sistemas externos. A capacidade do sistema que executa essas tarefas \u00e9 facilmente escal\u00e1vel por meio da adi\u00e7\u00e3o de processadores. Tudo o que nos resta \u00e9 formar um cluster de processadores e distribuir as tarefas uniformemente entre eles.<\/p>\n<p><\/p>\n<p>Consideremos as situa\u00e7\u00f5es que surgem no exemplo de 3 processadores. Mesmo na fase de distribui\u00e7\u00e3o das tarefas, surge a quest\u00e3o da justi\u00e7a na distribui\u00e7\u00e3o e do esgotamento dos processadores. A justi\u00e7a ser\u00e1 garantida pela distribui\u00e7\u00e3o round-robin e, para evitar a situa\u00e7\u00e3o de sobrecarga dos processadores, introduziremos um limite <em>prefetch_limit<\/em>. Nos modos de transi\u00e7\u00e3o, <em>prefetch_limit<\/em> n\u00e3o permitir\u00e1 que um processador receba todas as tarefas.<\/p>\n<p><\/p>\n<p>Messaging gerencia filas e prioridades de processamento. Os processadores recebem tarefas \u00e0 medida que elas chegam. A execu\u00e7\u00e3o de uma tarefa pode ser conclu\u00edda com sucesso ou falhar:<\/p>\n<p><\/p>\n<ul>\n<li><code>messaging:ack(Tack)<\/code> \u2012 chamado em caso de processamento bem-sucedido da mensagem<\/li>\n<li><code>messaging:nack(Tack)<\/code> \u2012 chamado em todas as situa\u00e7\u00f5es n\u00e3o conforme. Ap\u00f3s retornar a tarefa, o messaging a transfere para outro processador.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeira aproxima\u00e7\u00e3o\" src=\"\/wp-content\/uploads\/2019\/04\/c2c632b6411247ee8b0dcfb3250a4503.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Suponha que, ao processar tr\u00eas tarefas, ocorreu uma falha complexa: o processador 1, ap\u00f3s receber a tarefa, falhou, sem ter conseguido comunicar nada ao ponto de troca. Nesse caso, ap\u00f3s o t\u00e9rmino do ack timeout, o ponto de troca transferir\u00e1 a tarefa para outro processador. O processador 3, por algum motivo, rejeitou a tarefa e enviou nack; assim, a tarefa tamb\u00e9m foi transferida para outro processador que a executou com sucesso.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnyy-itog\">Resumo preliminar<\/h2>\n<p><\/p>\n<p>Discutimos os principais blocos de constru\u00e7\u00e3o de sistemas distribu\u00eddos e obtivemos uma compreens\u00e3o b\u00e1sica de sua aplica\u00e7\u00e3o em Erlang\/Elixir.<\/p>\n<p><\/p>\n<p>Combinando padr\u00f5es b\u00e1sicos, \u00e9 poss\u00edvel construir paradigmas complexos para resolver as tarefas que surgem.<\/p>\n<p><\/p>\n<p>Na parte final do ciclo, abordaremos quest\u00f5es gerais sobre a organiza\u00e7\u00e3o de servi\u00e7os, roteamento e balanceamento, al\u00e9m de discutir o aspecto pr\u00e1tico da escalabilidade e resili\u00eancia dos sistemas.<\/p>\n<p><\/p>\n<p>Fim da segunda parte.<\/p>\n<p><\/p>\n<p>Foto <noindex>Marius Christensen<\/noindex><br \/>\nIlustra\u00e7\u00f5es preparadas com o aux\u00edlio de websequencediagrams.com<\/p>\n<p>Fonte: <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\/pt\/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=\"pt_PT\" \/>\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\/pt\/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\udd47Blocos de constru\u00e7\u00e3o de aplicativos distribu\u00eddos. Primeiro aproximar | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/30908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=30908"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/30908\/revisions"}],"predecessor-version":[{"id":162009,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/30908\/revisions\/162009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/22886"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=30908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=30908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=30908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}