{"id":80035,"date":"2020-05-02T13:42:54","date_gmt":"2020-05-02T11:42:54","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny"},"modified":"2020-05-02T13:42:54","modified_gmt":"2020-05-02T11:42:54","slug":"udobnye-arhitekturnye-patterny","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny","title":{"rendered":"Patrones arquitect\u00f3nicos convenientes","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00a1Hola, Habr!<\/p>\n<p><\/p>\n<p>A la luz de los acontecimientos actuales debido al coronavirus, varios servicios en l\u00ednea han empezado a recibir una carga incrementada. Por ejemplo, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.independent.co.uk\/life-style\/gadgets-and-tech\/news\/coronavirus-ocado-down-app-website-stockpiling-food-online-delivery-a9402216.html\">una de las cadenas comerciales en el Reino Unido simplemente detuvo su sitio web de pedidos en l\u00ednea<\/a><\/noindex>, ya que no contaba con los recursos necesarios. Y no siempre se puede acelerar un servidor simplemente agregando hardware m\u00e1s potente, sin embargo, es necesario procesar las solicitudes de los clientes (o se ir\u00e1n con la competencia).<\/p>\n<p><\/p>\n<p>En este art\u00edculo, mencionar\u00e9 brevemente las pr\u00e1cticas populares que permitir\u00e1n crear un servicio r\u00e1pido y resistente a fallos. Sin embargo, de las posibles esquemas de desarrollo, he seleccionado solo aquellos que ahora <strong>son f\u00e1ciles de utilizar<\/strong>. Para cada punto, ya tienes bibliotecas listas o hay opciones para resolver el problema a trav\u00e9s de una plataforma en la nube.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1 id=\"gorizontalnoe-masshtabirovanie\">Escalado horizontal<\/h1>\n<p><\/p>\n<p>El punto m\u00e1s simple y conocido por todos. En general, hay dos esquemas de distribuci\u00f3n de carga que se ven con m\u00e1s frecuencia: escalado horizontal y escalado vertical. <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9C%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D1%8C#%D0%93%D0%BE%D1%80%D0%B8%D0%B7%D0%BE%D0%BD%D1%82%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BC%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">En el primer caso,<\/a><\/noindex> permites que los servicios operen en paralelo, distribuyendo as\u00ed la carga entre ellos. <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9C%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D1%8C#%D0%92%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BC%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">En el segundo,<\/a><\/noindex> pides servidores m\u00e1s potentes o optimizas el c\u00f3digo.<\/p>\n<p><\/p>\n<p>Por ejemplo, tomar\u00e9 un almacenamiento en la nube abstracto de archivos, es decir, un an\u00e1logo de OwnCloud, OneDrive, etc.<\/p>\n<p><\/p>\n<p>La imagen est\u00e1ndar de un esquema similar se muestra a continuaci\u00f3n, pero solo demuestra la complejidad del sistema. Tenemos que sincronizar los servicios de alguna manera. \u00bfQu\u00e9 pasar\u00e1 si un usuario guarda un archivo desde su tableta y luego quiere verlo desde su tel\u00e9fono?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/7512c6d8783f5e0a38cc0861b01e54c8.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa diferencia entre los enfoques: en el escalado vertical estamos dispuestos a aumentar la potencia de los nodos, mientras que en el escalado horizontal, agregamos nodos nuevos para distribuir la carga.<\/p>\n<p><\/p>\n<h1 id=\"cqrs\">CQRS<\/h1>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/martinfowler.com\/bliki\/CQRS.html\">Separaci\u00f3n de responsabilidad en comandos y consultas<\/a><\/noindex> es un patr\u00f3n bastante importante, ya que permite a diferentes clientes no solo conectarse a diferentes servicios, sino tambi\u00e9n recibir flujos de eventos id\u00e9nticos. Sus beneficios no son tan evidentes para una aplicaci\u00f3n simple, sin embargo, es crucial (y simple) para un servicio de alta carga. Su esencia es: los flujos de datos entrantes y salientes no deben cruzarse. Es decir, no puedes enviar una solicitud y esperar una respuesta; en su lugar, env\u00edas una solicitud al servicio A, pero recibes una respuesta en el servicio B.<\/p>\n<p><\/p>\n<p>El primer beneficio de este enfoque es la capacidad de desconexi\u00f3n (en un sentido amplio) durante la ejecuci\u00f3n de una larga solicitud. Tomemos como ejemplo una secuencia m\u00e1s o menos est\u00e1ndar:<\/p>\n<p><\/p>\n<ol>\n<li>El cliente envi\u00f3 una solicitud al servidor.<\/li>\n<li>El servidor inici\u00f3 un procesamiento prolongado.<\/li>\n<li>El servidor respondi\u00f3 al cliente con el resultado.<\/li>\n<\/ol>\n<p><\/p>\n<p>Imaginemos que en el punto 2 se produjo una interrupci\u00f3n de la conexi\u00f3n (ya sea que la red se reconect\u00f3 o que el usuario cambi\u00f3 a otra p\u00e1gina, cortando la conexi\u00f3n). En este caso, ser\u00e1 dif\u00edcil para el servidor enviar una respuesta al usuario con informaci\u00f3n sobre lo que se proces\u00f3. Al aplicar CQRS, la secuencia ser\u00e1 un poco diferente:<\/p>\n<p><\/p>\n<ol>\n<li>El cliente se suscribi\u00f3 a las actualizaciones.<\/li>\n<li>El cliente envi\u00f3 una solicitud al servidor.<\/li>\n<li>El servidor respondi\u00f3 \"solicitud aceptada\".<\/li>\n<li>El servidor respondi\u00f3 con el resultado a trav\u00e9s del canal del punto \"1\".<\/li>\n<\/ol>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/8a00ea93eecc7cc0754122857c5f90d0.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como se puede ver, el esquema es un poco m\u00e1s complejo. Adem\u00e1s, el enfoque intuitivo de solicitud-respuesta est\u00e1 ausente aqu\u00ed. Sin embargo, como se observa, la interrupci\u00f3n de la conexi\u00f3n durante el procesamiento de la solicitud no conducir\u00e1 a un error. Adem\u00e1s, si efectivamente el usuario est\u00e1 conectado al servicio desde varios dispositivos (por ejemplo, desde un tel\u00e9fono m\u00f3vil y una tableta), se puede hacer que la respuesta llegue a ambos dispositivos.<\/p>\n<p><\/p>\n<p>Curiosamente, el c\u00f3digo para procesar los mensajes entrantes se vuelve similar (no al 100%) tanto para los eventos que fueron influenciados por el cliente como para otros eventos, incluidos los de otros clientes.<\/p>\n<p><\/p>\n<p>Sin embargo, en realidad, obtenemos beneficios adicionales debido a que el flujo unidireccional puede ser procesado de manera funcional (utilizando RX y an\u00e1logos). Y eso ya es una ventaja considerable, ya que, en esencia, la aplicaci\u00f3n puede hacerse completamente reactiva, adem\u00e1s de utilizar un enfoque funcional. Para aplicaciones robustas, esto puede ahorrar significativamente recursos en desarrollo y mantenimiento.<\/p>\n<p><\/p>\n<p>Si combinamos este enfoque con la escalabilidad horizontal, obtenemos como bono la posibilidad de enviar solicitudes a un servidor y recibir respuestas de otro. De esta manera, el cliente puede elegir el servicio que le sea conveniente, y el sistema interno podr\u00e1 manejar correctamente los eventos.<\/p>\n<p><\/p>\n<h1 id=\"event-sourcing\">Event Sourcing<\/h1>\n<p><\/p>\n<p>Como saben, una de las caracter\u00edsticas principales de un sistema distribuido es la ausencia de un tiempo com\u00fan y una secci\u00f3n cr\u00edtica com\u00fan. Para un proceso, puede hacerse la sincronizaci\u00f3n (en los mismos mutex), dentro de la cual est\u00e1s seguro de que nadie m\u00e1s est\u00e1 ejecutando ese c\u00f3digo. Sin embargo, para un sistema distribuido, esto es peligroso, ya que requerir\u00eda gastos generales y se perder\u00eda toda la ventaja de la escalabilidad: de todos modos, todos los componentes esperar\u00edan a uno.<\/p>\n<p><\/p>\n<p>De aqu\u00ed obtenemos un hecho importante: no se puede sincronizar un sistema distribuido r\u00e1pido, ya que entonces disminuir\u00edamos el rendimiento. Por otro lado, a menudo necesitamos cierta consistencia de los componentes. Para ello, se puede utilizar el enfoque de <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">consistencia eventual<\/a><\/noindex>, donde se garantiza que, en ausencia de cambios en los datos, despu\u00e9s de un cierto per\u00edodo de tiempo tras la \u00faltima actualizaci\u00f3n (\u00abeventualmente\u00bb), todas las solicitudes devolver\u00e1n el \u00faltimo valor actualizado.<\/p>\n<p><\/p>\n<p>Es importante entender que para las bases de datos cl\u00e1sicas a menudo se aplica <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Consistency_model#Strict_consistency\">consistencia estricta<\/a><\/noindex>, donde cada nodo posee la misma informaci\u00f3n (esto a menudo se logra cuando la transacci\u00f3n se considera establecida solo despu\u00e9s de la respuesta del segundo servidor). Hay ciertas flexibilidades debido a los niveles de aislamiento, pero la esencia general sigue siendo la misma: puedes vivir en un mundo completamente consistente.<\/p>\n<p><\/p>\n<p>Sin embargo, volvamos a la tarea inicial. Si una parte del sistema puede construirse con <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">consistencia eventual<\/a><\/noindex>, entonces se puede construir el siguiente esquema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/33c80be6bc33bd897ca9b9e5525f9ae8.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Caracter\u00edsticas importantes de este enfoque:<\/p>\n<p><\/p>\n<ul>\n<li>Cada solicitud entrante se coloca en una cola.<\/li>\n<li>Durante el proceso de procesamiento de la solicitud, el servicio tambi\u00e9n puede colocar tareas en otras colas.<\/li>\n<li>Cada evento entrante tiene un identificador (que es necesario para la deduplicaci\u00f3n).<\/li>\n<li>La cola funciona ideol\u00f3gicamente seg\u00fan el esquema \"solo a\u00f1adir\". No se pueden eliminar elementos ni reorganizarlos.<\/li>\n<li>La cola funciona seg\u00fan el esquema FIFO (perd\u00f3n por la tautolog\u00eda). Si es necesario realizar ejecuci\u00f3n paralela, entonces se deben trasladar objetos a diferentes colas en una de las etapas.<\/li>\n<\/ul>\n<p><\/p>\n<p>Recuerdo que estamos considerando el caso de un almacenamiento en l\u00ednea de archivos. En este caso, el sistema se ver\u00e1, m\u00e1s o menos, as\u00ed:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/b95efb29545dcde1db9432d12d00a1b1.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Es importante destacar que los servicios en el diagrama no necesariamente indican un servidor separado. Incluso el proceso puede ser el mismo. Lo que importa es que, ideol\u00f3gicamente, estas cosas est\u00e1n divididas de tal manera que se puede aplicar f\u00e1cilmente la escalabilidad horizontal.<\/p>\n<p><\/p>\n<p>Y para dos usuarios, el esquema se ver\u00e1 as\u00ed (los servicios destinados a diferentes usuarios est\u00e1n marcados con diferentes colores):<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/4c4aadc8b9dd505c3ad743e69fee4fae.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Los beneficios de esta combinaci\u00f3n:<\/p>\n<p><\/p>\n<ul>\n<li>Los servicios de procesamiento de informaci\u00f3n est\u00e1n separados. Las colas tambi\u00e9n est\u00e1n separadas. Si necesitamos aumentar la capacidad del sistema, solo necesitamos iniciar m\u00e1s servicios en m\u00e1s servidores.<\/li>\n<li>Cuando recibimos informaci\u00f3n del usuario, no es necesario esperar a que se complete el guardado de datos. Por el contrario, es suficiente con responder \"ok\", y luego comenzar a trabajar gradualmente. Al mismo tiempo, la cola suaviza los picos, ya que la adici\u00f3n de un nuevo objeto ocurre r\u00e1pidamente y el usuario no necesita esperar por un recorrido completo por todo el ciclo.<\/li>\n<li>Como ejemplo, he a\u00f1adido un servicio de deduplicaci\u00f3n, que intenta combinar archivos id\u00e9nticos. Si tarda mucho en un 1% de los casos, el cliente pr\u00e1cticamente no se dar\u00e1 cuenta (ver arriba), lo que es una gran ventaja, ya que de nosotros ya no se requiere una velocidad y fiabilidad del 100%.<\/li>\n<\/ul>\n<p><\/p>\n<p>Sin embargo, tambi\u00e9n se pueden ver desventajas:<\/p>\n<p><\/p>\n<ul>\n<li>Nuestro sistema ha perdido la estricta coherencia. Esto significa que, por ejemplo, si uno se suscribe a diferentes servicios, te\u00f3ricamente se puede obtener un estado diferente (ya que uno de los servicios podr\u00eda no recibir a tiempo la notificaci\u00f3n de la cola interna). Como otra consecuencia, el sistema ahora no tiene un tiempo com\u00fan. Es decir, no se pueden, por ejemplo, clasificar todos los eventos simplemente por el tiempo de llegada, ya que los relojes entre servidores pueden no estar sincronizados (m\u00e1s a\u00fan, tener la misma hora en dos servidores ser\u00eda una utop\u00eda).<\/li>\n<li>No se puede retroceder ning\u00fan evento ahora (como se podr\u00eda hacer con una base de datos). En lugar de eso, es necesario a\u00f1adir un nuevo evento \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/49451237\/compensating-events-on-cqrs-es-architecture\">compensation event<\/a><\/noindex>, que cambiar\u00e1 el \u00faltimo estado al necesario. Como ejemplo de un \u00e1rea similar: sin reescribir el historial (lo cual es malo en ciertos casos), en git no se puede deshacer un commit, sin embargo, se puede hacer un <noindex><a rel=\"nofollow\" href=\"https:\/\/git-scm.com\/docs\/git-revert\">rollback commit<\/a><\/noindex>, que en esencia simplemente devolver\u00e1 el estado anterior. Sin embargo, tanto el commit err\u00f3neo como el rollback quedar\u00e1n registrados en el historial.<\/li>\n<li>El esquema de datos puede cambiar de una versi\u00f3n a otra, sin embargo, no ser\u00e1 posible actualizar eventos antiguos al nuevo est\u00e1ndar (ya que los eventos no se pueden cambiar en principio).<\/li>\n<\/ul>\n<p><\/p>\n<p>Como se puede ver, Event Sourcing se lleva bien con CQRS. De hecho, implementar un sistema con colas eficaces y convenientes, pero sin separaci\u00f3n de flujos de datos, ya es complicado en s\u00ed mismo, ya que habr\u00e1 que a\u00f1adir puntos de sincronizaci\u00f3n que anular\u00e1n todo el efecto positivo de las colas. Al aplicar ambos enfoques a la vez, es necesario realizar ligeras correcciones en el c\u00f3digo del funcionamiento del programa. En nuestro caso, al enviar un archivo al servidor, la respuesta solo dice 'ok', lo que significa que 'la operaci\u00f3n de adici\u00f3n de archivo se ha guardado'. Formalmente, esto no implica que los datos ya est\u00e9n disponibles en otros dispositivos (por ejemplo, el servicio de deduplicaci\u00f3n puede estar reestructurando el \u00edndice). Sin embargo, despu\u00e9s de un tiempo, el cliente recibir\u00e1 una notificaci\u00f3n del tipo 'el archivo X ha sido guardado'.<\/p>\n<p><\/p>\n<p>Como resultado:<\/p>\n<p><\/p>\n<ul>\n<li>El n\u00famero de estados de env\u00edo de archivos aumenta: en lugar del cl\u00e1sico 'archivo enviado', obtenemos dos: 'archivo a\u00f1adido a la cola en el servidor' y 'archivo guardado en el almacenamiento'. Lo \u00faltimo significa que otros dispositivos ya pueden comenzar a recibir el archivo (teniendo en cuenta que las colas funcionan a diferentes velocidades).<\/li>\n<li>Debido a que la informaci\u00f3n sobre el env\u00edo ahora llega a trav\u00e9s de diferentes canales, necesitamos idear soluciones para obtener el estado del procesamiento del archivo. Como consecuencia de esto: a diferencia de la cl\u00e1sica request-response, el cliente puede reiniciarse durante el procesamiento del archivo, pero el estado de este mismo procesamiento ser\u00e1 correcto. Adem\u00e1s, este aspecto funciona, en esencia, de forma predeterminada. Como consecuencia: ahora somos m\u00e1s tolerantes a fallos.<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"sharding\">Sharding<\/h1>\n<p><\/p>\n<p>Como se mencion\u00f3 anteriormente, en sistemas con event sourcing no hay una coherencia estricta. Esto significa que podemos utilizar varios almacenes sin ninguna sincronizaci\u00f3n entre ellos. Acerc\u00e1ndonos a nuestra tarea, podemos:<\/p>\n<p><\/p>\n<ul>\n<li>Separar archivos por tipos. Por ejemplo, im\u00e1genes\/videos pueden ser decodificados y seleccionados en un formato m\u00e1s eficiente.<\/li>\n<li>Separar cuentas por pa\u00edses. Esto puede ser necesario debido a muchas leyes, sin embargo, esta arquitectura permite hacerlo autom\u00e1ticamente.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/dd310df700bc39c014d0105a3425fece.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si desea transferir datos de un almacenamiento a otro, aqu\u00ed ya no ser\u00e1 posible hacerlo con medios est\u00e1ndar. Desafortunadamente, en este caso es necesario detener la cola, realizar la migraci\u00f3n y luego reactivarla. En general, no es posible transferir datos 'en caliente', sin embargo, si la cola de eventos se almacena completamente y tiene copias de los estados anteriores del almacenamiento, podemos reproducir los eventos de la siguiente manera:<\/p>\n<p><\/p>\n<ul>\n<li>En Event Source, cada evento tiene su propio identificador (idealmente, no decreciente). Por lo tanto, en el almacenamiento podemos agregar un campo: id del \u00faltimo elemento procesado.<\/li>\n<li>Duplicamos la cola para que todos los eventos puedan ser procesados para varios almacenes independientes (el primero es el que ya contiene datos y el segundo es nuevo, aunque todav\u00eda vac\u00edo). La segunda cola, por supuesto, a\u00fan no se est\u00e1 procesando.<\/li>\n<li>Iniciamos la segunda cola (es decir, comenzamos a reproducir eventos).<\/li>\n<li>Cuando la nueva cola est\u00e9 relativamente vac\u00eda (es decir, la diferencia media de tiempo entre la adici\u00f3n de un elemento y su extracci\u00f3n sea aceptable), se puede comenzar a redirigir a los lectores al nuevo almacenamiento.<\/li>\n<\/ul>\n<p><\/p>\n<p>Como se puede ver, en nuestro sistema nunca ha habido ni hay una estricta consistencia. Solo existe eventual consistencia, es decir, la garant\u00eda de que los eventos se procesan en el mismo orden (sin embargo, posiblemente, con diferentes retrasos). Y aprovechando esto, podemos transferir datos comparativamente f\u00e1cil sin detener el sistema en el otro extremo del mundo.<\/p>\n<p><\/p>\n<p>As\u00ed, continuando con nuestro ejemplo sobre el almacenamiento en l\u00ednea para archivos, esta arquitectura ya nos ofrece varias ventajas:<\/p>\n<p><\/p>\n<ul>\n<li>Podemos mover objetos m\u00e1s cerca de los usuarios, y de manera din\u00e1mica. Esto puede mejorar la calidad del servicio. <\/li>\n<li>Podemos almacenar parte de los datos dentro de las empresas. Por ejemplo, los usuarios de Enterprise a menudo exigen que sus datos se almacenen en centros de datos controlables (para evitar fugas de datos). Gracias al sharding podemos soportar esto f\u00e1cilmente. Y la tarea se simplifica a\u00fan m\u00e1s si el cliente tiene una nube compatible (por ejemplo, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-gb\/azure-stack\/asdk\/asdk-what-is?view=azs-1910\">Azure self hosted<\/a><\/noindex>).<\/li>\n<li>Lo m\u00e1s importante es que no tenemos que hacerlo. Al principio, bastar\u00eda con un solo almacenamiento para todas las cuentas (para comenzar a trabajar m\u00e1s r\u00e1pido). Y la caracter\u00edstica clave de este sistema es que, aunque es escalable, en la etapa inicial es bastante simple. Simplemente no hay que escribir de inmediato c\u00f3digo que funcione con un mill\u00f3n de colas independientes, etc. Si es necesario, se puede hacer en el futuro.<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"static-content-hosting\">Alojamiento de Contenido Est\u00e1tico<\/h1>\n<p><\/p>\n<p>Este punto puede parecer obvio, pero sigue siendo necesario para una aplicaci\u00f3n de carga m\u00e1s o menos est\u00e1ndar. Su esencia es simple: todo el contenido est\u00e1tico se entrega no desde el mismo servidor donde est\u00e1 la aplicaci\u00f3n, sino desde especiales, dedicados precisamente para este prop\u00f3sito. Como consecuencia, estas operaciones se realizan m\u00e1s r\u00e1pidamente (un nginx hipot\u00e9tico entrega archivos de manera m\u00e1s eficiente y menos costosa que un servidor Java). Adem\u00e1s, la arquitectura CDN (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Content_delivery_network\">Red de Entrega de Contenido<\/a><\/noindex>) permite ubicar nuestros archivos m\u00e1s cerca de los usuarios finales, lo que mejora la experiencia de uso del servicio.<\/p>\n<p><\/p>\n<p>El ejemplo m\u00e1s simple y est\u00e1ndar de contenido est\u00e1tico es un conjunto de scripts e im\u00e1genes para un sitio web. Con ellos es todo bastante sencillo: se conocen por adelantado, luego se carga el archivo en los servidores de CDN, desde donde se entregan a los usuarios finales.<\/p>\n<p><\/p>\n<p>Sin embargo, en la pr\u00e1ctica, se puede aplicar un enfoque similar a la arquitectura lambda para el contenido est\u00e1tico. Regresando a nuestra tarea (almacenamiento en l\u00ednea de archivos), en la que necesitamos entregar archivos a los usuarios. La soluci\u00f3n m\u00e1s simple ser\u00eda crear un servicio que, para cada solicitud del usuario, realice todas las comprobaciones necesarias (autorizaci\u00f3n, etc.) y luego descargue el archivo directamente de nuestro almacenamiento. El principal inconveniente de este enfoque es que el contenido est\u00e1tico (y un archivo con una revisi\u00f3n espec\u00edfica es esencialmente contenido est\u00e1tico) es entregado por el mismo servidor que contiene la l\u00f3gica empresarial. En su lugar, se podr\u00eda realizar el siguiente esquema:<\/p>\n<p><\/p>\n<ul>\n<li>El servidor emite una URL para la descarga. Puede tener el formato file_id + key, donde key es una firma digital m\u00ednima que otorga el acceso al recurso durante las siguientes 24 horas.<\/li>\n<li>La entrega del archivo es manejada por un sencillo nginx con las siguientes opciones:\n<ul>\n<li>Almacenamiento en cach\u00e9 de contenido. Dado que este servicio puede estar en un servidor separado, nos hemos dejado un margen para el futuro con la posibilidad de almacenar todos los archivos descargados \u00faltimamente en el disco.<\/li>\n<li>Verificaci\u00f3n de la clave en el momento de establecer la conexi\u00f3n<\/li>\n<\/ul>\n<\/li>\n<li>Opcional: procesamiento de contenido en streaming. Por ejemplo, si comprimimos todos los archivos en el servicio, se puede realizar la descompresi\u00f3n directamente en este m\u00f3dulo. Como consecuencia: las operaciones de IO se llevan a cabo donde realmente tienen sentido. Un archivador en Java puede requerir mucha memoria adicional, sin embargo, reescribir el servicio con l\u00f3gica empresarial en lenguajes como Rust o C++ podr\u00eda resultar tambi\u00e9n ineficaz. En nuestro caso, se utilizan diferentes procesos (o incluso servicios), por lo que se puede separar de manera bastante eficiente la l\u00f3gica empresarial de las operaciones de IO.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/4dead07d5824938e09b986192ccc8f5e.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tal esquema no se asemeja mucho a la distribuci\u00f3n de contenido est\u00e1tico (ya que no estamos exportando todo el paquete de est\u00e1ticos a ning\u00fan lado), sin embargo, en realidad, este enfoque se ocupa precisamente de la entrega de datos inmutables. Adem\u00e1s, este esquema puede generalizarse a otros casos donde el contenido no solo es est\u00e1tico, sino que puede presentarse como un conjunto de bloques inmutables y no eliminables (aunque se pueden agregar).<\/p>\n<p><\/p>\n<p>Otro ejemplo (para afianzar el concepto): si has trabajado con Jenkins\/TeamCity, sabes que ambas soluciones est\u00e1n escritas en Java. Ambas son procesos Java que se encargan tanto de la orquestaci\u00f3n de builds como de la gesti\u00f3n de contenido. En particular, tienen tareas como \"transferir archivo\/carpeta desde el servidor\". Por ejemplo: entrega de artefactos, transferencia de c\u00f3digo fuente (cuando el agente no descarga el c\u00f3digo directamente del repositorio, sino que lo hace el servidor), acceso a logs. Todas estas tareas difieren en la carga de IO. As\u00ed que resulta que el servidor, que se encarga de la l\u00f3gica de negocio compleja, tambi\u00e9n debe ser capaz de manejar grandes flujos de datos de manera eficaz. Y lo m\u00e1s interesante es que se puede delegar esta operaci\u00f3n al mismo nginx de la misma manera (solo que en la solicitud hay que a\u00f1adir una clave de datos).<\/p>\n<p><\/p>\n<p>Sin embargo, si volvemos a nuestro sistema, el esquema que resulta es el siguiente:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Patrones arquitect\u00f3nicos convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/97cfbf5daaa6678a9eecc3169692f0fc.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como se puede ver, el sistema se ha vuelto radicalmente m\u00e1s complejo. Ahora no es solo un mini-proceso que almacena archivos localmente. Ahora se requiere un soporte que no es el m\u00e1s sencillo, control de versiones de API, etc. Por lo tanto, despu\u00e9s de que se dibujen todos los diagramas, es mejor evaluar en detalle si la escalabilidad justifica esos costos. Sin embargo, si desea tener la capacidad de expandir el sistema (incluyendo para trabajar con un mayor n\u00famero de usuarios), tendr\u00e1 que optar por estas soluciones. Como resultado, la arquitectura del sistema est\u00e1 lista para aumentar la carga (casi cada componente se puede clonar para escalado horizontal). El sistema se puede actualizar sin detenerlo (simplemente algunas operaciones se ralentizar\u00e1n ligeramente).<\/p>\n<p><\/p>\n<p>Como mencion\u00e9 al principio, varios servicios en l\u00ednea est\u00e1n experimentando una carga aumentada. Y algunos de ellos simplemente han dejado de funcionar correctamente. De hecho, los sistemas fallaron justo en el momento en que el negocio deber\u00eda estar generando ingresos. En lugar de posponer la entrega, en lugar de ofrecer a los clientes 'planifiquen el suministro para los pr\u00f3ximos meses', el sistema simplemente dijo 'vayan con la competencia'. Esa es la verdadera dimensi\u00f3n del costo de un bajo rendimiento: las p\u00e9rdidas ocurren precisamente cuando las ganancias ser\u00edan m\u00e1s altas.<\/p>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Conclusi\u00f3n<\/h1>\n<p><\/p>\n<p>Todos estos enfoques ya eran conocidos anteriormente. VK ha estado utilizando la idea de Hosting de Contenido Est\u00e1tico para emitir im\u00e1genes desde hace tiempo. Un mont\u00f3n de juegos en l\u00ednea utilizan un esquema de Sharding para dividir a los jugadores por regiones o para separar las ubicaciones de juego (si el mundo es \u00fanico). El enfoque de Event Sourcing se utiliza ampliamente en el correo electr\u00f3nico. La mayor\u00eda de las aplicaciones de los traders, donde los datos llegan continuamente, est\u00e1n construidas sobre el enfoque CQRS para poder filtrar los datos recibidos. Adem\u00e1s, el escalado horizontal se ha estado aplicando en muchos servicios desde hace bastante tiempo.<\/p>\n<p><\/p>\n<p>Sin embargo, lo m\u00e1s importante es que todos estos patrones se han vuelto muy f\u00e1ciles de aplicar en las aplicaciones modernas (siempre que sean pertinentes, por supuesto). Las nubes ofrecen Sharding y escalado horizontal de inmediato, lo cual es mucho m\u00e1s f\u00e1cil que pedir diferentes servidores dedicados en distintos centros de datos por su cuenta. CQRS se ha vuelto mucho m\u00e1s f\u00e1cil, en parte gracias al desarrollo de bibliotecas como RX. Hace 10 a\u00f1os, un sitio web raro podr\u00eda haber soportado esto. La configuraci\u00f3n de Event Sourcing tambi\u00e9n se hace incre\u00edblemente sencilla gracias a los contenedores ya preparados con Apache Kafka. Hace 10 a\u00f1os, esto ser\u00eda una innovaci\u00f3n; ahora es cotidiano. Lo mismo ocurre con el Hosting de Contenido Est\u00e1tico: debido a las tecnolog\u00edas m\u00e1s convenientes (incluyendo el hecho de que hay documentaci\u00f3n detallada y una gran base de respuestas), esta aproximaci\u00f3n se ha vuelto a\u00fan m\u00e1s simple.<\/p>\n<p><\/p>\n<p>Como resultado, la implementaci\u00f3n de varios patrones arquitect\u00f3nicos bastante complejos ahora es mucho m\u00e1s sencilla, lo que significa que es recomendable considerarlos de antemano. Si en una aplicaci\u00f3n de diez a\u00f1os se descart\u00f3 una de las soluciones anteriores debido al alto costo de implementaci\u00f3n y operaci\u00f3n, en una nueva aplicaci\u00f3n, o tras una refactorizaci\u00f3n, se puede crear un servicio que arquitect\u00f3nicamente ya sea tanto escalable (en t\u00e9rminos de rendimiento) como preparado para nuevas demandas de clientes (por ejemplo, para la localizaci\u00f3n de datos personales).<\/p>\n<p><\/p>\n<p>Y lo m\u00e1s importante: por favor, no utilicen estos enfoques si tienen una aplicaci\u00f3n simple. S\u00ed, son bonitos e interesantes, pero para un sitio con un pico de visita de 100 personas, a menudo se puede optar por un monolito cl\u00e1sico (al menos externamente, internamente todo se puede dividir en m\u00f3dulos, etc.).<\/p>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/dbtc\/blog\/499758\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u0412 \u0441\u0432\u0435\u0442\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437-\u0437\u0430 \u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441\u0430 \u0440\u044f\u0434 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0442\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0434\u043d\u0430 \u0438\u0437 \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445 \u0441\u0435\u0442\u0435\u0439 \u0432 \u0412\u0435\u043b\u0438\u043a\u043e\u0431\u0440\u0438\u0442\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0430 \u0441\u0430\u0439\u0442 \u0441 \u043e\u043d\u043b\u0430\u0439\u043d-\u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435 \u0445\u0432\u0430\u0442\u0438\u043b\u043e \u043c\u043e\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0418 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440, \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0431\u043e\u043b\u0435\u0435 \u043c\u043e\u0449\u043d\u043e\u0435 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0434\u043e (\u0438\u043b\u0438 \u043e\u043d\u0438 \u0443\u0439\u0434\u0443\u0442 \u043a \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u0430\u043c). \u0412 \u044d\u0442\u043e\u0439 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":80036,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-80035","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=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u0412 \u0441\u0432\u0435\u0442\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437-\u0437\u0430 \u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441\u0430 \u0440\u044f\u0434 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0442\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443.\" \/>\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\/udobnye-arhitekturnye-patterny\" \/>\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\u0423\u0434\u043e\u0431\u043d\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u0412 \u0441\u0432\u0435\u0442\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437-\u0437\u0430 \u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441\u0430 \u0440\u044f\u0434 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0442\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny\" \/>\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=\"2020-05-02T11:42:54+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-02T11:42:54+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\udd47Patrones arquitect\u00f3nicos convenientes | ProHoster","description":"\u00a1Hola, Habr! A la luz de los acontecimientos actuales debido al coronavirus, varios servicios de internet han empezado a recibir una carga aumentada.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny","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\u0423\u0434\u043e\u0431\u043d\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u0412 \u0441\u0432\u0435\u0442\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437-\u0437\u0430 \u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441\u0430 \u0440\u044f\u0434 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0442\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443.","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny","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":"2020-05-02T11:42:54+00:00","article:modified_time":"2020-05-02T11:42:54+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"80035","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":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:26:40","updated":"2022-09-28 01:38:29","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\/80035","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=80035"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/80035\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/80036"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=80035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=80035"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=80035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}