{"id":55009,"date":"2020-01-10T00:00:00","date_gmt":"2020-01-09T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo"},"modified":"2020-02-18T14:03:04","modified_gmt":"2020-02-18T11:03:04","slug":"arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","title":{"rendered":"Arquitetura de armazenamento e entrega de fotos no Badoo","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/04d68ff091d9d271bfd352a6639e2f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Artem Denisov ( <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/users\/bo0rsh201\/\" class=\"user_link\">bo0rsh201<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/badoo\/\">Badoo<\/a><\/noindex>)<\/h2>\n<p>\nBadoo \u00e9 o maior site de encontros do mundo. No momento, temos cerca de 330 milh\u00f5es de usu\u00e1rios registrados em todo o mundo. Mas, o que \u00e9 muito mais importante no contexto da nossa conversa de hoje, \u00e9 que armazenamos cerca de 3 petabytes de fotos dos usu\u00e1rios. A cada dia, nossos usu\u00e1rios enviam cerca de 3,5 milh\u00f5es de novas fotos, e a carga de leitura \u00e9 de aproximadamente <b>80 mil solicita\u00e7\u00f5es por segundo<\/b>. Isso \u00e9 bastante para nosso backend, e \u00e0s vezes enfrentamos dificuldades com isso.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4e4690f9b0d95bd76fbbc1cd6805c26c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVou falar sobre o design desse sistema que armazena e fornece fotos de maneira geral, e darei uma perspectiva de desenvolvedor. Falarei sobre como ele se desenvolveu, com uma breve retrospectiva, onde marcarei os principais marcos, mas focarei mais detalhadamente nas solu\u00e7\u00f5es que estamos usando atualmente.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nE agora vamos come\u00e7ar.<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"SU9ETg39FEg\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/SU9ETg39FEg\/hqdefault.jpg\" alt=\"Por que no hosting comum a administra\u00e7\u00e3o do PrestaShop \u00e9 lenta, e no seu n\u00e3o \u00e9?\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nComo j\u00e1 mencionei, ser\u00e1 uma retrospectiva, e para come\u00e7ar, vamos pegar o exemplo mais simples.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/22b9627cda7ccadd9869b64e9d043d89.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTemos um desafio comum: precisamos receber, armazenar e fornecer as fotos dos usu\u00e1rios. De forma geral, o desafio \u00e9 amplo, e podemos usar qualquer coisa:<\/p>\n<ul>\n<li>um armazenamento em nuvem moderno,<\/li>\n<li>uma solu\u00e7\u00e3o pronta, que tamb\u00e9m s\u00e3o muitas atualmente;<\/li>\n<li>podemos configurar v\u00e1rias m\u00e1quinas em nosso data center e colocar grandes discos r\u00edgidos nelas para armazenar fotos l\u00e1.<\/li>\n<\/ul>\n<p>\nHistoricamente, o Badoo \u2014 tanto agora quanto na \u00e9poca em que estava apenas come\u00e7ando \u2014 opera em nossos pr\u00f3prios servidores, dentro de nossos pr\u00f3prios data centers. Portanto, para n\u00f3s, essa op\u00e7\u00e3o era a mais adequada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9434fbabada15670297c551066ad7e71.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSimplesmente pegamos algumas m\u00e1quinas, nomeamos de \"photos\", e assim formamos um cluster que armazena fotos. Mas, parece que falta algo. Para que tudo funcione, precisamos de alguma forma determinar em qual m\u00e1quina algumas fotos ser\u00e3o armazenadas. E aqui, n\u00e3o \u00e9 preciso descobrir a p\u00f3lvora.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/36258e7107fd8c60f7e9e563a2cb681c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAdicionamos ao nosso armazenamento com informa\u00e7\u00f5es sobre os usu\u00e1rios um campo. Esse ser\u00e1 a chave de sharding. No nosso caso, o nomeamos como place_id, e esse id de locais indica onde as fotos dos usu\u00e1rios s\u00e3o armazenadas. N\u00f3s constitu\u00edmos mapas.<\/p>\n<p>Na primeira fase, isso pode at\u00e9 ser feito manualmente \u2014 dizemos que a foto deste usu\u00e1rio com esse local ser\u00e1 armazenada em tal servidor. Gra\u00e7as a este mapa, sabemos sempre quando o usu\u00e1rio carrega uma foto, onde salv\u00e1-la e de onde entreg\u00e1-la.<\/p>\n<p>\u00c9 um esquema absolutamente trivial, mas tem algumas vantagens significativas. Primeiro \u2014 \u00e9 simples, como j\u00e1 mencionei, e segundo \u2014 com essa abordagem, podemos facilmente escalar horizontalmente, apenas entregando novos dispositivos e adicionando-os ao mapa. N\u00e3o precisamos fazer mais nada.<\/p>\n<p>Assim foi por um tempo conosco.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3effb442702f162f7bad9c18ec54392e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIsso foi por volta de 2009. Est\u00e1vamos entregando dispositivos, entregando\u2026<\/p>\n<p>E em certo momento come\u00e7amos a notar que esse esquema apresentava certas desvantagens. Quais desvantagens?<\/p>\n<p>Em primeiro lugar, \u00e9 a capacidade limitada. N\u00e3o conseguimos colocar tantos discos r\u00edgidos em um servidor f\u00edsico quanto gostar\u00edamos. E isso se tornou um problema ao longo do tempo e com o crescimento do dataset.<\/p>\n<p>E o segundo. Essa configura\u00e7\u00e3o de m\u00e1quinas \u00e9 at\u00edpica, pois \u00e9 dif\u00edcil reutilizar essas m\u00e1quinas em outros clusters, elas s\u00e3o bastante espec\u00edficas, ou seja, devem ser de baixo desempenho, mas ao mesmo tempo ter um disco r\u00edgido grande.<\/p>\n<p>Isso tudo era em 2009, mas, na verdade, esses requisitos ainda s\u00e3o relevantes hoje. Temos uma retrospectiva, ent\u00e3o em 2009 tudo estava ruim com isso.<\/p>\n<p>E o \u00faltimo ponto \u2014 \u00e9 o pre\u00e7o.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e49010eaeab139199d8fe010caa65bf0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNaquela \u00e9poca, o pre\u00e7o era bastante elevado, e precis\u00e1vamos procurar alternativas. Ou seja, precis\u00e1vamos encontrar uma maneira melhor de utilizar tanto o espa\u00e7o nos data centers quanto os servidores f\u00edsicos em que tudo isso estava instalado. Nossos engenheiros de sistema come\u00e7aram uma grande pesquisa, na qual revisaram v\u00e1rias op\u00e7\u00f5es diferentes. Eles tamb\u00e9m consideraram sistemas de arquivos em cluster, como PolyCeph e Lustre. Havia problemas com desempenho e era uma opera\u00e7\u00e3o bastante pesada. Desistimos. Tentamos montar todo o dataset via NFS em cada dispositivo, para assim escalar de alguma forma. A leitura tamb\u00e9m n\u00e3o funcionou bem, tentamos diferentes solu\u00e7\u00f5es de v\u00e1rios fornecedores.<\/p>\n<p>E no final, decidimos usar o que chamamos de Storage Area Network.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e99402fa641f3bd5fc8d57a9f8995642.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEstes s\u00e3o grandes SHD projetados para armazenar grandes volumes de dados. Eles consistem em prateleiras com discos que est\u00e3o montadas em m\u00e1quinas de entrega finais via fibra \u00f3ptica. Assim, temos um pequeno pool de m\u00e1quinas, e esses SHD, que s\u00e3o transparentes para nossa l\u00f3gica de entrega, ou seja, para o nosso nginx ou qualquer outro, atendem \u00e0s solicita\u00e7\u00f5es por essas fotos.<\/p>\n<p>Essa solu\u00e7\u00e3o tinha benef\u00edcios claros. \u00c9 um SHD. Ele \u00e9 voltado para armazenar fotos. Isso acaba sendo mais barato do que simplesmente configurar as m\u00e1quinas com discos r\u00edgidos.<\/p>\n<p>Um segundo benef\u00edcio. <\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7fd2e7d629cc239096b14c68be5f76bf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c9 que a capacidade aumentou muito, ou seja, conseguimos armazenar muito mais armazenamento em um espa\u00e7o muito menor.<\/p>\n<p>Mas houve desvantagens que se tornaram evidentes rapidamente. Com o aumento do n\u00famero de usu\u00e1rios e da carga neste sistema, come\u00e7aram a surgir problemas de desempenho. E o problema aqui \u00e9 bastante \u00f3bvio \u2014 qualquer SHD destinado a armazenar muitas fotos em um pequeno volume tende a sofrer com leituras intensivas. Isso \u00e9 realmente aplic\u00e1vel a qualquer armazenamento em nuvem e qualquer outra coisa. Atualmente, n\u00e3o existe armazenamento perfeito que seja infinitamente escal\u00e1vel, que voc\u00ea possa encher com qualquer coisa, e que suporte leituras muito bem. Especialmente leituras aleat\u00f3rias.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/566e836e2fe13a2a3d040ae3fa865d6d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nComo no caso das nossas fotos, porque as fotos s\u00e3o solicitadas de forma n\u00e3o sequencial, e isso afeta muito o seu desempenho.<\/p>\n<p>Mesmo com os n\u00fameros de hoje, se tivermos mais de 500 RPS por imagens em uma m\u00e1quina conectada ao armazenamento, j\u00e1 come\u00e7am os problemas. E isso foi bastante ruim para n\u00f3s, porque o n\u00famero de usu\u00e1rios est\u00e1 crescendo, tudo deve piorar. Precisamos otimizar isso de alguma forma.<\/p>\n<p>Para otimizar, na \u00e9poca decidimos, obviamente, olhar para o perfil de carga \u2014 o que realmente est\u00e1 acontecendo, o que precisa ser otimizado.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d67310e6b90c4ee1337065790576c9a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE aqui tudo joga a nosso favor.<\/p>\n<p>Eu j\u00e1 mencionei no primeiro slide: temos 80 mil solicita\u00e7\u00f5es por segundo para leitura com apenas 3,5 milh\u00f5es de uploads por dia. Ou seja, h\u00e1 uma diferen\u00e7a de tr\u00eas ordens de grandeza. \u00c9 evidente que precisamos otimizar a leitura e praticamente est\u00e1 claro como.<\/p>\n<p>H\u00e1 mais um detalhe. A natureza do servi\u00e7o \u00e9 que a pessoa se registra, faz o upload de uma foto, depois come\u00e7a a ver outras pessoas ativamente, curtir suas fotos, e \u00e9 ativamente mostrado para outras pessoas. Em seguida, ela encontra um par ou n\u00e3o, dependendo de como as coisas se desenrolam, e por um tempo para de usar o servi\u00e7o. Nesse momento, quando ela est\u00e1 usando, suas fotos s\u00e3o muito populares \u2014 s\u00e3o muito procuradas, vistas por muitas pessoas. Assim que ela para de fazer isso, rapidamente ela sai desse intenso destaque para outras pessoas, como antes, e suas fotos praticamente n\u00e3o s\u00e3o mais solicitadas.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/dcc7e306055d8f2b0895f24679bfc3e2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOu seja, temos um conjunto de dados muito pequeno e quente. Mas, ao mesmo tempo, h\u00e1 uma quantidade significativa de solicita\u00e7\u00f5es. E uma solu\u00e7\u00e3o obviamente adequada aqui \u00e9 adicionar cache.<\/p>\n<p>O cache com LRU resolver\u00e1 todos os nossos problemas. O que fazemos?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/2bd0c88a97d928f386db21549fc02500.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAdicionamos um cluster relativamente pequeno, que chamamos de fotocache (photoscache), antes do nosso grande cluster de armazenamento. Isso, na verdade, \u00e9 apenas um proxy de cache.<\/p>\n<p>Como isso funciona internamente? Aqui est\u00e1 nosso usu\u00e1rio, aqui est\u00e1 o armazenamento. Tudo como antes. O que acrescentamos entre eles?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7b7b5f102f1c012b2aef8f02ec731fac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c9 simplesmente uma m\u00e1quina com um disco local f\u00edsico que \u00e9 r\u00e1pido. \u00c9 um SSD, por exemplo. E nesse disco armazenamos algum cache local.<\/p>\n<p>Como isso se parece? O usu\u00e1rio envia um pedido por uma foto. O NGINX procura primeiro no cache local. Se n\u00e3o encontrar, faz um proxy_pass para nosso armazenamento, baixa a foto de l\u00e1 e a entrega ao usu\u00e1rio.<\/p>\n<p>Mas isso \u00e9 bastante simples e n\u00e3o est\u00e1 claro o que acontece l\u00e1 dentro. Funciona mais ou menos assim.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/46be24df171d1008e2a9099b7e4c9be6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO cache \u00e9 logicamente dividido em tr\u00eas camadas. Quando digo \u2018tr\u00eas camadas\u2019, isso n\u00e3o significa que h\u00e1 um sistema complicado. N\u00e3o, \u00e9 simplesmente, em termos gerais, tr\u00eas diret\u00f3rios no sistema de arquivos:<\/p>\n<ol>\n<li>Este \u00e9 o buffer, onde as fotos rec\u00e9m-carregadas do proxy v\u00e3o parar.<\/li>\n<li>Este \u00e9 o cache quente, onde est\u00e3o armazenadas as fotos que est\u00e3o sendo ativamente solicitadas agora.<\/li>\n<li>E o cache frio, para onde as fotos s\u00e3o gradualmente empurradas do quente, quando recebem menos solicita\u00e7\u00f5es.<\/li>\n<\/ol>\n<p>\nPara que isso funcione, precisamos gerenciar esse cache de alguma forma, precisamos mover fotos nele etc. Esse tamb\u00e9m \u00e9 um processo bastante primitivo.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9b16fe3e99a5f88f06169f6e5eedf2b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO Nginx simplesmente registra no RAMDisk access.log para cada solicita\u00e7\u00e3o, onde indica o caminho da foto que est\u00e1 servindo (caminho relativo, naturalmente) e qual se\u00e7\u00e3o a est\u00e1 servindo. Ou seja, pode estar escrito \"foto 1\" e depois um buffer, cache quente, cache frio ou proxy.<\/p>\n<p>Dependendo disso, precisamos de alguma forma decidir o que fazer com a foto.<\/p>\n<p>Em cada m\u00e1quina, temos um pequeno daemon que l\u00ea constantemente esse log e mant\u00e9m as estat\u00edsticas sobre o uso das fotos em sua mem\u00f3ria.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0dceda5e5ff432d1609520f0c152f152.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEle simplesmente coleta l\u00e1, mant\u00e9m contadores e periodicamente faz o seguinte. As fotos que s\u00e3o ativamente solicitadas, que recebem muitas requisi\u00e7\u00f5es, ele move para o cache quente, onde quer que estejam.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/941c13ecfea88372f3a7eb62d81b0c4e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs fotos que s\u00e3o solicitadas raramente e come\u00e7aram a ser solicitadas com menos frequ\u00eancia, ele gradualmente empurra do cache quente para o frio.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a07235246995ad2fa4e6aeccae23a629.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE quando o espa\u00e7o no cache acaba, come\u00e7amos a deletar tudo do cache frio indiscriminadamente. E isso, ali\u00e1s, funciona muito bem.<\/p>\n<p>Para que a foto seja armazenada imediatamente durante o proxy para o buffer, usamos a diretiva proxy_store e o buffer - que tamb\u00e9m \u00e9 um RAMDisk, ou seja, para o usu\u00e1rio isso funciona muito rapidamente. Isso diz respeito \u00e0s entranhas do pr\u00f3prio servidor de cache.<\/p>\n<p>Resta a quest\u00e3o de como distribuir as requisi\u00e7\u00f5es entre esses servidores.<\/p>\n<p>Suponha que temos um cluster de vinte m\u00e1quinas de armazenamento e tr\u00eas servidores de cache (foi assim que aconteceu).<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6bc970b687701f3b6d57e153e3abed18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrecisamos de alguma forma determinar quais requisi\u00e7\u00f5es buscam quais fotos e para onde direcion\u00e1-las.<\/p>\n<p>A op\u00e7\u00e3o mais simples \u00e9 o Round Robin. Ou fazer isso aleatoriamente?<\/p>\n<p>Isso, evidentemente, tem uma s\u00e9rie de desvantagens, porque estaremos utilizando o cache de forma muito ineficiente nessa situa\u00e7\u00e3o. As requisi\u00e7\u00f5es cair\u00e3o em m\u00e1quinas aleat\u00f3rias: aqui foi armazenada, na vizinha j\u00e1 n\u00e3o h\u00e1. E tudo isso funcionar\u00e1, se funcionar, de forma muito ruim. Mesmo com um n\u00famero reduzido de m\u00e1quinas no cluster.<\/p>\n<p>Precisamos de alguma forma de identificar claramente em qual servidor enviar cada requisi\u00e7\u00e3o.<\/p>\n<p>H\u00e1 um jeito simples. Pegamos o hash da URL ou o hash da nossa chave de sharding que est\u00e1 na URL e o dividimos inteiramente pelo n\u00famero de servidores. Vai funcionar? Vai.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/794a82ac1268b651ab936f0225b802a2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOu seja, temos um request cem por cento garantido, por exemplo, para algum \"example_url\" sempre ser\u00e1 direcionado para o servidor com \u00edndice \"2\", e o cache ser\u00e1 constantemente utilizado da melhor forma poss\u00edvel.<\/p>\n<p>Mas surge um problema com o re-sharding nesse esquema. Re-sharding \u2014 o que quero dizer \u00e9 a altera\u00e7\u00e3o no n\u00famero de servidores.<\/p>\n<p>Vamos supor que nosso cluster de cache parou de conseguir lidar, e decidimos adicionar mais uma m\u00e1quina.<\/p>\n<p>Estamos adicionando.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5f2fcba4c4f267c069811c3677bd0213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAgora temos tudo dividido n\u00e3o por tr\u00eas, mas por quatro. Assim, praticamente todas as chaves que t\u00ednhamos, praticamente todos os URLs agora vivem em outros servidores. Todo o cache foi invalidado instantaneamente. Todos os requests inundaram nosso cluster de armazenamento, ele come\u00e7ou a falhar, houve uma recusa de servi\u00e7o e usu\u00e1rios insatisfeitos. N\u00e3o queremos que isso aconte\u00e7a.<\/p>\n<p>Essa op\u00e7\u00e3o tamb\u00e9m n\u00e3o nos serve.<\/p>\n<p>Ent\u00e3o, o que devemos fazer? Precisamos de alguma forma de usar o cache de maneira eficaz, sempre direcionando um request para o mesmo servidor, mas ao mesmo tempo ser resilientes ao re-sharding. E existe uma solu\u00e7\u00e3o, que n\u00e3o \u00e9 exatamente complicada. Chama-se hashing consistente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1380758686274df9755a7ebf7d1c8753.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nComo isso funciona?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/44f97abfac46fa9f361055548819e8a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPegamos alguma fun\u00e7\u00e3o da chave de sharding e dispersamos todos os seus valores em uma circunfer\u00eancia. Ou seja, no ponto 0 temos os seus valores m\u00ednimos e m\u00e1ximos convergindo. Depois, colocamos todos os nossos servidores nessa mesma circunfer\u00eancia de maneira mais ou menos assim:<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d470ec615a789913a6baa2726b05acea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCada servidor \u00e9 determinado por um ponto, e o setor que vai at\u00e9 ele, no sentido hor\u00e1rio, \u00e9 atendido por esse host. Quando recebemos requests, vemos imediatamente que, por exemplo, o request A \u2014 tem um hash assim \u2014 e \u00e9 atendido pelo servidor 2. O request B \u2014 pelo servidor 3. E assim por diante.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fcdbd1caa9f1162cf02e8b0a1c79cb74.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO que acontece nessa situa\u00e7\u00e3o durante o re-sharding?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7386cda826e9419d5f8a9a0d6d6703c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00e3o invalidamos todo o cache, como antes, e n\u00e3o deslocamos todas as chaves, mas deslocamos cada setor por uma pequena dist\u00e2ncia de modo que, para ocupar o espa\u00e7o liberado, digamos assim, caber\u00e1 nosso sexto servidor, que queremos adicionar, e o colocamos l\u00e1.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8680e0cf023ce911b4d162e9102c0545.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nClaro, em tal situa\u00e7\u00e3o, as chaves tamb\u00e9m sofrem. Mas elas se deslocam muito menos do que antes. E vemos que nossas duas primeiras chaves permaneceram em seus servidores, enquanto o servidor de cache mudou apenas para a \u00faltima chave. Isso funciona de maneira bastante eficiente, e se voc\u00ea adicionar novos hosts de forma incremental, n\u00e3o h\u00e1 um grande problema. Voc\u00ea adiciona aos poucos, espera at\u00e9 que o cache seja preenchido novamente, e tudo funciona bem.<\/p>\n<p>A \u00fanica d\u00favida que resta \u00e9 sobre as falhas. Suponhamos que um de nossos servidores tenha ido para o saco.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8e3301af782ce8983716c4bc9add79a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE n\u00f3s n\u00e3o gostar\u00edamos de regenerar esse mapa nesse momento, invalidar parte do cache e assim por diante, se, por exemplo, a m\u00e1quina reiniciou e precisamos atender \u00e0s solicita\u00e7\u00f5es. Mantemos simplesmente um cache fotogr\u00e1fico de reserva em cada local, que atua como substituto para qualquer m\u00e1quina que esteja fora de opera\u00e7\u00e3o no momento. E se, de repente, um servidor se tornar indispon\u00edvel, o tr\u00e1fego vai para l\u00e1. Naturalmente, n\u00e3o temos cache l\u00e1, ou seja, ele est\u00e1 frio, mas, pelo menos, as solicita\u00e7\u00f5es dos usu\u00e1rios s\u00e3o processadas. Se isso for um intervalo curto, lidamos com isso tranquilamente. Apenas haver\u00e1 uma carga maior no storage. Se o intervalo for longo, j\u00e1 podemos tomar a decis\u00e3o \u2014 remover esse servidor do mapa ou n\u00e3o, ou talvez substitu\u00ed-lo por outro.<\/p>\n<p>Isso em rela\u00e7\u00e3o ao sistema de cache. Vamos ver os resultados.<\/p>\n<p>\u00c0 primeira vista, n\u00e3o h\u00e1 nada complicado aqui. Mas esse m\u00e9todo de gerenciamento do cache nos deu uma taxa de acerto de cerca de 98%. Ou seja, dessas 80 mil solicita\u00e7\u00f5es por segundo, apenas 1600 chegam aos storages, e isso \u00e9 uma carga completamente normal, eles lidam com isso tranquilamente, sempre temos uma reserva.<\/p>\n<p>Colocamos esses servidores em tr\u00eas de nossos data centers e obtivemos tr\u00eas pontos de presen\u00e7a \u2014 Praga, Miami e Hong Kong.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/64eef492b65a014d8ba3c808b6579b41.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssim, eles est\u00e3o mais ou menos localizados perto de cada um de nossos mercados-alvo.<\/p>\n<p>E como um b\u00f4nus agrad\u00e1vel, recebemos esse proxy de cache, no qual o CPU est\u00e1, na verdade, ocioso, porque para fornecer conte\u00fado, n\u00e3o \u00e9 tanto necess\u00e1rio. E l\u00e1, com NGINX + Lua, implementamos muita l\u00f3gica utilit\u00e1ria.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b65c609df5e1985240d04ee65a3e4f55.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor exemplo, podemos experimentar com webp ou jpeg progressivo (s\u00e3o formatos modernos e eficazes), ver como isso afeta o tr\u00e1fego, tomar algumas decis\u00f5es, habilitar para determinados pa\u00edses, etc.; fazer redimensionamento din\u00e2mico ou crop das fotos em tempo real.<\/p>\n<p>Esse \u00e9 um bom caso de uso, quando voc\u00ea tem, por exemplo, um aplicativo m\u00f3vel que mostra fotos, e o aplicativo m\u00f3vel n\u00e3o quer gastar CPU do cliente para solicitar uma grande fotografia e redimension\u00e1-la para algum tamanho a fim de coloc\u00e1-la na visualiza\u00e7\u00e3o. Podemos simplesmente indicar dinamicamente na URL alguns par\u00e2metros em UPort, e o cache de fotos redimensionar\u00e1 a foto automaticamente. Em geral, ele escolher\u00e1 o tamanho que temos fisicamente no disco, o mais pr\u00f3ximo do solicitado, e o redimensionar\u00e1 nas coordenadas espec\u00edficas.<\/p>\n<blockquote><p>Ali\u00e1s, disponibilizamos grava\u00e7\u00f5es em v\u00eddeo dos \u00faltimos cinco anos da confer\u00eancia de desenvolvedores de sistemas de alta carga. <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex>. Assista, estude, compartilhe e inscreva-se no <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/profyclub\">canal do YouTube.<\/a><\/noindex>.<\/p><\/blockquote>\n<p>\nAl\u00e9m disso, podemos adicionar muita l\u00f3gica de produto. Por exemplo, podemos adicionar diferentes marcas d'\u00e1gua com base nos par\u00e2metros da URL, podemos desfocar fotos, borr\u00e1-las ou pixeliz\u00e1-las. Isso \u00e9 quando queremos mostrar a foto de uma pessoa, mas n\u00e3o queremos mostrar seu rosto, e isso funciona bem, tudo isso est\u00e1 implementado aqui.<\/p>\n<p>O que obtivemos? Obtivemos tr\u00eas pontos de presen\u00e7a, uma boa taxa de acerto, e ao mesmo tempo n\u00e3o temos CPU ociosa nessas m\u00e1quinas. Agora ele se tornou, sem d\u00favida, mais importante do que antes. Precisamos colocar m\u00e1quinas mais potentes, mas vale a pena.<\/p>\n<p>Quanto \u00e0 entrega das fotos, tudo isso \u00e9 bastante claro e \u00f3bvio. Eu acho que n\u00e3o estou trazendo nenhuma novidade, funciona assim em praticamente qualquer CDN.<\/p>\n<p>E, provavelmente, o ouvinte experiente pode ter se perguntado: por que simplesmente n\u00e3o trocar tudo para CDN? Seria aproximadamente a mesma coisa, todos os CDNs modernos sabem fazer isso. E h\u00e1 v\u00e1rias raz\u00f5es para isso.<\/p>\n<p>Primeiro \u2014 s\u00e3o as fotos.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/592c10eb74d46191bfcedec120f68556.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEste \u00e9 um dos pontos-chave da nossa infraestrutura, e precisamos ter o m\u00e1ximo de controle sobre elas. Se for uma solu\u00e7\u00e3o de um fornecedor externo, e voc\u00ea n\u00e3o tiver controle sobre isso, ser\u00e1 bastante dif\u00edcil lidar com isso quando voc\u00ea tiver um grande conjunto de dados e um fluxo muito elevado de solicita\u00e7\u00f5es de usu\u00e1rios.<\/p>\n<p>Vou dar um exemplo. Atualmente, em nossa infraestrutura, podemos, por exemplo, em caso de problemas ou toques subterr\u00e2neos, acessar a m\u00e1quina, debugar l\u00e1, por assim dizer. Podemos adicionar a coleta de algumas m\u00e9tricas que s\u00f3 nos interessam, podemos experimentar de alguma forma, observar como isso afeta os gr\u00e1ficos e assim por diante. Atualmente, estamos coletando muitas estat\u00edsticas sobre este cluster de cache. E periodicamente olhamos para isso e analisamos longamente algumas anomalias. Se estivesse do lado do CDN, seria muito mais dif\u00edcil controlar. Ou, por exemplo, se ocorrer algum acidente, sabemos o que aconteceu, sabemos como lidar com isso e como super\u00e1-lo. Essa \u00e9 a primeira conclus\u00e3o.<\/p>\n<p>A segunda conclus\u00e3o tamb\u00e9m \u00e9, em grande parte, hist\u00f3rica, porque o sistema tem evolu\u00eddo h\u00e1 muito tempo, e muitos requisitos de neg\u00f3cios diferentes surgiram em v\u00e1rias etapas, e nem sempre se encaixam na concep\u00e7\u00e3o do CDN.<\/p>\n<p>E um ponto que se segue do anterior \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/007cf3aed2f9cc12185fc3865bf9d196.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c9 que nos caches de fotos temos muita l\u00f3gica espec\u00edfica que nem sempre pode ser adicionada a pedido. \u00c9 pouco prov\u00e1vel que algum CDN adicione alguma coisa personalizada por solicita\u00e7\u00e3o. Por exemplo, criptografia de URLs, se voc\u00ea n\u00e3o quer que o cliente possa mudar algo. Quer mudar a URL no servidor e criptograf\u00e1-la, e depois passar aqui alguns par\u00e2metros din\u00e2micos.<\/p>\n<p>Qual conclus\u00e3o se imp\u00f5e? No nosso caso, o CDN n\u00e3o \u00e9 uma boa alternativa.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/cfc2963cca2357cf6b0f63419a4dc436.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE no seu caso, se voc\u00ea tiver alguns requisitos de neg\u00f3cios espec\u00edficos, pode implementar tranquilamente o que eu mostrei. E isso funcionar\u00e1 muito bem com um perfil de carga semelhante.<\/p>\n<p>Mas se voc\u00ea tiver uma solu\u00e7\u00e3o geral, e a tarefa n\u00e3o for muito espec\u00edfica, voc\u00ea pode tranquilamente usar o CDN. Ou se o tempo e os recursos forem muito mais importantes para voc\u00ea do que o controle.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b76d25404918a5d0d8bf1d6644c8d873.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE os CDNs modernos t\u00eam praticamente tudo o que eu acabei de lhe contar. Com exce\u00e7\u00e3o de algumas funcionalidades.<\/p>\n<p>Isso se refere \u00e0 entrega de fotos.<\/p>\n<p>Vamos agora um pouco \u00e0 frente em nossa retrospectiva e falar sobre armazenamento.<\/p>\n<p>O ano de 2013 estava passando.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f218bfc899512041967842430c02aa9b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOs servidores de cache foram adicionados, e os problemas de desempenho desapareceram. Tudo est\u00e1 bem. O conjunto de dados est\u00e1 crescendo. Em 2013, t\u00ednhamos cerca de 80 servidores conectados aos storages, e aproximadamente 40 servidores de cache em cada DC. Isso equivale a 560 terabytes de dados em cada DC, ou seja, cerca de um petabyte no total.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef741ba4a9164e6940f55e93dfb46ef0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE com o crescimento do conjunto de dados, os custos de opera\u00e7\u00e3o come\u00e7aram a aumentar significativamente. Em que isso se manifestava?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6cf5e489a4e97bc6e26fc6d4d16505b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNesse esquema, que est\u00e1 desenhado \u2014 com o SAN, as m\u00e1quinas conectadas a ele e os caches \u2014 h\u00e1 muitos pontos de falha. Se com a falha dos servidores de cache j\u00e1 conseguimos nos adaptar, onde tudo \u00e9 relativamente previs\u00edvel e compreens\u00edvel, o lado do storage era muito pior.<\/p>\n<p>Primeiro, a pr\u00f3pria Rede de Armazenamento (SAN) pode falhar.<\/p>\n<p>Em segundo lugar, ela est\u00e1 conectada por fibra \u00f3tica \u00e0s m\u00e1quinas finais. Podem haver problemas com as placas \u00f3pticas, switches.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6959b79284c5b1244a70a1d64f191893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nClaro, n\u00e3o s\u00e3o tantos quanto com o pr\u00f3prio SAN, mas, ainda assim, s\u00e3o pontos de falha.<\/p>\n<p>Depois, a pr\u00f3pria m\u00e1quina que est\u00e1 conectada ao storage. Ela tamb\u00e9m pode falhar.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1801cb502663a4de14329a5e67dfed79.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPortanto, temos tr\u00eas pontos de falha.<\/p>\n<p>Al\u00e9m disso, al\u00e9m dos pontos de falha, a manuten\u00e7\u00e3o dos storage \u00e9 pesada.<\/p>\n<p>\u00c9 um sistema complexo e de m\u00faltiplos componentes, e os engenheiros de sistemas \u00e0s vezes t\u00eam dificuldade com ele.<\/p>\n<p>E o \u00faltimo e mais importante ponto. Se ocorrer uma falha em qualquer um desses tr\u00eas pontos, temos uma probabilidade n\u00e3o nula de perder os dados do usu\u00e1rio, pois o sistema de arquivos pode se corromper.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4bf8bc1c73a2beef74cb4ee0ee45679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSuponhamos que o sistema de arquivos esteja corrompido. Sua recupera\u00e7\u00e3o leva, em primeiro lugar, muito tempo \u2014 pode demorar uma semana com um grande volume de dados. E, em segundo lugar, provavelmente acabaremos com uma quantidade de arquivos incompreens\u00edveis, os quais precisar\u00e3o ser de alguma forma vinculados \u00e0s fotos dos usu\u00e1rios. E corremos o risco de perder dados. O risco \u00e9 bastante alto. E quanto mais frequentes essas situa\u00e7\u00f5es ocorrem, e quanto mais problemas surgem em toda essa cadeia, maior \u00e9 esse risco.<\/p>\n<p>Era preciso fazer algo a respeito. E decidimos que dever\u00edamos simplesmente fazer backup dos dados. Essa \u00e9 na verdade uma solu\u00e7\u00e3o \u00f3bvia e boa. O que fizemos?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f80ec2b65003c40bd2fabf88966b3e05.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEste era o nosso servidor que estava conectado ao storage anteriormente. \u00c9 uma \u00fanica parti\u00e7\u00e3o principal, \u00e9 simplesmente um dispositivo de bloco, que na verdade representa um mount em um storage remoto por fibra \u00f3tica.<\/p>\n<p>N\u00f3s simplesmente adicionamos uma segunda parti\u00e7\u00e3o.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d3dba75ef477269d92145cd69d587527.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nColocamos um segundo storage ao lado (felizmente, isso n\u00e3o \u00e9 t\u00e3o caro) e o chamamos de se\u00e7\u00e3o de backup. Ele tamb\u00e9m est\u00e1 conectado por fibra \u00f3ptica e est\u00e1 na mesma m\u00e1quina. Mas precisamos de uma maneira de sincronizar os dados entre eles.<\/p>\n<p>Aqui, simplesmente fazemos uma fila ass\u00edncrona ao lado.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/67bced2b45c589009cfb01a1c21398a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEla n\u00e3o est\u00e1 muito carregada. Sabemos que temos poucas entradas. A fila \u00e9 apenas uma tabela no MySQL, na qual escrevemos linhas do tipo \"preciso fazer backup desta foto\". A cada altera\u00e7\u00e3o ou upload, copiamos da se\u00e7\u00e3o principal para o backup de forma ass\u00edncrona ou simplesmente com algum worker em segundo plano.<\/p>\n<p>E assim temos sempre duas se\u00e7\u00f5es consistentes. Mesmo que uma parte deste sistema falhe, sempre podemos trocar a se\u00e7\u00e3o principal pelo backup, e tudo continuar\u00e1 funcionando.<\/p>\n<p>Mas devido a isso, a carga de leitura aumenta bastante, pois al\u00e9m dos clientes que leem da se\u00e7\u00e3o principal, porque eles primeiro visualizam a foto l\u00e1 (ela \u00e9 mais recente), e ent\u00e3o procuram no backup, se n\u00e3o a encontraram (mas isso j\u00e1 \u00e9 feito pelo NGINX), nossa pr\u00f3pria sistema de backup agora tamb\u00e9m l\u00ea da se\u00e7\u00e3o principal. N\u00e3o \u00e9 que isso seja um gargalo, mas n\u00e3o quer\u00edamos aumentar a carga desnecessariamente.<\/p>\n<p>E adicionamos um terceiro disco, que \u00e9 um pequeno SSD, e o chamamos de buffer.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd35481822b4170087e5f670bf338dc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nComo isso funciona agora.<\/p>\n<p>O usu\u00e1rio faz upload da foto para o buffer, em seguida, um evento \u00e9 enviado para a fila informando que ela precisa ser copiada para as duas se\u00e7\u00f5es. Ela \u00e9 copiada, e a foto fica por algum tempo (digamos, um dia) no buffer, e s\u00f3 ent\u00e3o \u00e9 purgada. Isso melhora muito a experi\u00eancia do usu\u00e1rio, porque o usu\u00e1rio envia a foto e, geralmente, logo em seguida come\u00e7am a surgir requests, ou ele mesmo atualiza a p\u00e1gina. Mas tudo depende da aplica\u00e7\u00e3o que faz o upload.<\/p>\n<p>Ou, por exemplo, outras pessoas que come\u00e7aram a visualizar logo enviam requests para essa foto. No cache, ela ainda n\u00e3o est\u00e1, o primeiro request ocorre muito rapidamente. Basicamente, \u00e9 como no cache de fotos. O storage lento n\u00e3o participa disso. E quando ela for purgada em um dia, ou j\u00e1 estar\u00e1 cacheada em nossa camada de cache, ou provavelmente n\u00e3o ser\u00e1 mais necess\u00e1ria. Ou seja, a experi\u00eancia do usu\u00e1rio melhorou muito por causa dessas manipula\u00e7\u00f5es simples.<\/p>\n<p>E, o mais importante: paramos de perder dados.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/526f549457dd0c438f32b0adb76df76c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe certa forma, paramos <em>potencialmente<\/em> perder dados, porque na verdade n\u00e3o os perdemos. Mas havia um risco. Vemos que essa solu\u00e7\u00e3o, claro, \u00e9 boa, mas \u00e9 um pouco parecida com o al\u00edvio dos sintomas do problema, em vez de resolv\u00ea-lo completamente. E alguns problemas ainda permanecem aqui.<\/p>\n<p>Em primeiro lugar, este \u00e9 um ponto de falha na forma do pr\u00f3prio host f\u00edsico, no qual toda essa maquinaria opera, e ele n\u00e3o desapareceu.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0eb3d292655a7edf912793ed81e8931c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm segundo lugar, ainda existem problemas com os SANs, sua manuten\u00e7\u00e3o pesada, etc. Isso n\u00e3o era um fator cr\u00edtico, mas queria-se experimentar viver sem isso.<\/p>\n<p>E fizemos a terceira vers\u00e3o (na verdade, a segunda) \u2014 uma vers\u00e3o de backup. Como isso se parecia?<\/p>\n<p>Isso era o que havia \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8b1749b6feed200f8a64529ee2316c1a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNossas principais preocupa\u00e7\u00f5es s\u00e3o com o fato de que este \u00e9 um host f\u00edsico.<\/p>\n<p>Primeiro, estamos eliminando os SANs, porque queremos experimentar, queremos tentar usar apenas discos r\u00edgidos locais.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd0f5a8627d9179fcbc7097c1c18505f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIsso j\u00e1 \u00e9 2014-2015, e na \u00e9poca a situa\u00e7\u00e3o com os discos e sua capacidade em um host melhorou bastante. Decidimos, por que n\u00e3o tentar.<\/p>\n<p>E ent\u00e3o simplesmente pegamos nossa parti\u00e7\u00e3o de backup e a transferimos fisicamente para uma m\u00e1quina separada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/456e00bc8557d3340b06efcd1dde8a08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDessa forma, obtemos esse esquema. Temos duas m\u00e1quinas que armazenam conjuntos de dados id\u00eanticos. Elas se fazem backup mutuamente e sincronizam os dados pela rede atrav\u00e9s de uma fila ass\u00edncrona no mesmo MySQL.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d44cdb7b440ad4c58cc625123306a8c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor que isso funciona bem \u2014 porque temos poucas grava\u00e7\u00f5es. Ou seja, se a grava\u00e7\u00e3o fosse compar\u00e1vel \u00e0 leitura, talvez tiv\u00e9ssemos alguma sobrecarga de rede e problemas. H\u00e1 poucas grava\u00e7\u00f5es, muitas leituras \u2014 esse m\u00e9todo funciona bem, ou seja, copiamo fotos entre esses dois servidores bem raramente.<\/p>\n<p>Como isso funciona, se olharmos um pouco mais de perto.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/071c11abb6ee1d7734c53052139ff04b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUpload. O balanceador simplesmente escolhe hosts aleat\u00f3rios com pares e faz o upload para eles. Ao mesmo tempo, ele obviamente realiza verifica\u00e7\u00f5es de sa\u00fade, garantindo que a m\u00e1quina n\u00e3o fique fora de servi\u00e7o. Ou seja, ele faz upload das fotos apenas para um servidor funcionando, e depois, atrav\u00e9s de uma fila ass\u00edncrona, tudo isso \u00e9 copiado para seu vizinho. O upload \u00e9 extremamente simples.<\/p>\n<p>A tarefa \u00e9 um pouco mais complexa.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f494904aec823456e18b987a8c98bf56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAqui, Lua nos ajudou, porque \u00e9 um pouco dif\u00edcil implementar essa l\u00f3gica no NGINX vanilla. Primeiro, fazemos uma requisi\u00e7\u00e3o ao primeiro servidor, verificamos se a foto est\u00e1 l\u00e1, porque ela pode ter sido enviada, por exemplo, para o vizinho, e ainda n\u00e3o chegou aqui. Se a foto estiver l\u00e1, isso \u00e9 bom. N\u00f3s a entregamos imediatamente ao cliente e, possivelmente, fazemos cache.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/de5f77e997bb049f4cfc1709da0f1788.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe n\u00e3o estiver, fazemos uma requisi\u00e7\u00e3o ao vizinho e garantimos que a recebemos de l\u00e1.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/79aa5592acd28dfbc815261d0276c2e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssim, podemos novamente dizer: pode haver problemas de performance, porque as constantes idas e vindas \u2014 a foto foi enviada, aqui n\u00e3o est\u00e1, fazemos duas requisi\u00e7\u00f5es em vez de uma, isso deve funcionar lentamente.<\/p>\n<p>Na nossa situa\u00e7\u00e3o, isso n\u00e3o funciona lentamente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/52ca3902d80990f512201672cd5e6441.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEstamos coletando uma s\u00e9rie de m\u00e9tricas desse sistema, e a taxa de acertos desse mecanismo \u00e9 em torno de 95%. Ou seja, o atraso desse backup \u00e9 pequeno, e gra\u00e7as a isso, quase garantidamente, ap\u00f3s a foto ser carregada, a pegamos na primeira vez e n\u00e3o precisamos ir a lugar nenhum duas vezes.<\/p>\n<p>Assim, o que mais conseguimos, e que \u00e9 muito legal?<\/p>\n<p>Antes, t\u00ednhamos um principal volume de backup, e l\u00edamos dele sequencialmente. Ou seja, sempre busc\u00e1vamos primeiro no principal e depois no backup. Isso era uma opera\u00e7\u00e3o.<\/p>\n<p>Agora n\u00f3s utilizamos a leitura de duas m\u00e1quinas ao mesmo tempo. Distribu\u00edmos as requisi\u00e7\u00f5es em Round Robin. Em uma pequena porcentagem de casos, fazemos duas requisi\u00e7\u00f5es. Mas, em geral, agora temos o dobro de capacidade de leitura do que t\u00ednhamos antes. E a carga diminuiu bastante, tanto nas m\u00e1quinas que fazem a entrega quanto no armazenamento, que tamb\u00e9m t\u00ednhamos na \u00e9poca.<\/p>\n<p>Quanto \u00e0 toler\u00e2ncia a falhas. Na verdade, isso pelo que est\u00e1vamos lutando principalmente. A toler\u00e2ncia a falhas aqui saiu fant\u00e1stica.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a030a477e60d6e1f3d0b4e3395013df5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUma m\u00e1quina falha.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/42900b24e340c03ea642fd49f5b410ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSem problemas! O engenheiro de sistema pode at\u00e9 n\u00e3o acordar \u00e0 noite, pode esperar at\u00e9 de manh\u00e3, n\u00e3o h\u00e1 nada de s\u00e9rio que aconte\u00e7a.<\/p>\n<p>Se a fila falhar mesmo com essa m\u00e1quina quebrada, tamb\u00e9m n\u00e3o h\u00e1 problemas, simplesmente os logs v\u00e3o se acumulando primeiro na m\u00e1quina ativa e depois v\u00e3o para a fila, e depois para a m\u00e1quina que ser\u00e1 reativada em algum momento.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef42eadaaf3e3ecbf70847e9f88c1582.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO mesmo se aplica \u00e0 manuten\u00e7\u00e3o. N\u00f3s simplesmente desligamos uma das m\u00e1quinas, a retiramos manualmente de todos os pools, ela para de receber tr\u00e1fego, fazemos alguma manuten\u00e7\u00e3o, fazemos algumas corre\u00e7\u00f5es e, depois disso, a reintegramos ao sistema. Este backup \u00e9 recuperado rapidamente. Ou seja, um dia de inatividade de uma m\u00e1quina \u00e9 compensado em quest\u00e3o de minutos. Isso \u00e9 realmente muito pouco. Com a alta disponibilidade, como j\u00e1 mencionei, tudo funciona muito bem.<\/p>\n<p>Quais conclus\u00f5es podemos tirar desse esquema de redund\u00e2ncia?<\/p>\n<p>Conseguimos alta disponibilidade.<\/p>\n<p>Explora\u00e7\u00e3o simples. Como as m\u00e1quinas possuem discos r\u00edgidos locais, isso \u00e9 muito mais conveniente do ponto de vista da opera\u00e7\u00e3o para os engenheiros que trabalham com isso.<\/p>\n<p>Obtivemos um dobro na capacidade de leitura.<\/p>\n<p>Esse \u00e9 um \u00f3timo b\u00f4nus em rela\u00e7\u00e3o \u00e0 alta disponibilidade.<\/p>\n<p>Mas tamb\u00e9m h\u00e1 problemas. Agora, temos um desenvolvimento muito mais complexo de algumas fun\u00e7\u00f5es relacionadas a isso, porque o sistema se tornou 100% eventualmente consistente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b650276a41730cc303180e8304c5dabb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDevemos, por exemplo, em algum job em segundo plano, sempre pensar: 'Em qual servidor estamos rodando?' 'Temos certeza de que aqui est\u00e1 a imagem atual?' E assim por diante. Isso, naturalmente, tudo est\u00e1 encapsulado em wrappers e \u00e9 transparente para o programador que escreve a l\u00f3gica de neg\u00f3cios. No entanto, isso criou uma camada complexa. Mas estamos dispostos a conviver com isso em troca dos benef\u00edcios que obtivemos.<\/p>\n<p>E aqui novamente surge um certo conflito.<\/p>\n<p>No in\u00edcio, eu disse que armazenar tudo em discos r\u00edgidos locais \u00e9 ruim. E agora estou dizendo que gostamos disso.<\/p>\n<p>Sim, de fato, com o tempo a situa\u00e7\u00e3o mudou bastante, e agora essa abordagem trouxe muitas vantagens. Primeiro, conseguimos uma opera\u00e7\u00e3o muito mais simples.<\/p>\n<p>Em segundo lugar, isso \u00e9 mais eficiente, porque n\u00e3o temos aqueles controladores autom\u00e1ticos, conex\u00e3o com prateleiras de discos.<\/p>\n<p>L\u00e1 existem enormes maquin\u00e1rios, enquanto aqui s\u00e3o apenas alguns discos que est\u00e3o montados localmente na m\u00e1quina em RAID.<\/p>\n<p>Mas tamb\u00e9m existem desvantagens.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3c090e0801f1a686dc0d5fefce697c56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIsso \u00e9 aproximadamente 1,5 vezes mais caro do que usar SANs, mesmo com os pre\u00e7os atuais. Portanto, decidimos n\u00e3o converter todo o nosso grande cluster para m\u00e1quinas com discos r\u00edgidos locais e optamos por manter uma solu\u00e7\u00e3o h\u00edbrida.<\/p>\n<p>Cerca de metade das m\u00e1quinas que temos funciona com discos r\u00edgidos (bem, n\u00e3o exatamente metade \u2013 cerca de 30%, talvez). A parte restante consiste em m\u00e1quinas mais antigas, que usavam um esquema de backup anterior. N\u00f3s apenas reconfiguramos, pois n\u00e3o precisamos de dados novos ou de qualquer outra coisa, apenas movemos os mounts de um host f\u00edsico para dois.<\/p>\n<p>Assim, conseguimos um grande aumento na leitura e ampliamos nossa capacidade. Se antes mont\u00e1vamos um storage em uma m\u00e1quina, agora montamos quatro em um \u00fanico par, por exemplo. E isso funciona bem.<\/p>\n<p>Vamos fazer um breve resumo do que conseguimos, pelo que lutamos e se conseguimos.<\/p>\n<h3>Resultados<\/h3>\n<p>\nTemos usu\u00e1rios \u2013 no total, 33 milh\u00f5es.<\/p>\n<p>Temos tr\u00eas pontos de presen\u00e7a \u2013 Praga, Miami, Hong Kong.<\/p>\n<p>Neles, h\u00e1 uma camada de cache que consiste em m\u00e1quinas com discos locais r\u00e1pidos (SSD), onde uma simples configura\u00e7\u00e3o com NGINX, seu access.log e dem\u00f4nios em Python processam e gerenciam o cache.<\/p>\n<p>Se desejar, no seu projeto, se as fotos n\u00e3o forem t\u00e3o cr\u00edticas quanto para n\u00f3s, ou se o equil\u00edbrio entre controle e velocidade de desenvolvimento e consumo de recursos estiver a seu favor, ent\u00e3o voc\u00ea pode facilmente substitu\u00ed-lo por um CDN, que hoje em dia faz isso muito bem.<\/p>\n<p>A seguir, temos a camada de armazenamento, onde temos clusters de pares de m\u00e1quinas que se reservam mutuamente, com arquivos sendo copiados ass\u00edncronamente de uma para outra a cada altera\u00e7\u00e3o.<\/p>\n<p>Uma parte dessas m\u00e1quinas trabalha com discos r\u00edgidos locais.<\/p>\n<p>Outra parte dessas m\u00e1quinas est\u00e1 conectada a SANs.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5ddbc4f73d86aa1f83734885d8c9dea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE, por um lado, isso \u00e9 mais conveniente em termos de opera\u00e7\u00e3o e um pouco mais eficiente, por outro lado, \u00e9 pr\u00e1tico em termos de densidade de aloca\u00e7\u00e3o e custo por gigabyte.<\/p>\n<p>Este \u00e9 um breve resumo da arquitetura do que conseguimos e como isso tudo evoluiu.<\/p>\n<p>Mais alguns conselhos do chefe, bem simples.<\/p>\n<p>Primeiro, se voc\u00ea decidir que precisa urgentemente melhorar toda a sua infraestrutura de fotos, me\u00e7a primeiro, pois talvez n\u00e3o seja necess\u00e1rio melhorar nada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7770f41d0b190eb78ae0d19f4c8182a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVou dar um exemplo. Temos um cluster de m\u00e1quinas que fornece fotos de anexos em chats, e l\u00e1 ainda funciona um esquema de 2009, e ningu\u00e9m sofre por isso. Todos est\u00e3o satisfeitos, todos gostam.<\/p>\n<p>Para medir, comece por definir um conjunto de m\u00e9tricas, analise-as e ent\u00e3o decida o que n\u00e3o est\u00e1 funcionando e o que precisa ser melhorado. Para isso, temos uma ferramenta incr\u00edvel chamada Pinba.<\/p>\n<p>Ela permite coletar estat\u00edsticas do NGINX de forma detalhada para cada requisi\u00e7\u00e3o e c\u00f3digos de resposta, e a distribui\u00e7\u00e3o de tempos \u2014 tudo o que voc\u00ea precisar. Possui integra\u00e7\u00f5es com v\u00e1rias plataformas de an\u00e1lise, permitindo que voc\u00ea visualize tudo de forma clara.<\/p>\n<p>Primeiro medimos \u2014 depois melhoramos.<\/p>\n<p>A seguir. Otimizamos a leitura com cache, e a grava\u00e7\u00e3o com sharding, mas isso \u00e9 um ponto \u00f3bvio.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f53a4777f1a2c7793eba4a72c94263a4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm seguida. Se voc\u00ea est\u00e1 apenas come\u00e7ando a construir seu sistema, \u00e9 muito melhor tratar fotos como arquivos imut\u00e1veis. Isso evita uma s\u00e9rie de problemas relacionados \u00e0 invalida\u00e7\u00e3o do cache e \u00e0 l\u00f3gica que deve encontrar a vers\u00e3o correta da foto, entre outros.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f345c59681275326cda1320b4f188ce9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSuponha que voc\u00ea carregou uma foto, depois a girou; fa\u00e7a com que isso gere um arquivo fisicamente diferente. Ou seja, n\u00e3o tente economizar um pouco de espa\u00e7o gravando no mesmo arquivo e alterando a vers\u00e3o. Isso sempre traz complica\u00e7\u00f5es e muitas dores de cabe\u00e7a depois.<\/p>\n<p>Pr\u00f3ximo ponto. Sobre redimensionamento em tempo real.<\/p>\n<p>Anteriormente, quando os usu\u00e1rios enviavam uma foto, cri\u00e1vamos diversos tamanhos para todas as situa\u00e7\u00f5es, para diferentes clientes, e eles todos eram armazenados no disco. Agora, desistimos disso.<\/p>\n<p>Deixamos apenas tr\u00eas tamanhos principais: pequeno, m\u00e9dio e grande. Todo o resto \u00e9 redimensionado a partir do tamanho mais pr\u00f3ximo que foi solicitado no Uport, apenas fazemos um downscale e entregamos ao usu\u00e1rio.<\/p>\n<p>O custo do CPU da camada de cache acaba sendo muito mais barato do que se estivermos constantemente regenerando esses tamanhos em cada armazenamento. Suponha que queiramos adicionar um novo; isso pode levar um m\u00eas \u2014 rodar um script em todos os lugares que fa\u00e7a esse trabalho com cuidado, sem derrubar o cluster. Ou seja, se houver a op\u00e7\u00e3o de escolher, \u00e9 melhor manter o menor n\u00famero poss\u00edvel de tamanhos f\u00edsicos, mas garantir algum tipo de distribui\u00e7\u00e3o, digamos, tr\u00eas. E todo o resto, apenas redimensionar em tempo real com m\u00f3dulos prontos. Isso agora \u00e9 muito f\u00e1cil e acess\u00edvel.<\/p>\n<p>E um backup ass\u00edncrono incremental \u2014 isso \u00e9 uma boa pr\u00e1tica.<\/p>\n<p>Como nossa pr\u00e1tica mostrou, esse tipo de esquema funciona muito bem para a c\u00f3pia atrasada de arquivos alterados.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitetura de armazenamento e entrega de fotos no Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0e550721e838654e61e1fa4d08f9bb93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO \u00faltimo ponto tamb\u00e9m \u00e9 \u00f3bvio. Se sua infraestrutura n\u00e3o tem esses problemas no momento, mas h\u00e1 algo que pode falhar, com certeza isso acontecer\u00e1 quando houver uma leve press\u00e3o extra. Portanto, \u00e9 melhor pensar nisso com anteced\u00eancia e evitar problemas mais tarde. Isso \u00e9 tudo.<\/p>\n<h3>Contatos<\/h3>\n<p>\n\u00bb <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/users\/bo0rsh201\/\" class=\"user_link\">bo0rsh201<\/a><\/noindex> <br \/>\n\u00bb <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/badoo\/\">Blog da empresa Badoo<\/a><\/noindex><\/p>\n<blockquote><p>Esta apresenta\u00e7\u00e3o \u00e9 a transcri\u00e7\u00e3o de uma das melhores palestras na confer\u00eancia de desenvolvedores de sistemas de alta carga <noindex><a rel=\"nofollow\" href=\"http:\/\/highload.ru\/?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">HighLoad++<\/a><\/noindex>. Faltam menos de um m\u00eas para a confer\u00eancia HighLoad++ 2017.<\/p>\n<p>J\u00e1 temos <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\">Programa da Confer\u00eancia<\/a><\/noindex>, e a programa\u00e7\u00e3o est\u00e1 sendo ativamente formada.<\/p>\n<p>Este ano, continuamos explorando o tema de arquiteturas e escalabilidade:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2946.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Como atender um bilh\u00e3o de usu\u00e1rios e entregar um terabit de tr\u00e1fego<\/a><\/noindex> \/ \u0418\u0433\u043e\u0440\u044c \u0412\u0430\u0441\u0438\u043b\u044c\u0435\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/3088.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Como reescrever do zero o banco de dados de mensagens pessoais do Vkontakte e migrar para ele sem downtime<\/a><\/noindex> \/ \u0414\u043c\u0438\u0442\u0440\u0438\u0439 \u0415\u0433\u043e\u0440\u043e\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2843.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Morte por liquida\u00e7\u00e3o: como o Yandex.Money tentou se apressar para a Black Friday e resistir<\/a><\/noindex> \/ \u0410\u043d\u0430\u0442\u043e\u043b\u0438\u0439 \u041f\u043b\u0430\u0441\u043a\u043e\u0432\u0441\u043a\u0438\u0439<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/3003.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Arquitetura tolerante a falhas do sistema frontal do banco<\/a><\/noindex> \/ \u0420\u043e\u043c\u0430\u043d \u0428\u0435\u0445\u043e\u0432\u0446\u043e\u0432, \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u0413\u0440\u043e\u043c\u0430\u0442\u0447\u0438\u043a\u043e\u0432<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\/2948.html?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">Arquitetura do sistema de pagamentos: quase corporativa<\/a><\/noindex> \/ \u0424\u0438\u043b\u0438\u043f\u043f \u0414\u0435\u043b\u044c\u0433\u044f\u0434\u043e<\/li>\n<\/ul>\n<p>\nAlguns desses materiais tamb\u00e9m s\u00e3o utilizados por n\u00f3s no curso online de desenvolvimento de sistemas de alta carga <noindex><a rel=\"nofollow\" href=\"http:\/\/highload.guide\/?utm_source=habr&amp;utm_medium=media&amp;utm_campaign=past.articles&amp;utm_content=common\">HighLoad.Guide<\/a><\/noindex> \u2014 uma s\u00e9rie de e-mails, artigos, materiais e v\u00eddeos especialmente selecionados. J\u00e1 temos mais de 30 materiais \u00fanicos em nosso manual. Junte-se a n\u00f3s!\n<\/p><\/blockquote>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/340976\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 ( bo0rsh201, Badoo) Badoo \u2014 \u044d\u0442\u043e \u043a\u0440\u0443\u043f\u043d\u0435\u0439\u0448\u0438\u0439 \u0432 \u043c\u0438\u0440\u0435 \u0441\u0430\u0439\u0442 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043d\u0430\u0441 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 330 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043c\u0438\u0440\u0443. \u041d\u043e, \u0447\u0442\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0433\u043e \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u0430, \u2014 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u043e\u043a\u043e\u043b\u043e 3 \u043f\u0435\u0442\u0430\u0431\u0430\u0439\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u041a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c \u043d\u0430\u0448\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0437\u0430\u043b\u0438\u0432\u0430\u044e\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 3,5 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-55009","post","type-post","status-publish","format-standard","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=\"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (\" \/>\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\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\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\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u0434\u0430\u0447\u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0432 Badoo | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\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-01-09T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:03:04+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\udd47Arquitetura de armazenamento e entrega de fotografias na Badoo | ProHoster","description":"Artem Denisov (","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","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\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u0434\u0430\u0447\u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0432 Badoo | ProHoster","og:description":"\u0410\u0440\u0442\u0435\u043c \u0414\u0435\u043d\u0438\u0441\u043e\u0432 (","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","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-01-09T21:00:00+00:00","article:modified_time":"2020-02-18T11:03:04+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"55009","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-01-24 13:30:15","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:53:49","updated":"2026-01-24 13:30:15","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\/55009","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=55009"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/55009\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=55009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=55009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=55009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}