{"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\/pt\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny","title":{"rendered":"Padr\u00f5es arquiteturais convenientes","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Ol\u00e1, Habr!<\/p>\n<p><\/p>\n<p>\u00c0 luz dos eventos atuais devido ao coronav\u00edrus, v\u00e1rios servi\u00e7os online come\u00e7aram a receber uma carga aumentada. Por exemplo, <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\">uma das redes de varejo no Reino Unido simplesmente parou o site de pedidos online<\/a><\/noindex>, pois n\u00e3o havia capacidade suficiente. E nem sempre \u00e9 poss\u00edvel acelerar o servidor apenas adicionando hardware mais potente, no entanto, \u00e9 necess\u00e1rio processar as solicita\u00e7\u00f5es dos clientes (ou eles ir\u00e3o para os concorrentes).<\/p>\n<p><\/p>\n<p>Neste artigo, eu irei contar brevemente sobre as pr\u00e1ticas populares que permitir\u00e3o criar um servi\u00e7o r\u00e1pido e resiliente. Entretanto, entre os esquemas de desenvolvimento poss\u00edveis, selecionei apenas aqueles que agora <strong>s\u00e3o f\u00e1ceis de utilizar.<\/strong>Para cada item, voc\u00ea j\u00e1 possui bibliotecas prontas ou tem a possibilidade de resolver a tarefa utilizando uma plataforma em nuvem.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1 id=\"gorizontalnoe-masshtabirovanie\">Escalonamento horizontal<\/h1>\n<p><\/p>\n<p>O item mais simples e conhecido. Condicionalmente, as duas esquemas de balanceamento de carga mais comuns s\u00e3o o escalonamento horizontal e 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\">No primeiro caso,<\/a><\/noindex> voc\u00ea permite que os servi\u00e7os operem em paralelo, distribuindo assim a carga entre eles. <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\">No segundo,<\/a><\/noindex> voc\u00ea encomenda servidores mais potentes ou otimiza o c\u00f3digo.<\/p>\n<p><\/p>\n<p>Para exemplificar, vou usar um armazenamento de arquivos em nuvem abstrato, ou seja, algo como OwnCloud, OneDrive, e assim por diante.<\/p>\n<p><\/p>\n<p>A imagem padr\u00e3o desse esquema \u00e9 abaixo, no entanto, ela apenas demonstra a complexidade do sistema. Precisamos encontrar uma forma de sincronizar os servi\u00e7os. O que acontece se o usu\u00e1rio salvar um arquivo de um tablet e, em seguida, quiser visualiz\u00e1-lo a partir de um telefone?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/7512c6d8783f5e0a38cc0861b01e54c8.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nA diferen\u00e7a entre as abordagens: no escalonamento vertical, estamos prontos para aumentar a capacidade dos n\u00f3s, enquanto no horizontal \u2014 adicionamos novos n\u00f3s para distribuir a 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\">Command Query Responsibility Segregation<\/a><\/noindex> \u00e9 um padr\u00e3o bastante importante, pois permite que diferentes clientes n\u00e3o apenas se conectem a diferentes servi\u00e7os, mas tamb\u00e9m recebam correntes de eventos id\u00eanticas. Seus benef\u00edcios n\u00e3o s\u00e3o t\u00e3o evidentes para um aplicativo simples, mas s\u00e3o extremamente importantes (e simples) para um servi\u00e7o sobrecarregado. Sua ess\u00eancia \u00e9: fluxos de dados de entrada e sa\u00edda n\u00e3o devem se cruzar. Ou seja, voc\u00ea n\u00e3o pode enviar uma solicita\u00e7\u00e3o e esperar uma resposta, em vez disso, voc\u00ea envia uma solicita\u00e7\u00e3o para o servi\u00e7o A, mas recebe a resposta no servi\u00e7o B.<\/p>\n<p><\/p>\n<p>O primeiro b\u00f4nus dessa abordagem \u00e9 a capacidade de desconectar (em um sentido amplo) durante a execu\u00e7\u00e3o de uma requisi\u00e7\u00e3o longa. Para exemplificar, vamos considerar uma sequ\u00eancia mais ou menos padr\u00e3o:<\/p>\n<p><\/p>\n<ol>\n<li>O cliente enviou uma requisi\u00e7\u00e3o ao servidor.<\/li>\n<li>O servidor iniciou o processamento longo.<\/li>\n<li>O servidor respondeu ao cliente com o resultado.<\/li>\n<\/ol>\n<p><\/p>\n<p>Vamos imaginar que, no item 2, aconteceu uma quebra de conex\u00e3o (ou a rede reconectou, ou o usu\u00e1rio navegou para outra p\u00e1gina, interrompendo a conex\u00e3o). Nessa situa\u00e7\u00e3o, ser\u00e1 dif\u00edcil para o servidor enviar a resposta ao usu\u00e1rio com as informa\u00e7\u00f5es sobre o que foi processado. Ao aplicar CQRS, a sequ\u00eancia ser\u00e1 um pouco diferente:<\/p>\n<p><\/p>\n<ol>\n<li>O cliente se inscreveu para receber atualiza\u00e7\u00f5es.<\/li>\n<li>O cliente enviou uma requisi\u00e7\u00e3o ao servidor.<\/li>\n<li>O servidor respondeu 'requisi\u00e7\u00e3o recebida'.<\/li>\n<li>O servidor respondeu com o resultado atrav\u00e9s do canal do 'item 1'.<\/li>\n<\/ol>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/8a00ea93eecc7cc0754122857c5f90d0.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como pode ser visto, o esquema \u00e9 um pouco mais complexo. Al\u00e9m disso, a abordagem intuitiva de request-response aqui est\u00e1 ausente. Contudo, como \u00e9 evidente, a quebra de conex\u00e3o durante o processamento da requisi\u00e7\u00e3o n\u00e3o levar\u00e1 a um erro. Al\u00e9m disso, se o usu\u00e1rio estiver realmente conectado ao servi\u00e7o de v\u00e1rios dispositivos (por exemplo, de um celular e de um tablet), \u00e9 poss\u00edvel fazer com que a resposta chegue a ambos os dispositivos.<\/p>\n<p><\/p>\n<p>\u00c9 interessante notar que o c\u00f3digo para o processamento das mensagens recebidas torna-se semelhante (n\u00e3o 100%) tanto para os eventos que foram afetados pelo pr\u00f3prio cliente quanto para os demais eventos, inclusive de outros clientes.<\/p>\n<p><\/p>\n<p>No entanto, na pr\u00e1tica, obtemos b\u00f4nus adicionais devido ao fato de que o fluxo unidirecional pode ser processado de maneira funcional (usando RX e similares). E isso j\u00e1 \u00e9 uma grande vantagem, pois, essencialmente, o aplicativo pode se tornar completamente reativo, al\u00e9m de aplicar uma abordagem funcional. Para aplicativos mais robustos, isso pode significar uma economia significativa de recursos em desenvolvimento e manuten\u00e7\u00e3o.<\/p>\n<p><\/p>\n<p>Se combinarmos essa abordagem com escalabilidade horizontal, teremos como b\u00f4nus a capacidade de enviar requisi\u00e7\u00f5es a um servidor e receber respostas de outro. Assim, o cliente pode escolher o servi\u00e7o que lhe for mais conveniente, enquanto a sistema internamente ainda poder\u00e1processar os eventos corretamente.<\/p>\n<p><\/p>\n<h1 id=\"event-sourcing\">Event Sourcing.<\/h1>\n<p><\/p>\n<p>Como voc\u00ea sabe, uma das principais caracter\u00edsticas de um sistema distribu\u00eddo \u00e9 a aus\u00eancia de tempo comum e de uma se\u00e7\u00e3o cr\u00edtica compartilhada. Para um \u00fanico processo, voc\u00ea pode fazer a sincroniza\u00e7\u00e3o (com os mesmos mutexes), dentro da qual voc\u00ea tem certeza de que ningu\u00e9m mais est\u00e1 executando aquele c\u00f3digo. No entanto, para um sistema distribu\u00eddo, isso \u00e9 arriscado, pois isso exige sobrecarga, al\u00e9m de aniquilar toda a beleza da escalabilidade \u2014 todos os componentes ainda estar\u00e3o esperando um s\u00f3.<\/p>\n<p><\/p>\n<p>Daqui obtemos um fato importante \u2014 um sistema distribu\u00eddo r\u00e1pido n\u00e3o pode ser sincronizado, pois isso diminuiria o desempenho. Por outro lado, muitas vezes precisamos de uma certa consist\u00eancia entre os componentes. E para isso, podemos usar a abordagem de <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">consist\u00eancia eventual<\/a><\/noindex>, onde \u00e9 garantido que na aus\u00eancia de altera\u00e7\u00f5es nos dados, ap\u00f3s um certo per\u00edodo de tempo desde a \u00faltima atualiza\u00e7\u00e3o (\u201cem \u00faltima inst\u00e2ncia\u201d), todas as solicita\u00e7\u00f5es retornar\u00e3o o \u00faltimo valor atualizado.<\/p>\n<p><\/p>\n<p>\u00c9 importante entender que para bancos de dados cl\u00e1ssicos, \u00e9 frequentemente aplicada a <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Consistency_model#Strict_consistency\">consist\u00eancia estrita<\/a><\/noindex>, onde cada n\u00f3 possui as mesmas informa\u00e7\u00f5es (isso geralmente \u00e9 alcan\u00e7ado quando uma transa\u00e7\u00e3o \u00e9 considerada estabelecida apenas ap\u00f3s a resposta de um segundo servidor). Aqui h\u00e1 algumas flexibiliza\u00e7\u00f5es devido aos n\u00edveis de isolamento, no entanto, a ess\u00eancia geral permanece a mesma \u2014 voc\u00ea pode viver em um mundo totalmente consistente.<\/p>\n<p><\/p>\n<p>No entanto, voltemos \u00e0 tarefa inicial. Se parte do sistema puder ser constru\u00edda com <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">consist\u00eancia eventual<\/a><\/noindex>, ent\u00e3o podemos construir o seguinte esquema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/33c80be6bc33bd897ca9b9e5525f9ae8.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Caracter\u00edsticas importantes dessa abordagem:<\/p>\n<p><\/p>\n<ul>\n<li>Cada solicita\u00e7\u00e3o recebida \u00e9 colocada em uma fila.<\/li>\n<li>Durante o processamento da solicita\u00e7\u00e3o, o servi\u00e7o tamb\u00e9m pode colocar tarefas em outras filas.<\/li>\n<li>Cada evento de entrada tem um identificador (que \u00e9 necess\u00e1rio para a deduplica\u00e7\u00e3o).<\/li>\n<li>A fila funciona ideologicamente segundo o esquema \"apenas adicionar\". N\u00e3o \u00e9 poss\u00edvel remover elementos ou rearranj\u00e1-los.<\/li>\n<li>A fila funciona segundo o esquema FIFO (desculpe pela tautologia). Se for necess\u00e1rio realizar execu\u00e7\u00e3o paralela, ent\u00e3o em uma das etapas os objetos devem ser realocados em diferentes filas.<\/li>\n<\/ul>\n<p><\/p>\n<p>Lembro que estamos considerando o caso de um armazenamento online de arquivos. Neste caso, o sistema parecer\u00e1, aproximadamente, assim:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/b95efb29545dcde1db9432d12d00a1b1.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00c9 importante notar que os servi\u00e7os no diagrama n\u00e3o significam necessariamente um servidor separado. Mesmo o processo pode ser o mesmo. O que importa \u00e9 que, ideologicamente, essas coisas est\u00e3o separadas de tal forma que facilita a aplica\u00e7\u00e3o de escalabilidade horizontal.<\/p>\n<p><\/p>\n<p>E para dois usu\u00e1rios, o esquema ficar\u00e1 assim (os servi\u00e7os destinados a diferentes usu\u00e1rios s\u00e3o marcados com cores diferentes):<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/4c4aadc8b9dd505c3ad743e69fee4fae.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Os benef\u00edcios dessa combina\u00e7\u00e3o:<\/p>\n<p><\/p>\n<ul>\n<li>Os servi\u00e7os de processamento de informa\u00e7\u00f5es est\u00e3o separados. As filas tamb\u00e9m est\u00e3o divididas. Se precisarmos aumentar a capacidade de throughput do sistema, basta iniciar mais servi\u00e7os em um maior n\u00famero de servidores.<\/li>\n<li>Quando recebemos informa\u00e7\u00f5es do usu\u00e1rio, n\u00e3o precisamos esperar pelo salvamento completo dos dados. Pelo contr\u00e1rio, podemos simplesmente responder 'ok', e depois come\u00e7ar a trabalhar gradualmente. Ao mesmo tempo, a fila suaviza os picos, j\u00e1 que a adi\u00e7\u00e3o de um novo objeto ocorre rapidamente, e o usu\u00e1rio n\u00e3o precisa esperar por todo o ciclo completo.<\/li>\n<li>Como exemplo, adicionei um servi\u00e7o de deduplica\u00e7\u00e3o que tenta unir arquivos semelhantes. Se ele levar tempo em 1% dos casos, o cliente praticamente n\u00e3o notar\u00e1 (veja acima), o que \u00e9 uma grande vantagem, pois n\u00e3o necessitamos de 100% de velocidade e confiabilidade.<\/li>\n<\/ul>\n<p><\/p>\n<p>No entanto, as desvantagens s\u00e3o imediatamente vis\u00edveis:<\/p>\n<p><\/p>\n<ul>\n<li>Nossa sistema perdeu a coer\u00eancia rigorosa. Isso significa que, por exemplo, ao assinar diferentes servi\u00e7os, teoricamente podemos obter estados diferentes (uma vez que um dos servi\u00e7os pode n\u00e3o ter tempo para receber a notifica\u00e7\u00e3o da fila interna). Como outra consequ\u00eancia, o sistema agora n\u00e3o tem um tempo comum. Ou seja, n\u00e3o podemos, por exemplo, classificar todos os eventos apenas pelo tempo de chegada, pois os rel\u00f3gios entre os servidores podem n\u00e3o estar sincronizados (al\u00e9m do mais, ter o mesmo tempo em dois servidores \u00e9 uma utopia).<\/li>\n<li>Nenhum evento pode agora ser simplesmente revertido (como poderia ser feito com um banco de dados). Em vez disso, \u00e9 necess\u00e1rio adicionar um novo evento \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/49451237\/compensating-events-on-cqrs-es-architecture\">compensation event<\/a><\/noindex>, que mudar\u00e1 o \u00faltimo estado para o necess\u00e1rio. Como exemplo de um campo semelhante: sem reescrever o hist\u00f3rico (o que \u00e9 ruim em certas situa\u00e7\u00f5es), no git n\u00e3o \u00e9 poss\u00edvel reverter um commit, mas \u00e9 poss\u00edvel fazer um <noindex><a rel=\"nofollow\" href=\"https:\/\/git-scm.com\/docs\/git-revert\">rollback commit<\/a><\/noindex>, que, na pr\u00e1tica, simplesmente retornar\u00e1 o estado anterior. No entanto, tanto o commit incorreto quanto o rollback estar\u00e3o salvos no hist\u00f3rico.<\/li>\n<li>O esquema de dados pode mudar de vers\u00e3o para vers\u00e3o, no entanto, n\u00e3o ser\u00e1 poss\u00edvel atualizar eventos antigos para o novo padr\u00e3o (j\u00e1 que eventos n\u00e3o podem ser alterados, em princ\u00edpio).<\/li>\n<\/ul>\n<p><\/p>\n<p>Como \u00e9 evidente, o Event Sourcing se adapta bem ao CQRS. Al\u00e9m disso, implementar um sistema com filas eficientes e pr\u00e1ticas, mas sem separa\u00e7\u00e3o de fluxos de dados, j\u00e1 \u00e9 complicado por si s\u00f3, pois ser\u00e1 necess\u00e1rio adicionar pontos de sincroniza\u00e7\u00e3o que anular\u00e3o todo o efeito positivo das filas. Ao aplicar ambas as abordagens simultaneamente, \u00e9 necess\u00e1rio ajustar levemente o c\u00f3digo do funcionamento do programa. No nosso caso, ao enviar um arquivo para o servidor, a resposta \u00e9 apenas \u2018ok\u2019, o que significa apenas que \u2018a opera\u00e7\u00e3o de adi\u00e7\u00e3o do arquivo foi salva\u2019. Formalmente, isso n\u00e3o significa que os dados j\u00e1 est\u00e3o dispon\u00edveis em outros dispositivos (por exemplo, o servi\u00e7o de deduplica\u00e7\u00e3o pode estar reorganizando o \u00edndice). No entanto, ap\u00f3s algum tempo, o cliente receber\u00e1 uma notifica\u00e7\u00e3o como \u2018o arquivo X foi salvo\u2019.<\/p>\n<p><\/p>\n<p>Como resultado:<\/p>\n<p><\/p>\n<ul>\n<li>O n\u00famero de status de envio de arquivos aumenta: em vez do cl\u00e1ssico \u2018arquivo enviado\u2019, temos dois: \u2018arquivo adicionado \u00e0 fila no servidor\u2019 e \u2018arquivo salvo no armazenamento\u2019. O \u00faltimo significa que outros dispositivos j\u00e1 podem come\u00e7ar a receber o arquivo (com a ressalva de que as filas funcionam a velocidades diferentes).<\/li>\n<li>Devido ao fato de que a informa\u00e7\u00e3o sobre o envio agora chega por diferentes canais, precisamos encontrar solu\u00e7\u00f5es para obter o status de processamento do arquivo. Como consequ\u00eancia: ao contr\u00e1rio do cl\u00e1ssico request-response, o cliente pode ser reiniciado durante o processamento do arquivo, mas o status desse processamento ser\u00e1 correto. E esse ponto funciona, na verdade, imediatamente. Como resultado: agora somos mais tolerantes a falhas.<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"sharding\">Sharding<\/h1>\n<p><\/p>\n<p>Como j\u00e1 mencionado, em sistemas com event sourcing n\u00e3o h\u00e1 consist\u00eancia r\u00edgida. Portanto, podemos usar v\u00e1rios armazenamentos sem qualquer sincroniza\u00e7\u00e3o entre eles. Aproximando-nos da nossa tarefa, podemos:<\/p>\n<p><\/p>\n<ul>\n<li>Separar arquivos por tipos. Por exemplo, imagens\/v\u00eddeos podem ser decodificados e selecionados em um formato mais eficiente.<\/li>\n<li>Separar contas por pa\u00edses. Devido a v\u00e1rias leis, isso pode ser necess\u00e1rio, mas essa arquitetura permite essa possibilidade automaticamente.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/dd310df700bc39c014d0105a3425fece.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se voc\u00ea deseja transferir dados de um armazenamento para outro, as ferramentas padr\u00e3o n\u00e3o ser\u00e3o suficientes. Infelizmente, nesse caso, \u00e9 necess\u00e1rio interromper a fila, realizar a migra\u00e7\u00e3o e depois reinici\u00e1-la. Em geral, os dados n\u00e3o podem ser transferidos \"em tempo real\", no entanto, se a fila de eventos for armazenada completamente e voc\u00ea tiver c\u00f3pias dos estados anteriores do armazenamento, podemos reproduzir os eventos da seguinte maneira:<\/p>\n<p><\/p>\n<ul>\n<li>No Event Source, cada evento tem seu pr\u00f3prio identificador (idealmente, n\u00e3o decrescente). Isso significa que podemos adicionar um campo no armazenamento \u2014 id do \u00faltimo elemento processado.<\/li>\n<li>Duplicamos a fila para que todos os eventos possam ser processados para v\u00e1rios armazenamentos independentes (o primeiro \u00e9 aquele onde os dados j\u00e1 est\u00e3o, e o segundo \u00e9 novo, mas ainda vazio). A segunda fila, naturalmente, ainda n\u00e3o est\u00e1 sendo processada.<\/li>\n<li>Iniciamos a segunda fila (ou seja, come\u00e7amos a reproduzir eventos).<\/li>\n<li>Quando a nova fila estiver relativamente vazia (ou seja, a diferen\u00e7a m\u00e9dia de tempo entre a adi\u00e7\u00e3o de um elemento e sua remo\u00e7\u00e3o for aceit\u00e1vel), podemos come\u00e7ar a transferir os leitores para o novo armazenamento.<\/li>\n<\/ul>\n<p><\/p>\n<p>Como pode ser visto, em nosso sistema nunca houve e n\u00e3o h\u00e1 estrita consist\u00eancia. Existe apenas eventual consist\u00eancia, ou seja, a garantia de que os eventos s\u00e3o processados na mesma ordem (no entanto, possivelmente com diferentes atrasos). E, aproveitando isso, podemos transferir dados comparativamente facilmente sem interromper o sistema para o outro lado do planeta.<\/p>\n<p><\/p>\n<p>Assim, continuando com nosso exemplo de armazenamento online para arquivos, essa arquitetura j\u00e1 nos oferece uma s\u00e9rie de benef\u00edcios:<\/p>\n<p><\/p>\n<ul>\n<li>Podemos mover objetos mais perto dos usu\u00e1rios de forma din\u00e2mica. Isso pode melhorar a qualidade do servi\u00e7o. <\/li>\n<li>Podemos armazenar parte dos dados dentro das empresas. Por exemplo, usu\u00e1rios corporativos geralmente exigem que seus dados sejam mantidos em data centers controlados (para evitar vazamentos de dados). Com o sharding, podemos facilmente suportar isso. A tarefa se torna ainda mais f\u00e1cil se o cliente tiver uma nuvem compat\u00edvel (por exemplo, <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>E o mais importante \u2014 podemos n\u00e3o fazer isso. Afinal, inicialmente ficar\u00edamos satisfeitos com um \u00fanico armazenamento para todas as contas (para come\u00e7ar a trabalhar mais rapidamente). E a caracter\u00edstica fundamental desse sistema \u2014 embora seja escal\u00e1vel, na fase inicial \u00e9 bastante simples. Basta n\u00e3o escrever c\u00f3digo que funcione com um milh\u00e3o de filas independentes, etc. Se necess\u00e1rio, isso pode ser feito no futuro.<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"static-content-hosting\">Hospedagem de Conte\u00fado Est\u00e1tico<\/h1>\n<p><\/p>\n<p>Esse ponto pode parecer bastante \u00f3bvio, mas ainda assim \u00e9 necess\u00e1rio para um aplicativo sobrecarregado mais ou menos padr\u00e3o. Sua ess\u00eancia \u00e9 simples: todo o conte\u00fado est\u00e1tico \u00e9 distribu\u00eddo n\u00e3o a partir do mesmo servidor onde o aplicativo est\u00e1 localizado, mas de servidores especiais dedicados a essa tarefa. Como resultado, essas opera\u00e7\u00f5es s\u00e3o realizadas mais rapidamente (um nginx, por exemplo, entrega arquivos de maneira mais \u00e1gil e menos custosa do que um servidor Java). Al\u00e9m disso, a arquitetura CDN (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Content_delivery_network\">Rede de Distribui\u00e7\u00e3o de Conte\u00fado<\/a><\/noindex>) permite posicionar nossos arquivos mais perto dos usu\u00e1rios finais, o que melhora a experi\u00eancia de uso do servi\u00e7o.<\/p>\n<p><\/p>\n<p>O exemplo mais simples e padr\u00e3o de conte\u00fado est\u00e1tico \u00e9 um conjunto de scripts e imagens para um site. Com eles, tudo \u00e9 simples \u2014 eles s\u00e3o conhecidos de antem\u00e3o, em seguida, o arquivo \u00e9 carregado nos servidores CDN, de onde \u00e9 distribu\u00eddo para os usu\u00e1rios finais.<\/p>\n<p><\/p>\n<p>No entanto, na pr\u00e1tica, para conte\u00fado est\u00e1tico, pode-se aplicar uma abordagem algo semelhante \u00e0 arquitetura lambda. Vamos voltar \u00e0 nossa tarefa (armazenamento online de arquivos), na qual precisamos distribuir arquivos para os usu\u00e1rios. A solu\u00e7\u00e3o mais simples seria criar um servi\u00e7o que, para cada solicita\u00e7\u00e3o do usu\u00e1rio, realiza todas as verifica\u00e7\u00f5es necess\u00e1rias (autentica\u00e7\u00e3o etc.) e depois baixa o arquivo diretamente do nosso armazenamento. A principal desvantagem dessa abordagem \u00e9 que o conte\u00fado est\u00e1tico (e um arquivo com uma revis\u00e3o espec\u00edfica, na verdade, \u00e9 um conte\u00fado est\u00e1tico) \u00e9 distribu\u00eddo pelo mesmo servidor que cont\u00e9m a l\u00f3gica de neg\u00f3cios. Em vez disso, podemos criar o seguinte esquema:<\/p>\n<p><\/p>\n<ul>\n<li>O servidor gera uma URL para download. Ela pode ser do tipo file_id + key, onde key \u00e9 uma assinatura digital curta que concede acesso ao recurso por at\u00e9 um dia.<\/li>\n<li>A distribui\u00e7\u00e3o do arquivo \u00e9 feita por um nginx simples com as seguintes op\u00e7\u00f5es:\n<ul>\n<li>Cache de conte\u00fado. Como este servi\u00e7o pode estar em um servidor separado, deixamos uma margem para o futuro, com a possibilidade de armazenar todos os \u00faltimos arquivos baixados em disco.<\/li>\n<li>Verifica\u00e7\u00e3o da chave no momento da conex\u00e3o<\/li>\n<\/ul>\n<\/li>\n<li>Opcional: processamento de conte\u00fado em fluxo. Por exemplo, se comprimimos todos os arquivos no servi\u00e7o, podemos descompact\u00e1-los diretamente neste m\u00f3dulo. Como consequ\u00eancia: opera\u00e7\u00f5es de IO s\u00e3o realizadas onde fazem mais sentido. Um arquivador em Java pode consumir muita mem\u00f3ria adicional, no entanto, reescrever o servi\u00e7o com l\u00f3gica de neg\u00f3cios em Rust\/C++ pode tamb\u00e9m ser ineficaz. No nosso caso, utilizamos diferentes processos (ou at\u00e9 mesmo servi\u00e7os), portanto, \u00e9 poss\u00edvel separar de maneira eficiente a l\u00f3gica de neg\u00f3cios e as opera\u00e7\u00f5es de IO.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/4dead07d5824938e09b986192ccc8f5e.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esse esquema n\u00e3o se parece muito com a entrega de conte\u00fado est\u00e1tico (uma vez que n\u00e3o estamos transferindo todo o pacote de est\u00e1tica para algum lugar), mas na realidade, essa abordagem realmente se dedica \u00e0 entrega de dados imut\u00e1veis. Al\u00e9m disso, esse esquema pode ser generalizado para outros casos, onde o conte\u00fado n\u00e3o \u00e9 apenas est\u00e1tico, mas pode ser representado como um conjunto de blocos imut\u00e1veis e n\u00e3o remov\u00edveis (embora possam ser adicionados).<\/p>\n<p><\/p>\n<p>Como mais um exemplo (para refor\u00e7ar): se voc\u00ea trabalhou com Jenkins\/TeamCity, sabe que ambas as solu\u00e7\u00f5es s\u00e3o escritas em Java. Ambas representam um processo Java que lida tanto com a orquestra\u00e7\u00e3o de builds quanto com a gest\u00e3o de conte\u00fado. Em particular, ambos t\u00eam tarefas do tipo \"transferir arquivo\/pasta do servidor\". Por exemplo: entrega de artefatos, transfer\u00eancia de c\u00f3digo-fonte (quando o agente n\u00e3o baixa o c\u00f3digo diretamente do reposit\u00f3rio, mas o servidor faz isso), acesso aos logs. Todas essas tarefas t\u00eam diferentes cargas de IO. Ou seja, o servidor, respons\u00e1vel pela l\u00f3gica de neg\u00f3cios complexa, tamb\u00e9m deve ser capaz de empurrar efetivamente grandes fluxos de dados. E o mais interessante \u00e9 que essa opera\u00e7\u00e3o pode ser delegada ao nginx da mesma forma (exceto que a solicita\u00e7\u00e3o deve incluir a chave de dados).<\/p>\n<p><\/p>\n<p>No entanto, se voltarmos ao nosso sistema, temos um esquema semelhante:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Padr\u00f5es arquiteturais convenientes\" src=\"\/wp-content\/uploads\/2020\/05\/97cfbf5daaa6678a9eecc3169692f0fc.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como observado, o sistema se tornou radicalmente mais complexo. N\u00e3o \u00e9 mais apenas um mini-processo que armazena arquivos localmente. Agora, \u00e9 necess\u00e1ria uma manuten\u00e7\u00e3o que n\u00e3o \u00e9 t\u00e3o simples, controle de vers\u00f5es de API, etc. Portanto, depois que todos os diagramas s\u00e3o desenhados, \u00e9 melhor avaliar detalhadamente se o custo da escalabilidade vale a pena. Contudo, se voc\u00ea deseja ter a capacidade de expandir o sistema (incluindo para lidar com um n\u00famero ainda maior de usu\u00e1rios), ter\u00e1 que considerar solu\u00e7\u00f5es desse tipo. O resultado \u00e9 que a arquitetura do sistema est\u00e1 preparada para um aumento de carga (praticamente todos os componentes podem ser clonados para escalabilidade horizontal). O sistema pode ser atualizado sem precisar ser parado (apenas algumas opera\u00e7\u00f5es podem desacelerar ligeiramente).<\/p>\n<p><\/p>\n<p>Como eu mencionei no in\u00edcio, atualmente v\u00e1rios servi\u00e7os na internet est\u00e3o enfrentando uma carga maior. E alguns deles simplesmente deixaram de operar corretamente. Na verdade, os sistemas falharam exatamente no momento em que o neg\u00f3cio precisava gerar receita. Ou seja, em vez de realizar uma entrega programada, em vez de oferecer aos clientes para \"planejar a entrega nos pr\u00f3ximos meses\", o sistema simplesmente disse \"v\u00e1 para a concorr\u00eancia\". Esta \u00e9, na verdade, o custo da baixa performance: as perdas ocorrer\u00e3o precisamente quando os lucros poderiam ser mais altos.<\/p>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Conclus\u00e3o<\/h1>\n<p><\/p>\n<p>Todas essas abordagens j\u00e1 eram conhecidas anteriormente. O VK, por exemplo, j\u00e1 utiliza a ideia de Static Content Hosting para a entrega de imagens. Muitas games online utilizam o esquema de Sharding para dividir os jogadores por regi\u00f5es ou para separar zonas de jogo (caso o mundo seja \u00fanico). O Event Sourcing \u00e9 amplamente utilizado em e-mails. A maioria dos aplicativos de traders, onde os dados chegam continuamente, \u00e9 na verdade constru\u00edda com a abordagem CQRS, para poder filtrar os dados recebidos. E a escalabilidade horizontal j\u00e1 \u00e9 aplicada h\u00e1 bastante tempo em muitos servi\u00e7os.<\/p>\n<p><\/p>\n<p>No entanto, o mais importante \u00e9 que todos esses padr\u00f5es se tornaram muito f\u00e1ceis de aplicar em aplica\u00e7\u00f5es modernas (se forem adequados, \u00e9 claro). As nuvens oferecem Sharding e escalabilidade horizontal de imediato, o que \u00e9 muito mais f\u00e1cil do que solicitar diferentes servidores dedicados em diferentes data centers por conta pr\u00f3pria. CQRS se tornou muito mais f\u00e1cil, pelo menos devido ao desenvolvimento de bibliotecas como RX. H\u00e1 10 anos, era raro um site conseguir suportar isso. Event Sourcing tamb\u00e9m \u00e9 configurado incrivelmente f\u00e1cil gra\u00e7as aos cont\u00eaineres prontos com Apache Kafka. H\u00e1 10 anos isso seria uma inova\u00e7\u00e3o, agora \u00e9 algo comum. O mesmo vale para o Static Content Hosting: devido a tecnologias mais acess\u00edveis (inclusive por haver documenta\u00e7\u00e3o detalhada e uma grande base de respostas), essa abordagem tornou-se ainda mais simples.<\/p>\n<p><\/p>\n<p>Como resultado, a implementa\u00e7\u00e3o de uma s\u00e9rie de padr\u00f5es arquiteturais bastante complexos tornou-se agora muito mais f\u00e1cil, e isso significa que vale a pena prestar aten\u00e7\u00e3o antecipadamente. Se em uma aplica\u00e7\u00e3o de dez anos foi descartada uma das solu\u00e7\u00f5es acima devido ao alto custo de implementa\u00e7\u00e3o e opera\u00e7\u00e3o, agora, em uma nova aplica\u00e7\u00e3o, ou ap\u00f3s um refatoramento, \u00e9 poss\u00edvel criar um servi\u00e7o que j\u00e1 ser\u00e1 arquitetonicamente extens\u00edvel (em termos de desempenho) e pronto para novas demandas dos clientes (por exemplo, para a localiza\u00e7\u00e3o de dados pessoais).<\/p>\n<p><\/p>\n<p>E o mais importante: por favor, n\u00e3o utilize essas abordagens se voc\u00ea tiver uma aplica\u00e7\u00e3o simples. Sim, elas s\u00e3o bonitas e interessantes, no entanto, para um site com pico de 100 visitantes, muitas vezes \u00e9 poss\u00edvel utilizar um mon\u00f3lito cl\u00e1ssico (pelo menos externamente; internamente, tudo pode ser fragmentado em m\u00f3dulos, etc.).<\/p>\n<p>Fonte: <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.3 - 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\/pt\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny\" \/>\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\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\/pt\/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\udd47Padr\u00f5es arquiteturais convenientes | ProHoster","description":"Ol\u00e1, Habr! \u00c0 luz dos eventos atuais devido ao coronav\u00edrus, diversos servi\u00e7os na internet come\u00e7aram a enfrentar uma carga aumentada.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/udobnye-arhitekturnye-patterny","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\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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/80035","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=80035"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/80035\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/80036"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=80035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=80035"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=80035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}