{"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\/es\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","title":{"rendered":"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en 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 es el sitio de citas m\u00e1s grande del mundo. Actualmente, tenemos registrados alrededor de 330 millones de usuarios en todo el mundo. Pero, lo que es mucho m\u00e1s importante en el contexto de nuestra conversaci\u00f3n de hoy, es que almacenamos alrededor de 3 petabytes de fotos de usuarios. Cada d\u00eda, nuestros usuarios suben aproximadamente 3,5 millones de nuevas fotos, y la carga de lectura es de alrededor de <b>80,000 solicitudes por segundo<\/b>. Esto es bastante para nuestro backend, y a veces tenemos dificultades con ello.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4e4690f9b0d95bd76fbbc1cd6805c26c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVoy a contarles sobre el dise\u00f1o de este sistema que almacena y entrega fotos en general, y dar\u00e9 una perspectiva desde el punto de vista del desarrollador. Habr\u00e1 una breve retrospectiva sobre c\u00f3mo ha evolucionado, donde se\u00f1alar\u00e9 los hitos principales, pero hablar\u00e9 con m\u00e1s detalle solo sobre las soluciones que estamos utilizando actualmente.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nY ahora, empecemos.<\/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=\"Reproducir video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nComo ya mencion\u00e9, ser\u00e1 una retrospectiva, y para comenzar, tomemos el ejemplo m\u00e1s b\u00e1sico.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/22b9627cda7ccadd9869b64e9d043d89.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTenemos una tarea com\u00fan, necesitamos recibir, almacenar y entregar las fotos de los usuarios. En esta forma, la tarea es general, podemos usar cualquier cosa:<\/p>\n<ul>\n<li>almacenamiento en la nube moderno,<\/li>\n<li>una soluci\u00f3n en caja, de las cuales tambi\u00e9n hay muchas ahora;<\/li>\n<li>podemos configurarlo en varias m\u00e1quinas en nuestro centro de datos y colocar discos duros grandes para almacenar las fotos all\u00ed.<\/li>\n<\/ul>\n<p>\nBadoo hist\u00f3ricamente \u2014 y ahora, y en su momento (cuando esto apenas comenzaba) \u2014 opera en sus propios servidores, dentro de nuestros propios centros de datos. Por lo tanto, esta opci\u00f3n fue \u00f3ptima para nosotros.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9434fbabada15670297c551066ad7e71.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSimplemente tomamos varias m\u00e1quinas, las llamamos \"photos\", y obtuvimos un cl\u00faster que almacena fotos. Pero, parece que falta algo. Para que todo esto funcione, necesitamos de alguna manera determinar en qu\u00e9 m\u00e1quina almacenaremos qu\u00e9 fotos. Y aqu\u00ed tampoco hay que descubrir Am\u00e9rica.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/36258e7107fd8c60f7e9e563a2cb681c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAgregamos a nuestro almacenamiento con informaci\u00f3n de los usuarios un campo. Este ser\u00e1 la clave de sharding. En nuestro caso, lo llamamos place_id, y este id de lugar indica d\u00f3nde se almacenan las fotos de los usuarios. Creamos mapas.<\/p>\n<p>En la primera etapa, esto se puede hacer incluso manualmente: decimos que la fotograf\u00eda de este usuario con esa ubicaci\u00f3n se almacenar\u00e1 en ese servidor. Gracias a este mapa, siempre sabemos cu\u00e1ndo el usuario sube una fotograf\u00eda, d\u00f3nde guardarla y desde d\u00f3nde entregarla.<\/p>\n<p>Es un esquema absolutamente trivial, pero tiene ventajas bastante significativas. Primero, es simple, como ya mencion\u00e9, y segundo, con este enfoque podemos escalar horizontalmente f\u00e1cilmente, simplemente a\u00f1adiendo nuevos nodos y sum\u00e1ndolos al mapa. No hay que hacer nada m\u00e1s.<\/p>\n<p>As\u00ed fue durante alg\u00fan tiempo.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3effb442702f162f7bad9c18ec54392e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEsto ocurri\u00f3 alrededor de 2009. Est\u00e1bamos entregando m\u00e1quinas, entregando...<\/p>\n<p>Y en alg\u00fan momento comenzamos a notar que este esquema ten\u00eda ciertas desventajas. \u00bfCu\u00e1les eran las desventajas?<\/p>\n<p>Primero, es la capacidad limitada. En un servidor f\u00edsico no podemos alojar tantos discos duros como nos gustar\u00eda. Con el tiempo y el crecimiento del dataset, eso se convirti\u00f3 en un problema.<\/p>\n<p>Y segundo. Esta es una configuraci\u00f3n poco com\u00fan de m\u00e1quinas, ya que es dif\u00edcil reutilizarlas en otros cl\u00fasteres; son bastante espec\u00edficas, es decir, deben tener un rendimiento bajo, pero al mismo tiempo un gran disco duro.<\/p>\n<p>Todo esto era para el a\u00f1o 2009, pero en principio, estos requisitos siguen siendo relevantes hasta hoy. Tenemos una retrospectiva, as\u00ed que en 2009 todo era malo con esto.<\/p>\n<p>Y el \u00faltimo punto es el precio.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e49010eaeab139199d8fe010caa65bf0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEl precio era bastante alto en ese momento, y necesit\u00e1bamos buscar alternativas. Es decir, ten\u00edamos que mejorar la utilizaci\u00f3n tanto del espacio en los centros de datos como de los servidores f\u00edsicos donde todo esto estaba alojado. Nuestros ingenieros de sistemas iniciaron una gran investigaci\u00f3n donde revisaron varias opciones. Miraron a sistemas de archivos en cl\u00faster, como PolyCeph y Lustre. Hubo problemas con el rendimiento y un mantenimiento bastante complicado. Decidieron no seguir con eso. Intentaron montar todo el dataset por NFS en cada nodo para escalar de alguna manera. La lectura tambi\u00e9n fue problem\u00e1tica, probaron varias soluciones de diferentes proveedores.<\/p>\n<p>Y al final decidimos utilizar lo que se llama una Red de \u00c1rea de Almacenamiento.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e99402fa641f3bd5fc8d57a9f8995642.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEstos son grandes SHD, que est\u00e1n dise\u00f1ados para almacenar grandes vol\u00famenes de datos. Consisten en estantes con discos que est\u00e1n montados en m\u00e1quinas de entrega finales a trav\u00e9s de fibra \u00f3ptica. As\u00ed, tenemos un grupo de m\u00e1quinas, bastante peque\u00f1o, y estos SHD, que son transparentes para nuestra l\u00f3gica de entrega, es decir, para nuestro nginx o quien sea, manejan las solicitudes de estas fotograf\u00edas.<\/p>\n<p>Esta soluci\u00f3n ten\u00eda ventajas evidentes. Es un SHD. Est\u00e1 dise\u00f1ado para almacenar fotos. Resulta ser m\u00e1s econ\u00f3mico que simplemente configurar m\u00e1quinas con discos duros.<\/p>\n<p>El segundo beneficio. <\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7fd2e7d629cc239096b14c68be5f76bf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs que la capacidad ha aumentado considerablemente, es decir, podemos alojar mucho m\u00e1s almacenamiento en un volumen mucho menor.<\/p>\n<p>Pero tambi\u00e9n hubo desventajas que se hicieron evidentes bastante r\u00e1pido. A medida que creci\u00f3 el n\u00famero de usuarios y la carga en este sistema, comenzaron a surgir problemas de rendimiento. Y el problema aqu\u00ed es bastante obvio: cualquier SHD dise\u00f1ado para almacenar muchas fotos en un peque\u00f1o volumen, generalmente sufre de lecturas intensivas. Esto es realmente relevante tanto para cualquier almacenamiento en la nube como para cualquier otra cosa. En este momento, no existe un almacenamiento ideal que sea infinitamente escalable, en el que se pueda meter cualquier cosa y que soporte muy bien las lecturas. Especialmente las lecturas aleatorias.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/566e836e2fe13a2a3d040ae3fa865d6d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAl igual que con nuestras fotos, porque las fotograf\u00edas se solicitan de manera no secuencial, y esto afecta enormemente su rendimiento.<\/p>\n<p>Incluso seg\u00fan las cifras de hoy, si tenemos m\u00e1s de 500 RPS en las solicitudes de fotos por m\u00e1quina a la que est\u00e1 conectado el almacenamiento, ya comienzan los problemas. Y esto ha sido bastante malo para nosotros, porque el n\u00famero de usuarios sigue creciendo, y todo deber\u00eda empeorar. Esto necesita ser optimizado de alguna manera.<\/p>\n<p>Para optimizar, en ese momento decidimos, evidentemente, mirar el perfil de carga \u2014 qu\u00e9 est\u00e1 sucediendo, qu\u00e9 necesitamos optimizar.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d67310e6b90c4ee1337065790576c9a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY aqu\u00ed todo juega a nuestro favor.<\/p>\n<p>Ya mencion\u00e9 en la primera diapositiva: tenemos 80 mil solicitudes por segundo para lectura con solo 3,5 millones de cargas por d\u00eda. Es decir, hay una diferencia de tres \u00f3rdenes de magnitud. Es obvio que necesitamos optimizar la lectura y pr\u00e1cticamente est\u00e1 claro c\u00f3mo hacerlo.<\/p>\n<p>Hay un peque\u00f1o detalle m\u00e1s. La especificidad del servicio es tal que una persona se registra, sube una foto, luego comienza a ver activamente a otras personas, les da 'me gusta', y es mostrado activamente a los dem\u00e1s. Luego encuentra una pareja o no, eso depende, y por un tiempo deja de usar el servicio. En ese momento, cuando est\u00e1 usando, sus fotos son muy 'calientes' \u2014 son bastante solicitadas, muchas personas las ven. Tan pronto como deja de hacerlo, r\u00e1pidamente deja de ser mostrado de manera intensa a los dem\u00e1s, como lo era antes, y sus fotos pr\u00e1cticamente dejan de ser solicitadas.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/dcc7e306055d8f2b0895f24679bfc3e2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs decir, tenemos un dataset muy peque\u00f1o y 'caliente'. Pero, al mismo tiempo, recibe muchas solicitudes. Y la soluci\u00f3n obvia aqu\u00ed es a\u00f1adir cach\u00e9.<\/p>\n<p>El cach\u00e9 con LRU resolver\u00e1 todos nuestros problemas. \u00bfQu\u00e9 hacemos?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/2bd0c88a97d928f386db21549fc02500.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA\u00f1adimos ante nuestro gran cl\u00faster con almacenamiento otro relativamente peque\u00f1o, que llamamos cach\u00e9s de fotos (photoscache). Esto es, en esencia, un proxy de cach\u00e9.<\/p>\n<p>\u00bfC\u00f3mo funciona esto internamente? Aqu\u00ed est\u00e1 nuestro usuario, aqu\u00ed est\u00e1 el almacenamiento. Todo como antes. \u00bfQu\u00e9 a\u00f1adimos entre ellos?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7b7b5f102f1c012b2aef8f02ec731fac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs simplemente una m\u00e1quina con un disco f\u00edsico local, que es r\u00e1pido. Es un SSD, por ejemplo. Y en este disco se almacena alg\u00fan cach\u00e9 local.<\/p>\n<p>\u00bfC\u00f3mo se ve esto? El usuario env\u00eda una solicitud por una foto. NGINX primero la busca en el cach\u00e9 local. Si no est\u00e1, simplemente hace proxy_pass a nuestro almacenamiento, descarga la fotograf\u00eda desde all\u00ed y se la da al usuario.<\/p>\n<p>Pero esto es muy b\u00e1sico y no est\u00e1 claro qu\u00e9 sucede internamente. Funciona aproximadamente as\u00ed.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/46be24df171d1008e2a9099b7e4c9be6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEl cach\u00e9 est\u00e1 l\u00f3gicamente dividido en tres capas. Cuando digo 'tres capas', no significa que haya un sistema complejo. No, son simplemente tres directorios en el sistema de archivos:<\/p>\n<ol>\n<li>Este es un b\u00fafer, donde entran las fotos reci\u00e9n cargadas desde el proxy.<\/li>\n<li>Este es un cach\u00e9 caliente, donde se almacenan las fotos que est\u00e1n siendo activamente solicitadas en este momento.<\/li>\n<li>Y un cach\u00e9 fr\u00edo, donde lentamente las fotos son expulsadas del caliente cuando reciben menos solicitudes.<\/li>\n<\/ol>\n<p>\nPara que esto funcione, necesitamos gestionar este cach\u00e9 de alguna manera, necesitamos mover las fotos dentro de \u00e9l, etc. Tambi\u00e9n es un proceso muy primitivo.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9b16fe3e99a5f88f06169f6e5eedf2b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNginx simplemente escribe en RAMDisk access.log para cada solicitud, donde indica la ruta de la foto que est\u00e1 siendo servida (ruta relativa, por supuesto) y qu\u00e9 secci\u00f3n la est\u00e1 sirviendo. Es decir, puede mencionarse \u00abfoto 1\u00bb y luego el buffer, o cach\u00e9 caliente, o cach\u00e9 fr\u00edo, o proxy.<\/p>\n<p>Dependiendo de esto, necesitamos tomar una decisi\u00f3n sobre qu\u00e9 hacer con la foto.<\/p>\n<p>En cada m\u00e1quina, tenemos un peque\u00f1o demonio que constantemente lee este log y almacena en su memoria las estad\u00edsticas sobre el uso de ciertas fotos.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0dceda5e5ff432d1609520f0c152f152.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSimplemente recopila informaci\u00f3n, lleva contadores y peri\u00f3dicamente hace lo siguiente. Las fotos que se solicitan activamente, que reciben muchas solicitudes, las mueve al cach\u00e9 caliente, sin importar d\u00f3nde est\u00e9n.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/941c13ecfea88372f3a7eb62d81b0c4e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLas fotos que se solicitan raramente y cuyos pedidos han disminuido, las empuja gradualmente del cach\u00e9 caliente al fr\u00edo.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a07235246995ad2fa4e6aeccae23a629.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY cuando rompemos espacio en el cach\u00e9, simplemente comenzamos a eliminar indiscriminadamente del cach\u00e9 fr\u00edo. Y, de hecho, funciona bien.<\/p>\n<p>Para que la foto se guarde de inmediato al ser proxy, utilizamos la directiva proxy_store y el buffer tambi\u00e9n es un RAMDisk, es decir, para el usuario funciona muy r\u00e1pido. Esto se refiere a las entra\u00f1as del servidor de cach\u00e9.<\/p>\n<p>Sigue la pregunta de c\u00f3mo distribuir las solicitudes entre estos servidores.<\/p>\n<p>Supongamos que hay un cl\u00faster de veinte m\u00e1quinas de almacenamiento y tres servidores de cach\u00e9 (as\u00ed result\u00f3).<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6bc970b687701f3b6d57e153e3abed18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNecesitamos de alguna forma determinar qu\u00e9 solicitudes corresponden a qu\u00e9 fotos y d\u00f3nde deben aterrizar.<\/p>\n<p>La opci\u00f3n m\u00e1s banal es Round Robin. \u00bfO hacer esto de manera aleatoria?<\/p>\n<p>Esto, evidentemente, tiene una serie de desventajas, porque vamos a utilizar el cach\u00e9 de manera muy ineficiente en tal situaci\u00f3n. Las solicitudes caer\u00e1n en m\u00e1quinas aleatorias: aqu\u00ed se cache\u00f3, en la vecina ya no est\u00e1. Y si esto funciona, lo har\u00e1 muy mal. Incluso con un n\u00famero peque\u00f1o de m\u00e1quinas en el cl\u00faster.<\/p>\n<p>Necesitamos de alguna manera determinar de forma inequ\u00edvoca en qu\u00e9 servidor aterrizar cada solicitud.<\/p>\n<p>Hay una forma simple. Tomamos el hash de la URL o el hash de nuestra clave de partici\u00f3n, que est\u00e1 en la URL, y lo dividimos por la cantidad de servidores. \u00bfFunciona? Funciona.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/794a82ac1268b651ab936f0225b802a2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs decir, tenemos un request del cien por ciento, por ejemplo, por alg\u00fan \u00abexample_url\u00bb siempre se aterrizar\u00e1 en el servidor con el \u00edndice \u00ab2\u00bb, y la cach\u00e9 se utilizar\u00e1 de la mejor manera posible.<\/p>\n<p>Pero surge un problema con el resharding en tal esquema. Resharding, me refiero al cambio en la cantidad de servidores.<\/p>\n<p>Supongamos que nuestro cl\u00faster de cacheo ha dejado de ser efectivo y hemos decidido agregar otra m\u00e1quina.<\/p>\n<p>Agregamos.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5f2fcba4c4f267c069811c3677bd0213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAhora estamos dividiendo todo no entre tres, sino entre cuatro. As\u00ed, pr\u00e1cticamente todas las claves que ten\u00edamos antes, pr\u00e1cticamente todas las URL ahora residen en otros servidores. Toda la cach\u00e9 se invalid\u00f3 de inmediato. Todas las solicitudes se dirigieron a nuestro cl\u00faster de almacenamiento, se volvi\u00f3 inestable, hubo una interrupci\u00f3n del servicio y usuarios descontentos. No queremos que eso ocurra.<\/p>\n<p>Esta opci\u00f3n tampoco nos conviene.<\/p>\n<p>Entonces, \u00bfqu\u00e9 debemos hacer? Debemos de alguna manera utilizar la cach\u00e9 de manera efectiva, aterrizando constantemente un request en el mismo servidor, pero al mismo tiempo ser resilientes al resharding. Y hay una soluci\u00f3n para eso, no es que sea complicada. Se llama hashing consistente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1380758686274df9755a7ebf7d1c8753.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00bfC\u00f3mo se ve esto?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/44f97abfac46fa9f361055548819e8a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTomamos alguna funci\u00f3n de la clave de sharding y dispersamos todos sus valores en una circunferencia. Es decir, en el punto 0 se encuentran sus valores m\u00ednimos y m\u00e1ximos. Luego, colocamos todos nuestros servidores en esa misma circunferencia de esta manera:<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d470ec615a789913a6baa2726b05acea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCada servidor se define por un punto, y el sector que va hasta \u00e9l en el sentido de las agujas del reloj, corresponde a este host. Cuando recibimos solicitudes, vemos de inmediato que, por ejemplo, la solicitud A \u2014 tiene un hash as\u00ed \u2014 y es atendida por el servidor 2. La solicitud B \u2014 por el servidor 3. Y as\u00ed sucesivamente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fcdbd1caa9f1162cf02e8b0a1c79cb74.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00bfQu\u00e9 sucede en esta situaci\u00f3n durante el resharding?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7386cda826e9419d5f8a9a0d6d6703c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNo invalidamos toda la cach\u00e9, como hac\u00edamos antes, y no desplazamos todas las claves, sino que movemos cada sector una peque\u00f1a distancia de tal manera que en el espacio libre, por as\u00ed decirlo, quepa nuestro sexto servidor que queremos agregar, y lo a\u00f1adimos all\u00ed.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8680e0cf023ce911b4d162e9102c0545.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor supuesto, en tal situaci\u00f3n, las claves tambi\u00e9n se desajustan. Pero se desajustan mucho menos que antes. Y vemos que nuestras dos primeras claves permanecen en sus servidores, mientras que solo el servidor de cach\u00e9 cambi\u00f3 para la \u00faltima clave. Esto funciona de manera bastante efectiva, y si agregas nuevos hosts de manera incremental, no hay un gran problema aqu\u00ed. Agregas poco a poco, esperas a que la cach\u00e9 se llene nuevamente, y todo funciona bien.<\/p>\n<p>La \u00fanica pregunta que queda es sobre las fallas. Supongamos que alguno de nuestros servidores se ha averiado.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8e3301af782ce8983716c4bc9add79a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY no nos gustar\u00eda en ese momento regenerar este mapa, invalidar parte de la cach\u00e9, etc., si, por ejemplo, la m\u00e1quina se reinici\u00f3 y necesitamos atender las solicitudes de alguna manera. Simplemente mantenemos en cada sitio un cach\u00e9 fotogr\u00e1fico de reserva que act\u00faa como reemplazo para cualquier m\u00e1quina que est\u00e9 fuera de servicio en ese momento. Y si de repente alg\u00fan servidor se vuelve inaccesible, el tr\u00e1fico se dirige all\u00ed. En este caso, naturalmente no hay cach\u00e9, es decir, est\u00e1 fr\u00edo, pero, al menos, se procesan las solicitudes de los usuarios. Si es un intervalo corto, lo manejamos sin problemas. Simplemente hay m\u00e1s carga en el almacenamiento. Si el intervalo es largo, entonces podemos decidir si quitar este servidor del mapa o no, o tal vez reemplazarlo por otro.<\/p>\n<p>Esto es respecto al sistema de cach\u00e9. Veamos los resultados.<\/p>\n<p>Aparentemente, no hay nada complicado aqu\u00ed. Pero este m\u00e9todo de gesti\u00f3n de la cach\u00e9 nos dio una tasa de aciertos del 98%. Es decir, de esas 80,000 solicitudes por segundo, solo 1,600 llegan a los almacenes, y esta es una carga completamente normal, ellos la manejan sin problemas, siempre tenemos un margen.<\/p>\n<p>Hemos colocado estos servidores en nuestros tres centros de datos, y obtuvimos tres puntos de presencia: Praga, Miami y Hong Kong.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/64eef492b65a014d8ba3c808b6579b41.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor lo tanto, est\u00e1n m\u00e1s o menos localizados cerca de cada uno de nuestros mercados objetivo.<\/p>\n<p>Y como bonificaci\u00f3n agradable, obtuvimos este proxy de cach\u00e9, en el que la CPU, de hecho, est\u00e1 ociosa, porque no se necesita tanto para servir contenido. Y all\u00ed, con NGINX + Lua, implementamos mucha l\u00f3gica utilitaria.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b65c609df5e1985240d04ee65a3e4f55.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor ejemplo, podemos experimentar con webp o jpeg progresivo (formatos modernos y eficientes), ver c\u00f3mo afecta al tr\u00e1fico, tomar decisiones, activar para ciertos pa\u00edses, etc.; hacer un cambio din\u00e1mico de tama\u00f1o o recortar fotos al vuelo.<\/p>\n<p>Este es un buen caso de uso, cuando, por ejemplo, tienes una aplicaci\u00f3n m\u00f3vil que muestra fotos, y la aplicaci\u00f3n no quiere utilizar la CPU del cliente para solicitar una foto grande y luego redimensionarla a un tama\u00f1o espec\u00edfico para insertarla en la vista. Simplemente podemos especificar din\u00e1micamente algunos par\u00e1metros en la URL, y la cach\u00e9 de fotos redimensionar\u00e1 la imagen. Generalmente, elegir\u00e1 el tama\u00f1o que tenemos f\u00edsicamente en el disco, lo m\u00e1s cercano a lo solicitado, y lo ajustar\u00e1 en las coordenadas espec\u00edficas.<\/p>\n<blockquote><p>Por cierto, hemos publicado en acceso abierto las grabaciones de video de los \u00faltimos cinco a\u00f1os de la conferencia de desarrolladores de sistemas de alta carga. <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/\">HighLoad++.<\/a><\/noindex>Mira, estudia, comparte y suscr\u00edbete al <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/profyclub\">canal de YouTube.<\/a><\/noindex>.<\/p><\/blockquote>\n<p>\nTambi\u00e9n podemos a\u00f1adir mucha l\u00f3gica de producto all\u00ed. Por ejemplo, podemos agregar diferentes marcas de agua seg\u00fan los par\u00e1metros de la URL, podemos desenfocar fotos, difuminar o pixelar. Esto es cuando queremos mostrar una foto de una persona, pero no queremos ense\u00f1ar su cara, funciona bien, todo esto est\u00e1 implementado aqu\u00ed.<\/p>\n<p>\u00bfQu\u00e9 hemos logrado? Hemos creado tres puntos de presencia, buena tasa de aciertos, y al mismo tiempo, el CPU de estas m\u00e1quinas no est\u00e1 inactivo. Ahora, por supuesto, se ha vuelto m\u00e1s importante que antes. Necesitamos poner m\u00e1quinas m\u00e1s potentes, pero vale la pena.<\/p>\n<p>Esto es lo que respecta a la entrega de fotos. Todo esto es bastante claro y obvio. Creo que no estoy descubriendo Am\u00e9rica, as\u00ed es como funciona pr\u00e1cticamente cualquier CDN.<\/p>\n<p>Y, probablemente, a un oyente experimentado le pueda surgir la pregunta: \u00bfpor qu\u00e9 no simplemente cambiar todo a un CDN? Ser\u00eda m\u00e1s o menos lo mismo, todos los CDN modernos pueden hacer eso. Y aqu\u00ed hay varias razones.<\/p>\n<p>La primera son las fotos.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/592c10eb74d46191bfcedec120f68556.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEste es uno de los aspectos clave de nuestra infraestructura, y necesitamos tener control sobre ellas tanto como sea posible. Si es una soluci\u00f3n de un proveedor externo, y no tienes ning\u00fan control sobre ella, te ser\u00e1 bastante dif\u00edcil vivir con ello cuando tienes un gran conjunto de datos y un flujo muy alto de solicitudes de usuarios.<\/p>\n<p>Voy a dar un ejemplo. Ahora en nuestra infraestructura, por ejemplo, en caso de alg\u00fan problema o golpes subterr\u00e1neos, podemos acceder a la m\u00e1quina, depurar all\u00ed, por decirlo de alguna manera. Podemos a\u00f1adir la recopilaci\u00f3n de m\u00e9tricas que solo a nosotros nos interesan, podemos experimentar de alguna manera, observar c\u00f3mo esto impacta en los gr\u00e1ficos, etc. Actualmente, se recopilan muchas estad\u00edsticas sobre este cl\u00faster de cach\u00e9. Y de vez en cuando las revisamos y analizamos a fondo algunas anomal\u00edas. Si esto estuviera del lado del CDN, ser\u00eda mucho m\u00e1s dif\u00edcil de controlar. O, por ejemplo, si ocurre alg\u00fan accidente, sabemos qu\u00e9 ha pasado, sabemos c\u00f3mo sobrellevarlo y c\u00f3mo solucionarlo. Esta es la primera conclusi\u00f3n.<\/p>\n<p>La segunda conclusi\u00f3n tambi\u00e9n es m\u00e1s bien hist\u00f3rica, porque el sistema ha estado evolucionando durante mucho tiempo y ha habido muchos requisitos comerciales diferentes en varias etapas, y no siempre se ajustan a la concepci\u00f3n del CDN.<\/p>\n<p>Y el punto que se deriva de lo anterior es:<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/007cf3aed2f9cc12185fc3865bf9d196.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs que en los fotocaches tenemos mucha l\u00f3gica espec\u00edfica, que no siempre se puede a\u00f1adir bajo solicitud. Dudo que alg\u00fan CDN vaya a a\u00f1adir cosas personalizadas a petici\u00f3n suya. Por ejemplo, el cifrado de URLs, si no desea que el cliente pueda modificar algo. Quiere cambiar la URL en el servidor y cifrarla, y luego pasar aqu\u00ed algunos par\u00e1metros din\u00e1micos.<\/p>\n<p>\u00bfQu\u00e9 conclusi\u00f3n se puede sacar? En nuestro caso, el CDN no es una alternativa muy buena.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/cfc2963cca2357cf6b0f63419a4dc436.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY en su caso, si tiene algunos requisitos comerciales espec\u00edficos, puede implementar por su cuenta lo que le he mostrado. Y esto funcionar\u00e1 perfectamente con un perfil de carga similar.<\/p>\n<p>Pero si tiene una soluci\u00f3n general y la tarea no es muy particular, puede optar por el CDN sin problemas. O si para usted es mucho m\u00e1s importante el tiempo y los recursos que el control.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b76d25404918a5d0d8bf1d6644c8d873.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY los CDN modernos tienen pr\u00e1cticamente todo lo que les he contado ahora. A excepci\u00f3n de algunas caracter\u00edsticas, m\u00e1s o menos.<\/p>\n<p>Esto en relaci\u00f3n con la entrega de fotos.<\/p>\n<p>Ahora, mov\u00e1monos un poco hacia adelante en nuestra retrospectiva y hablemos sobre almacenamiento.<\/p>\n<p>El a\u00f1o 2013 estaba en curso.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f218bfc899512041967842430c02aa9b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLos servidores de cach\u00e9 se han a\u00f1adido, los problemas de rendimiento han desaparecido. Todo est\u00e1 bien. El conjunto de datos est\u00e1 creciendo. En 2013 ten\u00edamos alrededor de 80 servidores conectados a los almacenamiento, y aproximadamente 40 servidores de cach\u00e9 en cada centro de datos. Esto equivale a 560 terabytes de datos en cada centro de datos, es decir, aproximadamente un petabyte en total.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef741ba4a9164e6940f55e93dfb46ef0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY con el crecimiento del conjunto de datos, los costos operativos comenzaron a aumentar significativamente. \u00bfEn qu\u00e9 se manifestaba esto?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6cf5e489a4e97bc6e26fc6d4d16505b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn este esquema, que est\u00e1 representado, con el SAN, las m\u00e1quinas conectadas a \u00e9l y las cach\u00e9s, hay muchos puntos de fallo. Mientras que con la falla de los servidores de cach\u00e9 ya hab\u00edamos logrado resolverlo, all\u00ed todo es m\u00e1s o menos predecible y entendible, en el lado del almacenamiento la situaci\u00f3n era mucho peor.<\/p>\n<p>Primero, la propia Red de \u00c1rea de Almacenamiento (SAN), que puede fallar.<\/p>\n<p>En segundo lugar, est\u00e1 conectada por fibra \u00f3ptica a las m\u00e1quinas finales. Pueden haber problemas con las tarjetas \u00f3pticas y los switches.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6959b79284c5b1244a70a1d64f191893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nClaro que no son tan numerosos como con el propio SAN, pero, aun as\u00ed, son puntos de fallo.<\/p>\n<p>Luego est\u00e1 la propia m\u00e1quina que est\u00e1 conectada al almacenamiento. Tambi\u00e9n puede fallar.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1801cb502663a4de14329a5e67dfed79.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn total, tenemos tres puntos de fallo.<\/p>\n<p>Adem\u00e1s, aparte de los puntos de fallo, el mantenimiento de las propias unidades de almacenamiento es complejo.<\/p>\n<p>Es un sistema multicompontente complicado, y a veces es dif\u00edcil para los ingenieros de sistemas.<\/p>\n<p>Y por \u00faltimo, el punto m\u00e1s importante. Si ocurre una falla en cualquiera de estos tres puntos, existe una probabilidad no nula de perder datos del usuario, ya que el sistema de archivos puede da\u00f1arse.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4bf8bc1c73a2beef74cb4ee0ee45679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSupongamos que nuestro sistema de archivos se ha da\u00f1ado. Su recuperaci\u00f3n lleva, en primer lugar, mucho tiempo \u2014 puede tardar una semana con un gran volumen de datos. Y en segundo lugar, lo m\u00e1s probable es que terminemos con un mont\u00f3n de archivos desconocidos que hay que relacionar de alguna manera con las fotos de los usuarios. Y corremos el riesgo de perder datos. El riesgo es bastante alto. Cuanto m\u00e1s a menudo ocurren tales situaciones, y cuanto m\u00e1s problemas surgen en toda esta cadena, mayor es este riesgo.<\/p>\n<p>Ten\u00eda que hacerse algo al respecto. Y decidimos que simplemente deb\u00edamos respaldar los datos. Esta es en realidad una soluci\u00f3n obvia y buena. \u00bfQu\u00e9 hicimos?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f80ec2b65003c40bd2fabf88966b3e05.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs\u00ed es como se ve\u00eda nuestro servidor, que estaba conectado al almacenamiento antes. Es una partici\u00f3n principal, simplemente un dispositivo de bloques que de hecho representa un montaje en el almacenamiento remoto a trav\u00e9s de fibra \u00f3ptica.<\/p>\n<p>Simplemente a\u00f1adimos una segunda partici\u00f3n.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d3dba75ef477269d92145cd69d587527.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nColocamos un segundo almacenamiento al lado (afortunadamente, no fue tan costoso) y lo llamamos secci\u00f3n de respaldo. Tambi\u00e9n est\u00e1 conectado por fibra \u00f3ptica, en la misma m\u00e1quina. Pero necesitamos sincronizar los datos entre ellos de alguna manera.<\/p>\n<p>Aqu\u00ed simplemente creamos una cola as\u00edncrona al lado.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/67bced2b45c589009cfb01a1c21398a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNo est\u00e1 muy cargada. Sabemos que tenemos pocas entradas. La cola es simplemente una tabla en MySQL donde se escriben l\u00edneas como \"necesito hacer una copia de seguridad de esta fotograf\u00eda\". En cualquier cambio o al subir, copiamos desde la secci\u00f3n principal a la de respaldo de forma as\u00edncrona o simplemente con alg\u00fan trabajador en segundo plano.<\/p>\n<p>Y as\u00ed, siempre tenemos dos secciones consistentes. Incluso si una parte de este sistema falla, siempre podemos cambiar la secci\u00f3n principal con la de respaldo, y todo seguir\u00e1 funcionando.<\/p>\n<p>Pero debido a esto, la carga de lectura aumenta significativamente, ya que, adem\u00e1s de los clientes que leen desde la secci\u00f3n principal (porque primero ven la fotograf\u00eda all\u00ed, ya que est\u00e1 m\u00e1s actualizada), luego buscan en la de respaldo si no la encuentran (pero esto lo gestiona simplemente NGINX), nuestra sistema de respaldo tambi\u00e9n lee desde la secci\u00f3n principal. No es que sea un punto cr\u00edtico, pero no quer\u00edamos aumentar la carga innecesariamente.<\/p>\n<p>Y a\u00f1adimos un tercer disco, que es un peque\u00f1o SSD, y lo llamamos b\u00fafer.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd35481822b4170087e5f670bf338dc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs\u00ed es como funciona ahora.<\/p>\n<p>El usuario sube una foto al b\u00fafer, luego se env\u00eda un evento a la cola informando que debe copiarse en las dos secciones. Se copia, y la fotograf\u00eda vive en el b\u00fafer por un tiempo (digamos, un d\u00eda) antes de ser purgada. Esto mejora significativamente la experiencia del usuario, porque cuando el usuario sube la fotograf\u00eda, generalmente recibe solicitudes inmediatamente despu\u00e9s, o actualiza la p\u00e1gina. Pero todo depende de la aplicaci\u00f3n que realiza la carga.<\/p>\n<p>O, por ejemplo, otras personas a las que se les empieza a mostrar la foto env\u00edan tambi\u00e9n solicitudes de inmediato. En la cach\u00e9 a\u00fan no est\u00e1, la primera solicitud se realiza muy r\u00e1pido. En esencia, es como el cach\u00e9 de fotos. El almacenamiento lento no participa en esto. Y cuando sea purgada despu\u00e9s de un d\u00eda, ya estar\u00e1 almacenada en nuestra capa de cach\u00e9, o es probable que ya no le interese a nadie. Es decir, la experiencia del usuario ha mejorado mucho gracias a estas simples manipulaciones.<\/p>\n<p>Y lo m\u00e1s importante: hemos dejado de perder datos.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/526f549457dd0c438f32b0adb76df76c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDigamos que hemos dejado de hacerlo. <em>potencialmente<\/em> perder datos, porque realmente no los perdimos. Pero hab\u00eda un peligro. Vemos que esta soluci\u00f3n, por supuesto, es buena, pero se asemeja un poco a tratar los s\u00edntomas del problema en lugar de resolverlo por completo. Y aqu\u00ed algunos problemas quedaron.<\/p>\n<p>En primer lugar, existe un punto de fallo en forma del propio host f\u00edsico, en el que toda esta maquinaria opera, y no ha desaparecido.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0eb3d292655a7edf912793ed81e8931c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn segundo lugar, quedan problemas con los SAN, su mantenimiento pesado, etc. No era un factor cr\u00edtico, pero nos gustar\u00eda intentar vivir sin ello.<\/p>\n<p>Y hicimos una tercera versi\u00f3n (en realidad, es la segunda) \u2014 la versi\u00f3n de respaldo. \u00bfC\u00f3mo fue eso?<\/p>\n<p>Esto es lo que hab\u00eda \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8b1749b6feed200f8a64529ee2316c1a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNuestros principales problemas son que es un host f\u00edsico.<\/p>\n<p>Primero, eliminamos los SAN porque queremos experimentar, queremos probar simplemente discos duros locales.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd0f5a8627d9179fcbc7097c1c18505f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nYa era 2014-2015, y en ese momento la situaci\u00f3n con los discos y su capacidad en un solo host hab\u00eda mejorado considerablemente. Decidimos, \u00bfpor qu\u00e9 no intentarlo?<\/p>\n<p>Y luego simplemente tomamos nuestra partici\u00f3n de respaldo y la trasladamos f\u00edsicamente a una m\u00e1quina separada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/456e00bc8557d3340b06efcd1dde8a08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe esta manera, obtenemos un esquema como este. Tenemos dos m\u00e1quinas que almacenan los mismos conjuntos de datos. Se respaldan mutuamente por completo y sincronizan los datos a trav\u00e9s de la red mediante una cola as\u00edncrona en el mismo MySQL.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d44cdb7b440ad4c58cc625123306a8c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00bfPor qu\u00e9 esto funciona bien? Porque tenemos pocas escrituras. Es decir, si la escritura fuera comparable a la lectura, probablemente tendr\u00edamos alg\u00fan overhead de red y problemas. Hay pocas escrituras, muchas lecturas \u2014 este m\u00e9todo funciona bien, es decir, rara vez copiamos fotos entre estos dos servidores.<\/p>\n<p>\u00bfC\u00f3mo funciona esto, si miramos un poco m\u00e1s en detalle?<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/071c11abb6ee1d7734c53052139ff04b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSubida. El balanceador simplemente elige hosts aleatorios de un par y hace la carga en uno de ellos. Al mismo tiempo, por supuesto, realiza controles de salud, revisa que la m\u00e1quina no haya ca\u00eddo. Es decir, solo carga fotos en un servidor activo, y luego, a trav\u00e9s de una cola as\u00edncrona, se copia todo a su vecino. Con la carga, todo es simplemente claro.<\/p>\n<p>La tarea es un poco m\u00e1s complicada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f494904aec823456e18b987a8c98bf56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAqu\u00ed nos ayud\u00f3 Lua, porque en NGINX vanilla es complicado implementar tal l\u00f3gica. Primero hacemos una solicitud al primer servidor, verificamos si la fotograf\u00eda est\u00e1 ah\u00ed, porque potencialmente podr\u00eda haberse subido, por ejemplo, al vecino, y aqu\u00ed todav\u00eda no ha llegado. Si la fotograf\u00eda est\u00e1 ah\u00ed, es genial. La entregamos de inmediato al cliente y, posiblemente, la almacenamos en cach\u00e9.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/de5f77e997bb049f4cfc1709da0f1788.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSi no est\u00e1, simplemente hacemos una solicitud al vecino y all\u00ed la obtenemos garantizadamente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/79aa5592acd28dfbc815261d0276c2e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs\u00ed que, nuevamente se puede decir: pueden haber problemas con el rendimiento, porque los constantes viajes de ida y vuelta \u2014 se subi\u00f3 la fotograf\u00eda, aqu\u00ed no est\u00e1, hacemos dos solicitudes en lugar de una, eso deber\u00eda funcionar lentamente.<\/p>\n<p>En nuestra situaci\u00f3n, esto no funciona lentamente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/52ca3902d80990f512201672cd5e6441.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEstamos recopilando un mont\u00f3n de m\u00e9tricas sobre este sistema, y la tasa de aciertos de dicho mecanismo es de aproximadamente 95%. Es decir, la latencia de este respaldo es peque\u00f1a, y gracias a eso pr\u00e1cticamente garantizamos que despu\u00e9s de que la foto ha sido cargada, la recuperamos en el primer intento y no tenemos que ir dos veces.<\/p>\n<p>As\u00ed que, \u00bfqu\u00e9 m\u00e1s hemos conseguido, y qu\u00e9 es realmente genial?<\/p>\n<p>Antes ten\u00edamos la secci\u00f3n principal de respaldo, y le\u00edamos de forma secuencial. Es decir, siempre busc\u00e1bamos primero en la principal y luego en el respaldo. Era un solo recorrido.<\/p>\n<p>Ahora estamos utilizando la lectura de dos m\u00e1quinas simult\u00e1neamente. Distribuimos las solicitudes en Round Robin. En un peque\u00f1o porcentaje de casos hacemos dos solicitudes. Pero en general ahora tenemos el doble de capacidad de lectura que antes. Y la carga ha disminuido significativamente, tanto en las m\u00e1quinas que entregan, como en los storages que ten\u00edamos en ese momento.<\/p>\n<p>En cuanto a la resistencia a fallos. En realidad, eso era con lo que principalmente luch\u00e1bamos. La resistencia a fallos ha resultado ser fant\u00e1stica aqu\u00ed.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a030a477e60d6e1f3d0b4e3395013df5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUna m\u00e1quina deja de funcionar.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/42900b24e340c03ea642fd49f5b410ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00a1Sin problemas! El ingeniero de sistemas ni siquiera tiene que despertarse por la noche, puede esperar hasta la ma\u00f1ana, no pasar\u00e1 nada.<\/p>\n<p>Incluso si, al fallar esta m\u00e1quina, se interrumpe la cola, tampoco hay problemas, simplemente el registro comenzar\u00e1 a acumularse primero en la m\u00e1quina viva, y luego pasar\u00e1 a la cola, y despu\u00e9s a aquella m\u00e1quina que volver\u00e1 a estar operativa despu\u00e9s de un tiempo.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef42eadaaf3e3ecbf70847e9f88c1582.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLo mismo ocurre con el mantenimiento. Simplemente apagamos una de las m\u00e1quinas, la sacamos manualmente de todos los grupos, deja de recibir tr\u00e1fico, realizamos alg\u00fan mantenimiento, hacemos algunos ajustes y luego la reincorporamos. Este backup se recupera bastante r\u00e1pido. Es decir, un d\u00eda de inactividad de una m\u00e1quina se compensa en un par de minutos. Eso es realmente muy poco. Con la tolerancia a fallos, como dije, aqu\u00ed todo funciona muy bien.<\/p>\n<p>\u00bfQu\u00e9 conclusiones se pueden sacar de este esquema de redundancia?<\/p>\n<p>Hemos conseguido tolerancia a fallos.<\/p>\n<p>Explotaci\u00f3n sencilla. Dado que las m\u00e1quinas tienen discos duros locales, esto es mucho m\u00e1s conveniente desde el punto de vista de los ingenieros que trabajan con ellos.<\/p>\n<p>Hemos logrado un doble margen para la lectura.<\/p>\n<p>Esto es un muy buen bonus adem\u00e1s de la tolerancia a fallos.<\/p>\n<p>Pero tambi\u00e9n hay problemas. Ahora tenemos un desarrollo mucho m\u00e1s complicado de algunas caracter\u00edsticas relacionadas, porque el sistema se ha vuelto 100% eventualmente consistente.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b650276a41730cc303180e8304c5dabb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDebemos, digamos, en alg\u00fan trabajo en segundo plano, estar siempre pensando: '\u00bfEn qu\u00e9 servidor estamos ahora?', '\u00bfHay aqu\u00ed una foto actualizada?' y as\u00ed sucesivamente. Esto, por supuesto, est\u00e1 envuelto en capas, y para el programador que escribe la l\u00f3gica de negocio, es transparente. Pero, sin embargo, ha aparecido una capa compleja considerable. Pero estamos dispuestos a lidiar con esto a cambio de las ventajas que hemos obtenido.<\/p>\n<p>Y aqu\u00ed de nuevo surge un cierto conflicto.<\/p>\n<p>Al principio dije que almacenar todo en discos duros locales es malo. Y ahora digo que nos ha gustado.<\/p>\n<p>S\u00ed, realmente con el tiempo la situaci\u00f3n ha cambiado mucho y ahora este enfoque tiene muchas ventajas. En primer lugar, obtenemos una explotaci\u00f3n mucho m\u00e1s sencilla.<\/p>\n<p>En segundo lugar, es m\u00e1s eficiente porque no tenemos esos controladores autom\u00e1ticos y conexiones a estanter\u00edas de discos.<\/p>\n<p>All\u00ed hay una maquinaria enorme, mientras que aqu\u00ed solo hay unos pocos discos que est\u00e1n configurados en RAID en la m\u00e1quina.<\/p>\n<p>Pero tambi\u00e9n hay desventajas.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3c090e0801f1a686dc0d5fefce697c56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs aproximadamente 1.5 veces m\u00e1s caro que usar SAN, incluso a los precios de hoy. Por lo tanto, decidimos no convertir todo nuestro gran cl\u00faster en m\u00e1quinas con discos duros locales y optamos por dejar una soluci\u00f3n h\u00edbrida.<\/p>\n<p>Casi la mitad de nuestras m\u00e1quinas trabaja con discos duros (bueno, no la mitad, probablemente alrededor del 30%). Y el resto son m\u00e1quinas antiguas, en las que antes hab\u00eda un primer esquema de respaldo. Simplemente las reconfiguramos, ya que no necesitamos nuevos datos ni nada m\u00e1s, solo movimos los montajes de un anfitri\u00f3n f\u00edsico a dos.<\/p>\n<p>Y ahora tenemos un gran margen en lectura, y hemos ampliado. Antes mont\u00e1bamos un almacenamiento por m\u00e1quina, ahora montamos cuatro en una pareja, por ejemplo. Y eso funciona bien.<\/p>\n<p>Vamos a hacer un breve resumen de lo que hemos logrado, por qu\u00e9 luchamos y si lo conseguimos.<\/p>\n<h3>Resultados<\/h3>\n<p>\nTenemos usuarios: un total de 33 millones.<\/p>\n<p>Contamos con tres puntos de presencia: Praga, Miami, Hong Kong.<\/p>\n<p>En ellos hay una capa de cach\u00e9, que consiste en m\u00e1quinas con discos locales r\u00e1pidos (SSD), en las que opera un simple sistema basado en NGINX, su access.log y demonios en Python que procesan y gestionan la cach\u00e9.<\/p>\n<p>Si lo deseas, en tu proyecto, si las fotos no son tan cr\u00edticas para ti como para nosotros, o si el intercambio entre control y velocidad de desarrollo y gasto de recursos te favorece en otro sentido, entonces puedes reemplazarlo por un CDN, que los modernos hacen muy bien.<\/p>\n<p>A continuaci\u00f3n, est\u00e1 la capa de almacenamiento, donde tenemos cl\u00fasteres de pares de m\u00e1quinas que se respaldan entre s\u00ed, los archivos se copian de uno a otro de forma as\u00edncrona ante cualquier cambio.<\/p>\n<p>Parte de estas m\u00e1quinas trabaja con discos duros locales.<\/p>\n<p>Parte de estas m\u00e1quinas est\u00e1n conectadas a SAN.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5ddbc4f73d86aa1f83734885d8c9dea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nY, por un lado, esto es m\u00e1s conveniente en la operaci\u00f3n y un poco m\u00e1s eficiente; por otro lado, es c\u00f3modo en t\u00e9rminos de densidad de colocaci\u00f3n y costo por gigabyte.<\/p>\n<p>Esta es una breve revisi\u00f3n de la arquitectura de lo que hemos logrado y c\u00f3mo ha evolucionado todo esto.<\/p>\n<p>Un par de consejos sencillos del jefe.<\/p>\n<p>Primero, si alguna vez decides que necesitas mejorar urgentemente toda tu infraestructura de fotos, primero mide, porque puede que no necesites mejorar nada.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7770f41d0b190eb78ae0d19f4c8182a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUn ejemplo. Tenemos un cl\u00faster de m\u00e1quinas que entrega fotos desde los attachments en los chats, y all\u00ed todav\u00eda funciona un esquema de 2009, y nadie se queja. A todos les va bien, a todos les gusta.<\/p>\n<p>Para medir, primero necesitas establecer una serie de m\u00e9tricas, observarlas y luego decidir qu\u00e9 te desagrada y qu\u00e9 necesitas mejorar. Para medir esto, tenemos una herramienta genial llamada Pinba.<\/p>\n<p>Permite recopilar estad\u00edsticas de NGINX de manera muy detallada para cada solicitud y c\u00f3digos de respuesta, as\u00ed como la distribuci\u00f3n de tiempos: todo lo que desees. Tiene integraciones con diferentes sistemas de an\u00e1lisis, y luego puedes visualizar todo esto de manera clara.<\/p>\n<p>Primero medimos, luego mejoramos.<\/p>\n<p>A continuaci\u00f3n. Optimizar la lectura con cach\u00e9, la escritura con particionamiento, pero este es un punto obvio.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f53a4777f1a2c7793eba4a72c94263a4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA continuaci\u00f3n. Si est\u00e1s comenzando a construir tu sistema, es mucho mejor tratar las im\u00e1genes como archivos inmutables. Esto te evita perder una clase entera de problemas relacionados con la invalidaci\u00f3n de cach\u00e9 y con la l\u00f3gica que debe encontrar la versi\u00f3n correcta de la imagen, entre otros.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f345c59681275326cda1320b4f188ce9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSupongamos que subiste una foto y luego la rotaste; aseg\u00farate de que sea un archivo f\u00edsicamente diferente. Es decir, no pienses: voy a ahorrar un poco de espacio, grabando en el mismo archivo y cambiando la versi\u00f3n. Esto siempre resulta contraproducente y genera muchos dolores de cabeza despu\u00e9s.<\/p>\n<p>El siguiente punto. Sobre el redimensionamiento en tiempo real.<\/p>\n<p>Antes, cuando los usuarios sub\u00edan una foto, cort\u00e1bamos un mont\u00f3n de tama\u00f1os para todas las eventualidades, para diferentes clientes, y todos estaban almacenados en el disco. Ahora hemos abandonado esa pr\u00e1ctica.<\/p>\n<p>Hemos conservado solo tres tama\u00f1os b\u00e1sicos: peque\u00f1o, mediano y grande. Todo lo dem\u00e1s lo redimensionamos a partir del tama\u00f1o que se solicita en Uport, simplemente hacemos un downscale y se lo entregamos al usuario.<\/p>\n<p>El costo de la capa de cach\u00e9 de CPU es mucho menor aqu\u00ed que si tuvi\u00e9ramos que regenerar continuamente esos tama\u00f1os en cada almacenamiento. Supongamos que queremos a\u00f1adir uno nuevo, eso puede tardar un mes: ejecutar un script en todas partes que haga esto cuidadosamente sin colapsar el cl\u00faster. Es decir, si hay posibilidad de elecci\u00f3n, es mejor tener la menor cantidad posible de tama\u00f1os f\u00edsicos, pero mantener alguna distribuci\u00f3n, digamos, tres. Y el resto simplemente redimensionarlo sobre la marcha utilizando m\u00f3dulos ya disponibles. Esto es ahora muy f\u00e1cil y accesible.<\/p>\n<p>Y una copia de seguridad incremental as\u00edncrona es algo bueno.<\/p>\n<p>Nuestra experiencia ha demostrado que este esquema funciona muy bien con la copia diferida de archivos modificados.<\/p>\n<p><img decoding=\"async\" alt=\"Arquitectura de almacenamiento y entrega de fotograf\u00edas en Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0e550721e838654e61e1fa4d08f9bb93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEl \u00faltimo punto tambi\u00e9n es obvio. Si en su infraestructura actualmente no hay estos problemas, pero hay algo que puede fallar, seguramente fallar\u00e1 cuando ese algo aumente un poco. Por lo tanto, es mejor pensar en esto de antemano y no experimentar problemas en el camino. Eso es todo de mi parte.<\/p>\n<h3>Contactos<\/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 de la empresa Badoo<\/a><\/noindex><\/p>\n<blockquote><p>Este informe es la transcripci\u00f3n de una de las mejores presentaciones en la conferencia de desarrolladores 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>. Queda menos de un mes para la conferencia HighLoad++ 2017.<\/p>\n<p>Ya tenemos listo <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\">Programa de la conferencia<\/a><\/noindex>, actualmente se est\u00e1 formando el horario.<\/p>\n<p>Este a\u00f1o continuamos explorando el tema de arquitecturas y escalado:<\/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\">C\u00f3mo servir a mil millones de usuarios y entregar un terabit de tr\u00e1fico<\/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\">C\u00f3mo reescribir desde cero la base de datos de mensajes personales de VKontakte y migrar a ella sin tiempo de inactividad<\/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\">La muerte por liquidaci\u00f3n: c\u00f3mo Yandex.Money intent\u00f3 acelerarse para el Black Friday y 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\">Arquitectura resistente de la sistema frontal del 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\">Arquitectura del sistema de pagos: casi enterprise<\/a><\/noindex> \/ \u0424\u0438\u043b\u0438\u043f\u043f \u0414\u0435\u043b\u044c\u0433\u044f\u0434\u043e<\/li>\n<\/ul>\n<p>\nTambi\u00e9n algunos de estos materiales son utilizados por nosotros en un curso en l\u00ednea de formaci\u00f3n en desarrollo 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> es una cadena de cartas, art\u00edculos, materiales y videos cuidadosamente seleccionados. Ya en nuestro libro de texto hay m\u00e1s de 30 materiales \u00fanicos. \u00a1\u00danete!\n<\/p><\/blockquote>\n<p>Fuente: <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.2 - 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\/es\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\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\/es\/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\udd47Arquitectura de almacenamiento y entrega de fotos en Badoo | ProHoster","description":"Artem Denisov (","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/55009","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=55009"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/55009\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=55009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=55009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=55009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}