{"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\/es\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","title":{"rendered":"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/7ef485e452075775ce317b557671274c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En el anterior <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">el art\u00edculo<\/a><\/noindex> Hemos analizado los fundamentos te\u00f3ricos de la arquitectura reactiva. Es hora de hablar sobre los flujos de datos, las formas de implementar sistemas reactivos de Erlang\/Elixir y los patrones de intercambio de mensajes en ellos:<\/p>\n<p><\/p>\n<ul>\n<li>Solicitud-respuesta<\/li>\n<li>Respuesta de solicitud en fragmentos<\/li>\n<li>Respuesta con solicitud<\/li>\n<li>Publicar-suscribirse<\/li>\n<li>Publicar-suscribirse invertido<\/li>\n<li>Distribuci\u00f3n de tareas<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"soa-msa-i-obmen-soobscheniyami\">SOA, MSA y el intercambio de mensajes<\/h2>\n<p><\/p>\n<p>SOA y MSA son arquitecturas de sistemas que definen las reglas para construir sistemas, mientras que el mensajer\u00eda proporciona los primitivos para su implementaci\u00f3n.<\/p>\n<p><\/p>\n<p>No quiero promover una arquitectura de sistemas sobre otra. Estoy a favor de aplicar las pr\u00e1cticas m\u00e1s eficaces y \u00fatiles para un proyecto y negocio espec\u00edficos. Cualquiera que sea el paradigma que elijamos, es mejor crear bloques de sistema teniendo en cuenta el estilo Unix: componentes con baja cohesi\u00f3n, responsables de entidades individuales. Los m\u00e9todos de API llevan a cabo las acciones m\u00e1s simples sobre estas entidades.<\/p>\n<p><\/p>\n<p>El mensajer\u00eda, como se entiende por su nombre, es un corredor de mensajes. Su objetivo principal es recibir y entregar mensajes. Se encarga de las interfaces para enviar informaci\u00f3n, crear canales l\u00f3gicos de transmisi\u00f3n dentro del sistema, la enrutaci\u00f3n y el equilibrio, as\u00ed como el manejo de fallos a nivel de sistema.<br \/>\nEl mensajer\u00eda que se desarrolla no intenta competir con rabbitmq ni reemplazarlo. Sus caracter\u00edsticas principales son:<\/p>\n<p><\/p>\n<ul>\n<li>Distribuci\u00f3n.<br \/>\nLos puntos de intercambio se pueden crear en todos los nodos del cl\u00faster, lo m\u00e1s cerca posible del c\u00f3digo que los utiliza.<\/li>\n<li>Simplicidad.<br \/>\nEnfoque en minimizar el c\u00f3digo repetitivo y la facilidad de uso.<\/li>\n<li>Mejor rendimiento.<br \/>\nNo intentamos duplicar la funcionalidad de rabbitmq, sino que destacamos solo la capa arquitect\u00f3nica y de transporte, que se integra f\u00e1cilmente en OTP, minimizando costos.<\/li>\n<li>Flexibilidad.<br \/>\nCada servicio puede combinar m\u00faltiples patrones de intercambio.<\/li>\n<li>Resiliencia, integrada en el dise\u00f1o.<\/li>\n<li>Escalabilidad.<br \/>\nEl mensajer\u00eda crece junto con la aplicaci\u00f3n. A medida que aumenta la carga, se pueden mover los puntos de intercambio a m\u00e1quinas separadas.<\/li>\n<\/ul>\n<p><\/p>\n<p><em>Observaci\u00f3n.<\/em> Desde el punto de vista de la organizaci\u00f3n del c\u00f3digo, los meta-proyectos son ideales para sistemas complejos en Erlang\/Elixir. Todo el c\u00f3digo del proyecto se encuentra en un solo repositorio: el proyecto paraguas. Al mismo tiempo, los microservicios est\u00e1n lo m\u00e1s aislados posible y realizan operaciones simples, encarg\u00e1ndose de una entidad espec\u00edfica. Con este enfoque, es f\u00e1cil mantener la API de todo el sistema, realizar cambios y escribir pruebas unitarias e integradas de manera c\u00f3moda.<\/p>\n<p><\/p>\n<p>Los componentes del sistema interact\u00faan directamente o a trav\u00e9s de un broker. Desde la perspectiva de la mensajer\u00eda, cada servicio tiene varias fases de vida:<\/p>\n<p><\/p>\n<ul>\n<li>Inicializaci\u00f3n del servicio.<br \/>\nEn esta etapa se lleva a cabo la configuraci\u00f3n y la ejecuci\u00f3n del proceso del servicio y sus dependencias.<\/li>\n<li>Creaci\u00f3n de un punto de intercambio.<br \/>\nEl servicio puede utilizar un punto de intercambio est\u00e1tico, definido en la configuraci\u00f3n del nodo, o crear puntos de intercambio din\u00e1micamente. <\/li>\n<li>Registro del servicio.<br \/>\nPara que el servicio pueda atender solicitudes, debe registrarse en el punto de intercambio.<\/li>\n<li>Funcionamiento normal.<br \/>\nEl servicio realiza un trabajo \u00fatil.<\/li>\n<li>Finalizaci\u00f3n del trabajo.<br \/>\nPueden haber 2 tipos de finalizaci\u00f3n del trabajo: normal y an\u00f3mala. En el caso normal, el servicio se desconecta del punto de intercambio y se detiene. En situaciones an\u00f3malas, la mensajer\u00eda ejecuta uno de los escenarios de manejo de fallas.<\/li>\n<\/ul>\n<p><\/p>\n<p>Parece bastante complicado, pero en el c\u00f3digo no es tan aterrador. Se presentar\u00e1n ejemplos de c\u00f3digo con comentarios posteriormente en el an\u00e1lisis de plantillas.<\/p>\n<p><\/p>\n<h2 id=\"exchanges\">Intercambios<\/h2>\n<p><\/p>\n<p>Un punto de intercambio es un proceso de mensajer\u00eda que implementa la l\u00f3gica de interacci\u00f3n con los componentes dentro de una plantilla de intercambio de mensajes. En todos los ejemplos que se presentan a continuaci\u00f3n, los componentes interact\u00faan a trav\u00e9s de puntos de intercambio, cuyas combinaciones forman la mensajer\u00eda.<\/p>\n<p><\/p>\n<h2 id=\"message-exchange-patterns-meps\">Patrones de intercambio de mensajes (MEPs)<\/h2>\n<p><\/p>\n<p>Globalmente, los patrones de intercambio se pueden dividir en bidireccionales y unidireccionales. Los primeros implican una respuesta al mensaje recibido, los segundos no. Un ejemplo cl\u00e1sico de un patr\u00f3n bidireccional en una arquitectura cliente-servidor es el patr\u00f3n de solicitud-respuesta. Revisemos este patr\u00f3n y sus modificaciones.<\/p>\n<p><\/p>\n<h3 id=\"requestresponse-ili-rpc\">Solicitud-respuesta o RPC<\/h3>\n<p><\/p>\n<p>RPC se utiliza cuando necesitamos obtener una respuesta de otro proceso. Este proceso puede estar ejecut\u00e1ndose en el mismo nodo o estar ubicado en otro continente. A continuaci\u00f3n se muestra un esquema de interacci\u00f3n entre el cliente y <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/es\/server\/dts-los-angeles\/\"   title=\"servidores\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"3483\">servidores<\/a> a trav\u00e9s de mensajer\u00eda.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/091725fc108d6ce1a5fc9ae866e2c395.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dado que la mensajer\u00eda es completamente as\u00edncrona, para el cliente el intercambio se divide en 2 fases:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Env\u00edo de solicitud<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">mensajer\u00eda:solicitud(Intercambio, EtiquetaDeCoincidenciaDeRespuesta, Definici\u00f3nDeSolicitud, ProcesoDeManejador).<\/code><\/pre>\n<p><\/p>\n<p><em>Intercambio<\/em> \u2012 nombre \u00fanico del punto de intercambio<br \/>\n<em>EtiquetaDeCoincidenciaDeRespuesta<\/em> \u2012 etiqueta local para el procesamiento de la respuesta. Por ejemplo, en el caso de enviar varias solicitudes id\u00e9nticas pertenecientes a diferentes usuarios.<br \/>\n<em>Definici\u00f3nDeSolicitud<\/em> \u2012 cuerpo de la solicitud<br \/>\n<em>ProcesoDeManejador<\/em> \u2012 PID del manejador. A este proceso le llegar\u00e1 la respuesta del servidor.<\/p>\n<p>\n<\/li>\n<li>\n<p>Procesamiento de la respuesta<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">manejar_info(#'$msg'{intercambio = INTERCAMBIO, etiqueta = EtiquetaDeCoincidenciaDeRespuesta,mensaje = CargaDeRespuesta}, Estado)<\/code><\/pre>\n<p><\/p>\n<p><em>CargaDeRespuesta<\/em> \u2012 respuesta del servidor.<\/p>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Para el servidor, el proceso tambi\u00e9n consta de 2 fases:<\/p>\n<p><\/p>\n<ol>\n<li>Inicializaci\u00f3n del punto de intercambio<\/li>\n<li>Procesamiento de las solicitudes recibidas<\/li>\n<\/ol>\n<p><\/p>\n<p>Ilustremos este patr\u00f3n con c\u00f3digo. Supongamos que necesitamos implementar un servicio simple que proporcione un \u00fanico m\u00e9todo para obtener la hora exacta.<\/p>\n<p><\/p>\n<h4 id=\"kod-servera\">C\u00f3digo del servidor<\/h4>\n<p><\/p>\n<p>Extraigamos la definici\u00f3n de la API del servicio en api.hrl:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% =====================================================\n%% entidades\n%% =====================================================\n-registro(hora, {\n  tiempo_unix :: entero_no_negativo(),\n  fecha_hora :: binario()\n}).\n\n-registro(error_hora, {\n  c\u00f3digo :: entero_no_negativo(),\n  error :: t\u00e9rmino()\n}).\n\n%% =====================================================\n%% m\u00e9todos\n%% =====================================================\n-registro(solicitud_hora, {\n  opciones :: t\u00e9rmino()\n}).\n-registro(respuesta_hora, {\n  resultado :: #hora{} | #error_hora{}\n}).<\/code><\/pre>\n<p><\/p>\n<p>Definamos el controlador del servicio en time_controller.erl<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">%% En el ejemplo solo se muestra el c\u00f3digo significativo. Al insertarlo en la plantilla gen_server, se puede obtener un servicio funcional.\n\n%% inicializaci\u00f3n del gen_server\ninit(Args) -&gt;\n  %% conexi\u00f3n con el punto de intercambio\n  mensajer\u00eda:monitorear_intercambio(req_resp, ?INTERCAMBIO, por_defecto, self())\n  {ok, #{}}.\n\n%% manejo del evento de p\u00e9rdida de conexi\u00f3n con el punto de intercambio. Este mismo evento llega si el punto de intercambio a\u00fan no se ha iniciado.\nhandle_info(#intercambio_muerto{intercambio = ?INTERCAMBIO}, Estado) -&gt;\n  erlang:enviar(self(), monitorear_intercambio),\n  {noreply, Estado};\n\n%% manejo de la API\nhandle_info(#solicitud_hora{opciones = _Opciones}, Estado) -&gt;\n  mensajer\u00eda:respuesta_una_vez(Cliente, #respuesta_hora{\nresultado = #hora{ tiempo_unix = time_utils:tiempo_unix(now()), fecha_hora = time_utils:iso8601_fmt(now())}\n  });\n  {noreply, Estado};\n\n%% finalizaci\u00f3n del gen_server\nterminar(_Raz\u00f3n, _Estado) -&gt;\n  mensajer\u00eda:demonitorar_intercambio(req_resp, ?INTERCAMBIO, por_defecto, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<h4 id=\"kod-klienta\">C\u00f3digo del cliente<\/h4>\n<p><\/p>\n<p>Para enviar una solicitud al servicio, se puede llamar a la API de solicitud de mensajer\u00eda en cualquier parte del cliente:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">caso mensajer\u00eda:solicitud(?INTERCAMBIO, etiqueta, #solicitud_hora{opciones = #{}}, self()) de\n    ok -&gt; ok;\n    _ -&gt; %% l\u00f3gica de repetici\u00f3n o fallo\nfin<\/code><\/pre>\n<p><\/p>\n<p>En un sistema distribuido, la configuraci\u00f3n de los componentes puede ser muy variada y en el momento de la solicitud, la mensajer\u00eda puede no haberse iniciado a\u00fan, o el controlador del servicio no estar\u00e1 preparado para atender la solicitud. Por lo tanto, necesitamos verificar la respuesta de la mensajer\u00eda y manejar el caso de fallo.<br \/>\nTras el env\u00edo exitoso, el cliente recibir\u00e1 una respuesta o un error del servicio.<br \/>\nManejemos ambos casos en 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\">Respuesta de solicitud en fragmentos<\/h3>\n<p><\/p>\n<p>Es mejor evitar enviar mensajes grandes. Esto afecta la capacidad de respuesta y el funcionamiento estable de todo el sistema. Si la respuesta a la solicitud ocupa mucha memoria, entonces la fragmentaci\u00f3n es obligatoria.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/bd60742a933a8e4e3eeaf7f4adf00f2a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqu\u00ed hay un par de ejemplos de tales casos:<\/p>\n<p><\/p>\n<ul>\n<li>Los componentes intercambian datos binarios, por ejemplo, archivos. Dividir la respuesta en partes peque\u00f1as ayuda a trabajar eficazmente con archivos de cualquier tama\u00f1o y a evitar el desbordamiento de memoria.<\/li>\n<li>Listados. Por ejemplo, necesitamos seleccionar todos los registros de una tabla muy grande en la base de datos y enviarlos a otro componente.<\/li>\n<\/ul>\n<p><\/p>\n<p>Yo llamo a tales respuestas 'un tren de carga'. En cualquier caso, 1024 mensajes de 1 MB son mejores que un solo mensaje de 1 GB. <\/p>\n<p><\/p>\n<p>En un cl\u00faster de Erlang, obtenemos una ventaja adicional: reducci\u00f3n de la carga en el punto de intercambio y la red, ya que las respuestas se env\u00edan directamente al destinatario, omitiendo el punto de intercambio.<\/p>\n<p><\/p>\n<h3 id=\"response-with-request\">Respuesta con solicitud<\/h3>\n<p><\/p>\n<p>Esta es una modificaci\u00f3n bastante rara del patr\u00f3n RPC para construir sistemas de di\u00e1logo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" 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-suscribirse (\u00e1rbol de distribuci\u00f3n de datos)<\/h3>\n<p><\/p>\n<p>Los sistemas orientados a eventos entregan datos a los consumidores a medida que estos est\u00e1n listos. As\u00ed, los sistemas tienden m\u00e1s a un modelo de push que a pull o poll. Esta caracter\u00edstica evita desperdiciar recursos solicitando constantemente y esperando datos.<br \/>\nEn la figura se muestra el proceso de distribuci\u00f3n de mensajes a los consumidores suscritos a un tema espec\u00edfico.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/e211d5dcfeb5ce8513699eac8e3b6d84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ejemplos cl\u00e1sicos de uso de este patr\u00f3n incluyen la propagaci\u00f3n de estados: del mundo del juego en videojuegos, datos de mercado en bolsas, informaci\u00f3n \u00fatil en feeds de datos.<\/p>\n<p><\/p>\n<p>Veamos el c\u00f3digo del suscriptor:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">init(_Args) -&gt;\n  %% nos suscribimos al intercambiador, clave = key\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {ok, #{}}.\n\nhandle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) -&gt;\n  %% si el punto de intercambio no est\u00e1 disponible, intentamos reconectarnos\n  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),\n  {noreply, State};\n\n%% procesamos los mensajes recibidos\nhandle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) -&gt;\n  ?debugVal(Msg),\n  {noreply, State};\n\n%% al detener al consumidor, nos desconectamos del punto de intercambio\nterminate(_Reason, _State) -&gt;\n  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p>La fuente puede invocar la funci\u00f3n de publicaci\u00f3n de mensajes en cualquier 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>Intercambio<\/em> \u2012 nombre del punto de intercambio,<br \/>\n<em>Clave<\/em> \u2012 clave de enrutamiento,<br \/>\n<em>Mensaje<\/em> \u2012 carga \u00fatil.<\/p>\n<p><\/p>\n<h2 id=\"inverted-publish-subscribe\">Publicar-suscribirse invertido<\/h2>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/2ef7cd7de459455937bdcfa8a11fd028.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al implementar pub-sub, se puede obtener un patr\u00f3n conveniente para el registro. El conjunto de fuentes y consumidores puede ser muy diverso. La imagen ilustra un caso con un solo consumidor y m\u00faltiples fuentes.<\/p>\n<p><\/p>\n<h2 id=\"task-distribution-pattern\">Patr\u00f3n de distribuci\u00f3n de tareas<\/h2>\n<p><\/p>\n<p>Casi todos los proyectos enfrentan tareas de procesamiento diferido, como la generaci\u00f3n de informes, la entrega de notificaciones y la obtenci\u00f3n de datos de sistemas externos. La capacidad del sistema que ejecuta estas tareas se puede escalar f\u00e1cilmente agregando manejadores. Todo lo que nos queda es formar un cl\u00faster de manejadores y distribuir las tareas de manera uniforme entre ellos.<\/p>\n<p><\/p>\n<p>Analicemos escenarios surgiendo con 3 manejadores. Desde la etapa de distribuci\u00f3n de tareas surge la cuesti\u00f3n de la justicia en la distribuci\u00f3n y el desbordamiento de los manejadores. La justicia ser\u00e1 garantizada por la distribuci\u00f3n round-robin, y para evitar situaciones de desbordamiento de los manejadores, introduciremos un l\u00edmite <em>prefetch_limit<\/em>. En modos transitorios, <em>prefetch_limit<\/em> no permitir\u00e1 que un solo manejador reciba todas las tareas.<\/p>\n<p><\/p>\n<p>Messaging gestiona colas y la prioridad de procesamiento. Los manejadores reciben tareas a medida que llegan. La ejecuci\u00f3n de una tarea puede finalizar con \u00e9xito o fracasar:<\/p>\n<p><\/p>\n<ul>\n<li><code>messaging:ack(Tack)<\/code> \u2012 se llama en caso de procesamiento exitoso del mensaje,<\/li>\n<li><code>messaging:nack(Tack)<\/code> \u2012 se llama en todas las situaciones an\u00f3malas. Despu\u00e9s de devolver la tarea, messaging la transferir\u00e1 a otro manejador.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Bloques de construcci\u00f3n de aplicaciones distribuidas. Primera aproximaci\u00f3n\" src=\"\/wp-content\/uploads\/2019\/04\/c2c632b6411247ee8b0dcfb3250a4503.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Supongamos que, al procesar tres tareas, ocurri\u00f3 un fallo complejo: el manejador 1 se cay\u00f3 despu\u00e9s de recibir la tarea, sin poder notificar nada al punto de intercambio. En este caso, el punto de intercambio, tras expirar el tiempo de espera de ack, transferir\u00e1 la tarea a otro manejador. El manejador 3, por alguna raz\u00f3n, rechaz\u00f3 la tarea y envi\u00f3 nack; en consecuencia, la tarea tambi\u00e9n pas\u00f3 a otro manejador que la complet\u00f3 con \u00e9xito.<\/p>\n<p><\/p>\n<h2 id=\"predvaritelnyy-itog\">Conclusiones preliminares<\/h2>\n<p><\/p>\n<p>Hemos analizado los bloques b\u00e1sicos de sistemas distribuidos y obtenido una comprensi\u00f3n b\u00e1sica de su aplicaci\u00f3n en Erlang\/Elixir.<\/p>\n<p><\/p>\n<p>Al combinar patrones b\u00e1sicos, se pueden construir paradigmas complejos para resolver las tareas que surgen.<\/p>\n<p><\/p>\n<p>En la parte final del ciclo, abordaremos cuestiones generales sobre la organizaci\u00f3n de servicios, enrutamiento y balanceo de carga, as\u00ed como hablaremos sobre la parte pr\u00e1ctica de la escalabilidad y la tolerancia a fallos de los sistemas.<\/p>\n<p><\/p>\n<p>Fin de la segunda parte.<\/p>\n<p><\/p>\n<p>Foto <noindex>Marius Christensen<\/noindex><br \/>\nLas ilustraciones fueron preparadas con websequencediagrams.com<\/p>\n<p>Fuente: <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\/es\/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=\"es_ES\" \/>\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\/es\/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\udd47Elementos b\u00e1sicos de aplicaciones distribuidas. Primera aproximaci\u00f3n | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-pervoe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/30908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=30908"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/30908\/revisions"}],"predecessor-version":[{"id":162009,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/30908\/revisions\/162009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/22886"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=30908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=30908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=30908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}