{"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\/it\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","title":{"rendered":"Architettura di archiviazione e restituzione delle fotografie in Badoo","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in 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 \u00e8 il sito di incontri pi\u00f9 grande al mondo. Attualmente abbiamo circa 330 milioni di utenti registrati in tutto il mondo. Ma ci\u00f2 che \u00e8 molto pi\u00f9 importante nel contesto della nostra conversazione di oggi, \u00e8 il fatto che memorizziamo circa 3 petabyte di foto degli utenti. Ogni giorno i nostri utenti caricano circa 3,5 milioni di nuove foto e il carico di lettura \u00e8 di circa <b>80.000 richieste al secondo<\/b>. \u00c8 un bel po' per il nostro backend, e a volte ci sono delle difficolt\u00e0.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4e4690f9b0d95bd76fbbc1cd6805c26c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nParler\u00f2 del design di questo sistema, che memorizza e restituisce le foto in generale, e dar\u00f2 uno sguardo a esso dal punto di vista del programmatore. Far\u00f2 una breve retrospettiva su come si \u00e8 evoluto, dove segner\u00f2 i principali traguardi, ma parler\u00f2 pi\u00f9 dettagliatamente solo delle soluzioni che utilizziamo attualmente.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nE ora cominciamo.<\/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=\"Guarda il video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nCome ho gi\u00e0 detto, sar\u00e0 una retrospettiva, e per cominciarla, prendiamo il pi\u00f9 semplice degli esempi.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/22b9627cda7ccadd9869b64e9d043d89.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAbbiamo un compito generale, dobbiamo ricevere, memorizzare e restituire le foto degli utenti. In questo modo il compito \u00e8 generale, possiamo usare qualsiasi cosa:<\/p>\n<ul>\n<li>un moderno storage cloud,<\/li>\n<li>una soluzione preconfezionata, di cui ce ne sono molte in questo momento;<\/li>\n<li>possiamo configurare alcune macchine nel nostro data center e installare grandi dischi rigidi per memorizzare le foto l\u00ec.<\/li>\n<\/ul>\n<p>\nBadoo storicamente \u2014 e sia allora che ora (nel periodo in cui tutto ci\u00f2 ha appena preso piede) \u2014 vive sui propri server, all'interno dei nostri data center. Pertanto, per noi questa opzione era ottimale.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9434fbabada15670297c551066ad7e71.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAbbiamo semplicemente preso alcune macchine, le abbiamo chiamate \"photos\", ed \u00e8 nato un cluster che memorizza le foto. Ma sembra che manchi qualcosa. Per fare in modo che tutto ci\u00f2 funzioni, dobbiamo in qualche modo determinare su quale macchina memorizzeremo quali foto. E non c'\u00e8 bisogno di scoprire l'America nemmeno qui.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/36258e7107fd8c60f7e9e563a2cb681c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAggiungiamo al nostro storage con informazioni sugli utenti un campo. Questo sar\u00e0 la chiave per lo sharding. Nel nostro caso, lo abbiamo chiamato place_id, e questo id dei luoghi indica il posto in cui sono memorizzate le foto degli utenti. Creiamo le mappe.<\/p>\n<p>Nella prima fase, si pu\u00f2 anche fare a mano: diciamo che la foto di questo utente con questo posto atterrer\u00e0 su questo server. Grazie a questa mappa sappiamo sempre quando l'utente carica una foto, dove salvarla e sappiamo da dove restituirla.<\/p>\n<p>\u00c8 uno schema assolutamente banale, ma ha vantaggi piuttosto significativi. Il primo \u00e8 che \u00e8 semplice, come ho gi\u00e0 detto, e il secondo \u00e8 che con questo approccio possiamo facilmente scalare orizzontalmente, semplicemente consegnando nuove macchine e aggiungendole alla mappa. Non c'\u00e8 bisogno di fare altro.<\/p>\n<p>Cos\u00ec \u00e8 stato per un certo periodo da noi.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3effb442702f162f7bad9c18ec54392e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEra pi\u00f9 o meno nel 2009. Consegnavamo macchine, consegnavamo...<\/p>\n<p>E a un certo punto abbiamo cominciato a notare che questo schema presentava alcuni svantaggi. Quali svantaggi?<\/p>\n<p>In primo luogo, la capacit\u00e0 limitata. Su un singolo server fisico non possiamo mettere cos\u00ec tanti dischi rigidi come vorremmo. E nel tempo, con la crescita del dataset, \u00e8 diventato un problema.<\/p>\n<p>E in secondo luogo. Questa \u00e8 una configurazione non tipica delle macchine, poich\u00e9 tali macchine sono difficili da riutilizzare in altri cluster, sono abbastanza specifiche, cio\u00e8 devono essere a bassa potenza, ma allo stesso tempo con ampi dischi rigidi.<\/p>\n<p>Tutto ci\u00f2 risale al 2009, ma in linea di massima queste richieste sono ancora valide oggi. Abbiamo una retrospettiva, quindi nel 2009 tutto andava male in questo senso.<\/p>\n<p>E l'ultimo punto \u00e8 il prezzo.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e49010eaeab139199d8fe010caa65bf0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl prezzo allora era davvero elevato, e dovevamo cercare delle alternative. Cio\u00e8, dovevamo in qualche modo ottimizzare meglio sia lo spazio nei data center che i server fisici su cui tutto questo era ospitato. E i nostri ingegneri di sistema iniziarono una grande ricerca, rivedendo un sacco di diverse opzioni. Esaminarono anche i file system cluster, come PolyCeph e Lustre. C'erano problemi di prestazioni e una gestione piuttosto pesante. Hanno rinunciato. Hanno provato a montare l'intero dataset tramite NFS su ciascuna macchina, per cercare di scalare in questo modo. Anche la lettura non \u00e8 andata bene, hanno provato diverse soluzioni da diversi fornitori.<\/p>\n<p>E alla fine abbiamo deciso di utilizzare quella che chiamiamo Storage Area Network.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/e99402fa641f3bd5fc8d57a9f8995642.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSi tratta di grandi SHD, progettati per l'archiviazione di ampie volumetrie di dati. Rappresentano scaffali con dischi montati su macchine di output finali tramite fibra ottica. Cos\u00ec facendo, abbiamo un certo pool di macchine, sufficientemente ridotto, e queste SHD, che sono trasparenti per la nostra logica di output, cio\u00e8 per il nostro nginx o altro, gestiscono le richieste per queste fotografie.<\/p>\n<p>Questo approccio ha evidenti vantaggi. Si tratta di SHD. Sono orientati a memorizzare foto. Risulta pi\u00f9 economico rispetto a configurare direttamente macchine con dischi rigidi.<\/p>\n<p>Secondo vantaggio. <\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7fd2e7d629cc239096b14c68be5f76bf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl fatto \u00e8 che la capacit\u00e0 \u00e8 aumentata notevolmente, cio\u00e8 possiamo archiviare molto pi\u00f9 storage in un volume molto ridotto.<\/p>\n<p>Ma ci sono stati anche svantaggi, che sono emersi abbastanza rapidamente. Con l'aumento del numero di utenti e del carico su questo sistema, sono iniziate a sorgere problematiche di prestazioni. E il problema \u00e8 piuttosto evidente: qualsiasi SHD progettata per immagazzinare molte foto in poco spazio di solito soffre di letture intensive. Questo vale realmente anche per qualsiasi storage cloud o qualunque altra cosa. Attualmente, non esiste uno storage ideale che sia scalabile all'infinito, nel quale si possa infilarci di tutto e che gestisca molto bene le letture. Soprattutto le letture casuali.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/566e836e2fe13a2a3d040ae3fa865d6d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCome nel caso delle nostre foto, perch\u00e9 le fotografie vengono richieste in modo non sequenziale, e questo incide notevolmente sulle loro prestazioni.<\/p>\n<p>Anche secondo le attuali statistiche, se superiamo i 500 RPS per macchina per le foto collegate allo storage, inizia a sorgere qualche problema. E questo \u00e8 stato piuttosto problematico per noi, poich\u00e9 il numero di utenti cresce e tutto dovrebbe diventare solo peggio. Dobbiamo ottimizzarlo in qualche modo.<\/p>\n<p>Per ottimizzare, abbiamo deciso di esaminare profili di carico \u2014 cosa sta accadendo e cosa deve essere ottimizzato.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d67310e6b90c4ee1337065790576c9a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE qui tutto gioca a nostro favore.<\/p>\n<p>Nel primo slide ho gi\u00e0 menzionato: abbiamo 80 mila richieste al secondo per la lettura con solo 3,5 milioni di upload al giorno. Cio\u00e8, c'\u00e8 una differenza di tre ordini di grandezza. \u00c8 chiaro che bisogna ottimizzare le letture e quasi \u00e8 evidente come.<\/p>\n<p>C'\u00e8 un altro piccolo dettaglio. La specificit\u00e0 del servizio \u00e8 tale che una persona si registra, carica una foto, quindi inizia a guardare attivamente altre persone, a metterle mi piace, e viene mostrata attivamente ad altre persone. Poi trova una coppia o non la trova, dipende, e per un certo periodo smette di utilizzare il servizio. In quel momento, quando lo usa, le sue foto sono molto richieste \u2014 vengono visualizzate da molte persone. Appena smette di farlo, rapidamente esce da quelle intense visualizzazioni per altre persone, come avveniva prima, e le sue foto praticamente non vengono pi\u00f9 richieste.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/dcc7e306055d8f2b0895f24679bfc3e2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCio\u00e8, abbiamo un dataset molto piccolo ma molto caldo. Tuttavia, ci sono fin troppe richieste. E una soluzione ovvia qui \u00e8 aggiungere una cache.<\/p>\n<p>Una cache con LRU risolver\u00e0 tutti i nostri problemi. Cosa facciamo?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/2bd0c88a97d928f386db21549fc02500.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAggiungiamo prima del nostro grande cluster con lo storage un altro relativamente piccolo, che chiamiamo fotocache (photoscache). Questo \u00e8, in sostanza, solo un proxy che fa caching.<\/p>\n<p>Come funziona internamente? Ecco il nostro utente, ecco lo storage. Tutto come prima. Cosa aggiungiamo tra di loro?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7b7b5f102f1c012b2aef8f02ec731fac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c8 semplicemente una macchina con un disco locale fisico, che \u00e8 veloce. Per esempio, con SSD. E su questo disco viene memorizzato un certo caching locale.<\/p>\n<p>Come appare? L'utente invia una richiesta per una foto. NGINX la cerca prima nel cache locale. Se non c'\u00e8, semplicemente fa proxy_pass sul nostro storage, scarica la foto di l\u00ec e la fornisce all'utente.<\/p>\n<p>Ma \u00e8 molto banale e non \u00e8 chiaro cosa succeda dentro. Funziona pi\u00f9 o meno cos\u00ec.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/46be24df171d1008e2a9099b7e4c9be6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa cache \u00e8 logicamente suddivisa in tre strati. Quando dico \"tre strati\", non significa che ci sia un sistema complicato. No, sono semplicemente tre directory nel file system:<\/p>\n<ol>\n<li>Questo \u00e8 un buffer, dove vanno a finire le fotografie appena caricate dal proxy.<\/li>\n<li>Questo \u00e8 il cache caldo, in cui vengono conservate le foto attualmente richieste.<\/li>\n<li>E la cache fredda, dove gradualmente le foto vengono spostate da quella calda, quando ricevono meno richieste.<\/li>\n<\/ol>\n<p>\nAffinch\u00e9 ci\u00f2 funzioni, dobbiamo in qualche modo gestire questa cache, dobbiamo spostare le fotografie al suo interno, ecc. Anche questo \u00e8 un processo molto primitivo.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/9b16fe3e99a5f88f06169f6e5eedf2b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNginx registra semplicemente ogni richiesta su RAMDisk access.log, nel quale indica il percorso dell'immagine che sta servendo attualmente (il percorso relativo, ovviamente), e il modo in cui \u00e8 stata servita. Cio\u00e8, pu\u00f2 esserci scritto \"foto 1\" e poi un buffer, o una cache calda, o una cache fredda, o un proxy.<\/p>\n<p>A seconda di questo, dobbiamo in qualche modo prendere decisioni su cosa fare con l'immagine.<\/p>\n<p>Su ciascuna macchina abbiamo un piccolo demone che legge costantemente questo log e mantiene in memoria le statistiche sull'uso delle varie immagini.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0dceda5e5ff432d1609520f0c152f152.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSemplicemente raccoglie dati, tiene dei contatori e periodicamente fa quanto segue. Le foto pi\u00f9 richieste, per le quali arrivano molte richieste, vengono spostate nella cache calda, ovunque si trovino.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/941c13ecfea88372f3a7eb62d81b0c4e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLe foto che vengono richieste raramente e che vengono richieste sempre meno, vengono gradualmente espulse dalla cache calda a quella fredda.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a07235246995ad2fa4e6aeccae23a629.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE quando nella cache finisce lo spazio, iniziamo semplicemente a rimuovere tutto dalla cache fredda senza alcuna discriminazione. E questo, per inciso, funziona bene.<\/p>\n<p>Per garantire che l'immagine venga salvata immediatamente durante il proxy pass nel buffer, utilizziamo la direttiva proxy_store e il buffer \u00e8 anch'esso RAMDisk, cio\u00e8 per l'utente funziona molto rapidamente. Questo riguarda le internes del server di caching stesso.<\/p>\n<p>Resta da affrontare la questione di come distribuire le richieste tra questi server.<\/p>\n<p>Supponiamo ci sia un cluster di venti macchine di storage e tre server di caching (\u00e8 cos\u00ec che \u00e8 andata).<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6bc970b687701f3b6d57e153e3abed18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDobbiamo in qualche modo determinare quali richieste sono associate a quali immagini e dove indirizzarle.<\/p>\n<p>La soluzione pi\u00f9 banale \u00e8 il Round Robin. O farlo casualmente?<\/p>\n<p>Questo, ovviamente, ha una serie di svantaggi, perch\u00e9 utilizzeremo molto inefficacemente la cache in tal caso. Le richieste verranno indirizzate su macchine casuali: qui \u00e8 stata memorizzata, sulla macchina accanto non c'\u00e8 pi\u00f9. E funzioner\u00e0, se funzioner\u00e0, molto male. Anche con un numero ridotto di macchine nel cluster.<\/p>\n<p>Dobbiamo in qualche modo determinare inequivocabilmente su quale server indirizzare quale richiesta.<\/p>\n<p>C'\u00e8 un modo banale. Prendiamo l'hash dell'URL o l'hash della chiave di sharding che \u00e8 nell'URL, e lo dividiamo per il numero di server. Funzioner\u00e0? Sicuramente.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/794a82ac1268b651ab936f0225b802a2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCio\u00e8, abbiamo una richiesta al cento per cento, ad esempio, per un certo \u00abexample_url\u00bb che arriver\u00e0 sempre al server con indice \u00ab2\u00bb, e la cache sar\u00e0 costantemente utilizzata nel miglior modo possibile.<\/p>\n<p>Ma sorge un problema con il resharding in questo schema. Resharding \u2014 intendo dire la modifica del numero di server.<\/p>\n<p>Supponiamo che il nostro cluster di caching non riesca pi\u00f9 a gestire il carico e abbiamo deciso di aggiungere un'altra macchina.<\/p>\n<p>Aggiungiamo.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5f2fcba4c4f267c069811c3677bd0213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAdesso tutto si divide in modo intero non su tre, ma su quattro. In questo modo, praticamente tutte le chiavi che avevamo prima, praticamente tutti gli URL ora vivono su altri server. Entire cache \u00e8 stata invalidata in un attimo. Tutte le richieste si sono concentrate sul nostro cluster di storage, \u00e8 andato in crisi, si sono avute interruzioni del servizio e utenti insoddisfatti. Non vogliamo fare cos\u00ec.<\/p>\n<p>Questa opzione non ci piace neanche.<\/p>\n<p>Quindi, cosa dobbiamo fare? Dobbiamo in qualche modo utilizzare in modo efficace la cache, mantenendo costantemente una richiesta sullo stesso server, ma allo stesso tempo essere resilienti al resharing. E c'\u00e8 una soluzione per questo, non \u00e8 poi cos\u00ec complicata. Si chiama hashing consistente.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1380758686274df9755a7ebf7d1c8753.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCome si presenta?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/44f97abfac46fa9f361055548819e8a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrendiamo qualche funzione dalla chiave di sharding e distribuiamo tutti i suoi valori su un cerchio. Cio\u00e8, nel punto 0 abbiamo i suoi valori minimi e massimi che si incontrano. Inoltre, su questo stesso cerchio disponiamo tutti i nostri server in questo modo:<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d470ec615a789913a6baa2726b05acea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOgni server \u00e8 rappresentato da un punto e il settore che si estende fino a quel punto in senso orario \u00e8 quindi servito da quel host. Quando riceviamo le richieste, vediamo subito che, ad esempio, la richiesta A \u2014 ha un certo hash \u2014 e viene servita dal server 2. La richiesta B \u2014 dal server 3. E cos\u00ec via.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fcdbd1caa9f1162cf02e8b0a1c79cb74.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCosa succede in questa situazione durante il resharing?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7386cda826e9419d5f8a9a0d6d6703c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNon invalidiamo pi\u00f9 l'intera cache, come prima, e non spostiamo tutte le chiavi, ma spostiamo ogni settore di una piccola distanza in modo tale che, per cos\u00ec dire, nel posto liberato possa entrare il nostro sesto server che vogliamo aggiungere, e lo aggiungiamo l\u00ec.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8680e0cf023ce911b4d162e9102c0545.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCerto, in questa situazione anche le chiavi si spostano. Ma si spostano molto meno di prima. E vediamo che le nostre prime due chiavi sono rimaste sui loro server, mentre il server di caching \u00e8 cambiato solo per l'ultima chiave. Funziona in modo abbastanza efficace, e se aggiungi nuovi host in modo incrementale, non ci sono grandi problemi. Aggiungi un po' alla volta, aspetti che la cache si riempia di nuovo, e tutto funziona bene.<\/p>\n<p>Resta solo una domanda in caso di guasti. Supponiamo che un nostro server sia fuori servizio.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8e3301af782ce8983716c4bc9add79a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE non ci piacerebbe molto dover rigenerare questa mappa, invalidare parte della cache e cos\u00ec via, se, ad esempio, il server \u00e8 stato riavviato, ma dobbiamo comunque gestire le richieste. Manteniamo semplicemente un backup della cache fotografica su ogni sito, che funge da sostituto per qualsiasi server che attualmente \u00e8 fuori servizio. E se un server diventa improvvisamente non disponibile, il traffico viene reindirizzato l\u00ec. Naturalmente, in questo caso non abbiamo alcuna cache, cio\u00e8 \u00e8 fredda, ma, almeno, le richieste degli utenti vengono elaborate. Se questo intervallo \u00e8 breve, lo gestiamo tranquillamente. C'\u00e8 solo un maggior carico sullo storage. Se l'intervallo \u00e8 lungo, possiamo gi\u00e0 decidere se rimuovere questo server dalla mappa o meno, o magari sostituirlo con un altro.<\/p>\n<p>Questo riguarda il sistema di caching. Vediamo i risultati.<\/p>\n<p>Semberebbe che non ci sia nulla di complicato. Ma questo metodo di gestione della cache ci ha dato un tasso di successo del 98%. Cio\u00e8, di queste 80.000 richieste al secondo, solo 1.600 arrivano allo storage, e questo \u00e8 un carico assolutamente normale, lo gestiscono tranquillamente, abbiamo sempre un margine.<\/p>\n<p>Abbiamo posizionato questi server in tre dei nostri DC, e abbiamo ottenuto tre punti di presenza: Praga, Miami e Hong Kong.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/64eef492b65a014d8ba3c808b6579b41.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCos\u00ec, sono pi\u00f9 o meno localizzati vicino a ciascuno dei nostri mercati target.<\/p>\n<p>E come piacevole bonus abbiamo ottenuto questo proxy di caching, su cui la CPU in realt\u00e0 \u00e8 inattiva, perch\u00e9 per la distribuzione dei contenuti non \u00e8 cos\u00ec necessaria. E l\u00ec, con NGINX + Lua, abbiamo implementato molte logiche utilitaristiche.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b65c609df5e1985240d04ee65a3e4f55.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAd esempio, possiamo sperimentare con webp o jpeg progressivo (questi sono formati moderni ed efficienti), vedere come influiscono sul traffico, prendere decisioni, attivarli per determinati paesi, ecc.; effettuare il ridimensionamento dinamico o il ritaglio delle foto al volo.<\/p>\n<p>\u00c8 un buon caso d'uso, quando ad esempio hai un'app mobile che mostra foto, e l'app mobile non vuole sprecare CPU del client per richiedere una foto grande e poi ridimensionarla a una certa dimensione per inserirla nella vista. Possiamo semplicemente specificare dinamicamente alcuni parametri nell'URL in UPort, e il fotocache ridimensioner\u00e0 automaticamente la foto. Di solito, sceglier\u00e0 la dimensione che abbiamo fisicamente sul disco, la pi\u00f9 vicina a quella richiesta, e la ridimensioner\u00e0 nelle coordinate specifiche.<\/p>\n<blockquote><p>A proposito, abbiamo pubblicato registrazioni video degli ultimi cinque anni della conferenza per sviluppatori di sistemi ad alta carico. <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex>. Guardate, studiate, condividete e iscrivetevi al <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/profyclub\">canale YouTube<\/a><\/noindex>.<\/p><\/blockquote>\n<p>\nPossiamo anche aggiungere molta logica di prodotto. Ad esempio, possiamo aggiungere diverse filigrane in base ai parametri dell'URL, possiamo sfocare le foto, sgranarle o pixelarle. Questo \u00e8 quando vogliamo mostrare la foto di una persona, ma non vogliamo mostrare il suo viso; funziona bene ed \u00e8 tutto implementato qui.<\/p>\n<p>Cosa abbiamo ottenuto? Abbiamo ottenuto tre punti di presenza, un buon tasso di successo, e nel contempo la CPU su queste macchine non \u00e8 inoperosa. Ora \u00e8 diventata, ovviamente, pi\u00f9 importante di prima. Dobbiamo mettere macchine un po' pi\u00f9 potenti, ma ne vale la pena.<\/p>\n<p>Questo riguarda la consegna delle fotografie. Qui tutto \u00e8 abbastanza chiaro e ovvio. Penso di non aver scoperto l'America, cos\u00ec funziona praticamente qualsiasi CDN.<\/p>\n<p>E, molto probabilmente, l'ascoltatore esperto potrebbe avere una domanda: perch\u00e9 non prendere semplicemente e cambiare tutto in CDN? Sarebbe pi\u00f9 o meno la stessa cosa, tutti i moderni CDN sanno farlo. E qui ci sono vari motivi.<\/p>\n<p>Il primo sono le foto.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/592c10eb74d46191bfcedec120f68556.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQuesto \u00e8 uno dei punti chiave della nostra infrastruttura e abbiamo bisogno di avere il massimo controllo su di esse. Se si tratta di una soluzione di un fornitore esterno e non si ha alcun potere su di essa, sar\u00e0 abbastanza difficile gestire questa situazione quando si dispone di un grande dataset e di un flusso molto ampio di richieste degli utenti.<\/p>\n<p>Faccio un esempio. Attualmente, sulla nostra infrastruttura, possiamo, ad esempio, nel caso ci siano problemi o rumori sotterranei, entrare nella macchina, fare il debugging l\u00ec, per cos\u00ec dire. Possiamo aggiungere la raccolta di metriche di cui abbiamo solo bisogno, possiamo sperimentare in vari modi, osservare come questo influisce sui grafici e cos\u00ec via. Attualmente si raccoglie un\u2019enorme quantit\u00e0 di statistiche su questo cluster di caching. E di tanto in tanto, diamo un\u2019occhiata e esploriamo a lungo alcune anomalie. Se fosse tutto dalla parte del CDN, sarebbe molto pi\u00f9 difficile controllare. Oppure, ad esempio, se si verifica un incidente, sappiamo cosa \u00e8 successo, sappiamo come viverci e come affrontarlo. Questa \u00e8 la prima conclusione.<\/p>\n<p>La seconda conclusione \u00e8 piuttosto storica, perch\u00e9 il sistema si \u00e8 sviluppato da tempo, e ci sono stati molteplici requisiti aziendali in diverse fasi, e non sempre si integrano nella concezione del CDN.<\/p>\n<p>E il punto che deriva dal precedente \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/007cf3aed2f9cc12185fc3865bf9d196.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c8 che sui fotocaching abbiamo molta logica specifica, che non sempre pu\u00f2 essere aggiunta su richiesta. \u00c8 poco probabile che un CDN aggiunga qualcosa di personalizzato su richiesta. Ad esempio, la crittografia degli URL, se non vuoi che il cliente possa modificarli. Vuoi cambiare l\u2019URL sul server e crittografarlo, e poi restituire qui alcuni parametri dinamici.<\/p>\n<p>Qual \u00e8 la conclusione che si impone? Nel nostro caso, il CDN non \u00e8 una buona alternativa.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/cfc2963cca2357cf6b0f63419a4dc436.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNel vostro caso, se avete requisiti aziendali specifici, potete tranquillamente implementare ci\u00f2 che vi ho mostrato. E questo funzioner\u00e0 benissimo con un profilo di carico simile.<\/p>\n<p>Ma se avete una soluzione generale, e la questione non \u00e8 molto particolare, potete tranquillamente usare un CDN. Oppure, se \u00e8 molto pi\u00f9 importante per voi avere tempo e risorse piuttosto che controllo.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b76d25404918a5d0d8bf1d6644c8d873.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE i moderni CDN hanno praticamente tutto ci\u00f2 di cui vi ho parlato ora. Con eccezione di alcune funzionalit\u00e0 pi\u00f9 o meno.<\/p>\n<p>Questo riguardo alla consegna delle fotografie.<\/p>\n<p>Ora spostiamoci un po' avanti nella nostra retrospettiva e parliamo di archiviazione.<\/p>\n<p>Era il 2013.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f218bfc899512041967842430c02aa9b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI server di caching sono stati aggiunti, i problemi di performance sono scomparsi. Tutto va bene. Il dataset cresce. Nel 2013 avevamo circa 80 server connessi agli storage e circa 40 server di caching in ogni data center. Questo equivale a 560 terabyte di dati in ciascun data center, cio\u00e8 circa un petabyte in totale.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef741ba4a9164e6940f55e93dfb46ef0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE con la crescita del dataset, anche i costi operativi sono aumentati notevolmente. In cosa si \u00e8 concretizzato questo?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6cf5e489a4e97bc6e26fc6d4d16505b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn questo schema, che \u00e8 disegnato \u2014 con SAN, le macchine connesse e i cache \u2014 ci sono molteplici punti di guasto. Se con il guasto dei server di caching eravamo gi\u00e0 riusciti a gestire la situazione, l\u00ec tutto era relativamente prevedibile e chiaro, dall'altro lato, quello dello storage, la situazione era molto peggiore.<\/p>\n<p>Innanzitutto, l'Storage Area Network (SAN) stesso, che pu\u00f2 guastarsi.<\/p>\n<p>In secondo luogo, \u00e8 connesso in fibra ottica alle macchine finali. Possono esserci problemi con le schede ottiche e gli switch.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/6959b79284c5b1244a70a1d64f191893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNaturalmente, non ce ne sono cos\u00ec tanti come con il SAN stesso, ma, comunque, queste sono anche punti di guasto.<\/p>\n<p>Dopo, c'\u00e8 la macchina stessa, che \u00e8 collegata allo storage. Anche questa pu\u00f2 guastarsi.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/1801cb502663a4de14329a5e67dfed79.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn totale abbiamo tre punti di guasto.<\/p>\n<p>Inoltre, a parte i punti di guasto, c'\u00e8 anche un pesante mantenimento stesso degli storage.<\/p>\n<p>\u00c8 un sistema complesso e multicomponente, e per gli ingegneri di sistema pu\u00f2 essere faticoso.<\/p>\n<p>E l'ultimo, il punto pi\u00f9 importante. Se si verifica un guasto in uno dei questi tre punti, c'\u00e8 una probabilit\u00e0 non trascurabile di perdere dati degli utenti, poich\u00e9 il file system potrebbe danneggiarsi.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/4bf8bc1c73a2beef74cb4ee0ee45679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSupponiamo che il file system si sia danneggiato. Il suo recupero richiede, innanzitutto, molto tempo \u2014 pu\u00f2 impiegare anche una settimana, a seconda del volume dei dati. E in secondo luogo, alla fine, \u00e8 probabile che otteniamo un sacco di file incomprensibili, che dovranno in qualche modo essere abbinati alle fotografie degli utenti. E rischiamo di perdere dati. Il rischio \u00e8 piuttosto elevato. E pi\u00f9 spesso si verificano tali situazioni e pi\u00f9 problemi sorgono in tutta questa catena, maggiore \u00e8 il rischio.<\/p>\n<p>Dovevamo fare qualcosa al riguardo. E abbiamo deciso che era necessario semplicemente fare un backup dei dati. In realt\u00e0, \u00e8 una soluzione ovvia e buona. Cosa abbiamo fatto?<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f80ec2b65003c40bd2fabf88966b3e05.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQuesto era il nostro server, che era connesso allo storage prima. C'\u00e8 una partizione principale, \u00e8 semplicemente un dispositivo a blocchi, che rappresenta in realt\u00e0 un montaggio su uno storage remoto tramite fibra ottica.<\/p>\n<p>Abbiamo semplicemente aggiunto una seconda partizione.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d3dba75ef477269d92145cd69d587527.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAbbiamo installato un secondo storage accanto (per fortuna, non \u00e8 costato molto) e l'abbiamo chiamato sezione di backup. \u00c8 collegato anch'esso in fibra ottica e si trova sulla stessa macchina. Tuttavia, dobbiamo in qualche modo sincronizzare i dati tra di loro.<\/p>\n<p>Qui creiamo semplicemente una coda asincrona accanto.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/67bced2b45c589009cfb01a1c21398a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNon \u00e8 molto sovraccarica. Sappiamo che abbiamo pochi record. La coda \u00e8 semplicemente una tabella in MySQL dove vengono scritte righe del tipo \"devo fare il backup di questa foto\". A ogni modifica o durante l'upload, copiamo dalla sezione principale a quella di backup tramite un lavoratore asincrono o semplicemente un background worker.<\/p>\n<p>In questo modo abbiamo sempre due sezioni consistenti. Anche se una parte di questo sistema si guasta, possiamo sempre sostituire la sezione principale con quella di backup e tutto continuer\u00e0 a funzionare.<\/p>\n<p>Tuttavia, ci\u00f2 aumenta notevolmente il carico di lettura, poich\u00e9 oltre ai clienti che leggono dalla sezione principale, perch\u00e9 inizialmente guardano la foto l\u00ec (\u00e8 pi\u00f9 aggiornata), poi cercano nel backup se non la trovano (ma questo lo fa semplicemente NGINX), in pi\u00f9 la nostra sistema di backup ora legge dalla sezione principale. Non si pu\u00f2 dire che fosse un collo di bottiglia, ma non volevo aumentare il carico, essenzialmente, senza motivo.<\/p>\n<p>E abbiamo aggiunto un terzo disco, che \u00e8 un piccolo SSD, e l'abbiamo chiamato buffer.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd35481822b4170087e5f670bf338dc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEcco come funziona adesso.<\/p>\n<p>L'utente carica la foto sul buffer, quindi viene inviato un evento in coda che deve essere copiata su entrambe le sezioni. Viene copiata e la foto rimane per un certo periodo (diciamo un giorno) nel buffer, e solo dopo viene eliminata. Questo migliora notevolmente l'esperienza utente, perch\u00e9 di solito quando l'utente carica una foto, subito dopo iniziano a arrivare le richieste, oppure lui stesso aggiorna la pagina, la ricarica. Ma tutto dipende dall'applicazione che fa l'upload.<\/p>\n<p>Oppure, ad esempio, altre persone a cui viene mostrata immediatamente la foto inviano subito richieste. Non \u00e8 ancora nella cache, la prima richiesta avviene molto rapidamente. In pratica, \u00e8 lo stesso che con la foto nella cache. Lo storage lento non partecipa affatto a questo. E quando dopo un giorno verr\u00e0 eliminata, sar\u00e0 gi\u00e0 o nella nostra cache di livello, oppure probabilmente non serve pi\u00f9 a nessuno. Quindi, l'esperienza utente qui \u00e8 notevolmente migliorata grazie a queste semplici manipolazioni.<\/p>\n<p>E, soprattutto, abbiamo smesso di perdere dati.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/526f549457dd0c438f32b0adb76df76c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDiciamo che abbiamo smesso <em>potenzialmente<\/em> perdere dati, perch\u00e9 in effetti non li abbiamo persi. Ma c'era un pericolo. Vediamo che una soluzione del genere \u00e8, ovviamente, buona, ma somiglia un po' a un trattamento dei sintomi del problema, invece di risolverlo definitivamente. E alcuni problemi sono rimasti.<\/p>\n<p>Innanzitutto, c'\u00e8 un punto di fallimento rappresentato dal server fisico stesso su cui funziona tutto questo, che non \u00e8 scomparso.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0eb3d292655a7edf912793ed81e8931c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn secondo luogo, ci sono ancora problemi con gli SAN, rimane la loro pesante manutenzione, ecc. Non era un fattore critico, ma volevamo provare a vivere senza di essi.<\/p>\n<p>E abbiamo realizzato la terza versione (di fatto la seconda) \u2014 la versione di backup. Come si presentava?<\/p>\n<p>Questo \u00e8 ci\u00f2 che c'era \u2013<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/8b1749b6feed200f8a64529ee2316c1a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI principali problemi che abbiamo sono legati al fatto che si tratta di un server fisico.<\/p>\n<p>Innanzitutto, eliminiamo gli SAN, perch\u00e9 vogliamo sperimentare, vogliamo provare a utilizzare solo dischi rigidi locali.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/fd0f5a8627d9179fcbc7097c1c18505f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSiamo gi\u00e0 nel 2014-2015, e a quel tempo la situazione con i dischi e la loro capacit\u00e0 in un singolo server \u00e8 migliorata notevolmente. Abbiamo deciso, perch\u00e9 non provare.<\/p>\n<p>Poi prendiamo semplicemente la nostra partizione di backup e la spostiamo fisicamente su una macchina separata.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/456e00bc8557d3340b06efcd1dde8a08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn questo modo, otteniamo questo schema. Abbiamo due macchine che memorizzano set di dati identici. Si riservano completamente a vicenda e sincronizzano i dati in rete tramite una coda asincrona nello stesso MySQL.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/d44cdb7b440ad4c58cc625123306a8c8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPerch\u00e9 funziona bene: perch\u00e9 abbiamo poche scritture. Cio\u00e8, se la scrittura fosse paragonabile alla lettura, avremmo probabilmente avuto qualche sovraccarico di rete e problemi. Ci sono poche scritture, molte letture \u2014 questo metodo funziona bene, cio\u00e8 copiamo abbastanza raramente le fotografie tra questi due server.<\/p>\n<p>In che modo funziona, se ci guardiamo pi\u00f9 da vicino.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/071c11abb6ee1d7734c53052139ff04b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUpload. Il bilanciatore di carico seleziona semplicemente server casuali in coppia e carica su di essi. Naturalmente, esegue controlli sulla salute, assicurandosi che la macchina non sia caduta. Cio\u00e8, carica foto solo su un server vivo, e poi attraverso una coda asincrona tutto viene copiato sul vicino. Per quanto riguarda l'upload, \u00e8 tutto estremamente semplice.<\/p>\n<p>Con il compito \u00e8 un po' pi\u00f9 complicato.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f494904aec823456e18b987a8c98bf56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQui ci ha aiutato Lua, perch\u00e9 fare una logica del genere con NGINX vanilla pu\u00f2 essere piuttosto complicato. Iniziamo facendo una richiesta al primo server, vediamo se l\u00ec c'\u00e8 una foto, perch\u00e9 potenzialmente potrebbe essere caricata, ad esempio, sul vicino e non essere ancora arrivata qui. Se la foto \u00e8 l\u00ec, \u00e8 un buon segno. La diamo immediatamente al cliente e, possibilmente, la memorizziamo in cache.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/de5f77e997bb049f4cfc1709da0f1788.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe non c'\u00e8, facciamo semplicemente una richiesta al vicino e da l\u00ec la otteniamo garantita.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/79aa5592acd28dfbc815261d0276c2e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCos\u00ec possiamo dire ancora una volta: potrebbero esserci problemi con le prestazioni, perch\u00e9 i continui round trip \u2014 la foto \u00e8 stata caricata, qui non c'\u00e8, facciamo due richieste anzich\u00e9 una, dovrebbe funzionare lentamente.<\/p>\n<p>Nella nostra situazione non funziona lentamente.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/52ca3902d80990f512201672cd5e6441.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nRaccogliamo una quantit\u00e0 di metriche su questo sistema, e il tasso di hit di questo meccanismo \u00e8 di circa il 95%. Cio\u00e8, il ritardo di questo backup \u00e8 minimo, e grazie a ci\u00f2 otteniamo praticamente garantito, dopo che la foto \u00e8 stata caricata, di riceverla al primo colpo e non dobbiamo fare due viaggi.<\/p>\n<p>Cos'altro abbiamo ottenuto e che \u00e8 davvero fantastico?<\/p>\n<p>In passato avevamo un'area di backup principale e leggevamo sequenzialmente da esse. Cio\u00e8, cercavamo sempre prima nel principale e poi nel backup. Era un solo passaggio.<\/p>\n<p>Ora utilizziamo la lettura da due macchine contemporaneamente. Distribuiamo le richieste in Round Robin. In una piccola percentuale di casi facciamo due richieste. Ma in generale ora abbiamo il doppio della capacit\u00e0 di lettura rispetto a prima. E il carico \u00e8 decisamente diminuito sia sulle macchine di erogazione sia sugli storage, che a quel tempo avevamo.<\/p>\n<p>Per quanto riguarda la tolleranza ai guasti. In effetti, su questo ci siamo concentrati principalmente. La tolleranza ai guasti qui \u00e8 risultata fantastica.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/a030a477e60d6e1f3d0b4e3395013df5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUna macchina smette di funzionare.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/42900b24e340c03ea642fd49f5b410ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNessun problema! L'ingegnere di sistema pu\u00f2 anche non svegliarsi di notte, pu\u00f2 aspettare fino al mattino, non ci sar\u00e0 nulla di grave.<\/p>\n<p>Se anche con il guasto di questa macchina la coda smette di funzionare, nessun problema, basta che il log si accumuli prima sulla macchina funzionante, e poi raggiunga la coda, e poi sulla macchina che sar\u00e0 riattivata dopo un po'.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/ef42eadaaf3e3ecbf70847e9f88c1582.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa stessa cosa vale per la manutenzione. Spegniamo semplicemente una delle macchine, la estraiamo manualmente da tutti i pool, smette di ricevere traffico, facciamo una sorta di manutenzione, sistemiamo qualcosa, dopo di che la rimettiamo in funzione, e il backup si recupera abbastanza rapidamente. Cio\u00e8, in un giorno di inattivit\u00e0 di una macchina, si recupera nell'ordine di pochi minuti. \u00c8 davvero molto poco. Con l'affidabilit\u00e0, ripeto, qui siamo a posto.<\/p>\n<p>Quali conclusioni possiamo trarre da questo schema di riserva?<\/p>\n<p>Abbiamo ottenuto l'affidabilit\u00e0.<\/p>\n<p>Semplice utilizzo. Poich\u00e9 le macchine hanno dischi rigidi locali, \u00e8 molto pi\u00f9 comodo dal punto di vista operativo per gli ingegneri che ci lavorano.<\/p>\n<p>Abbiamo ottenuto una doppia capacit\u00e0 di lettura.<\/p>\n<p>\u00c8 un ottimo bonus in aggiunta all'affidabilit\u00e0.<\/p>\n<p>Ma ci sono anche dei problemi. Ora abbiamo uno sviluppo di alcune funzionalit\u00e0 molto pi\u00f9 complesso legato a questo, perch\u00e9 il sistema \u00e8 diventato 100% eventual consistency.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/b650276a41730cc303180e8304c5dabb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDobbiamo, diciamo, in qualche job di background pensare costantemente: \u00abSu quale server siamo attualmente attivi?\u00bb, \u00abC'\u00e8 davvero qui l'immagine attuale?\u00bb ecc. Naturalmente, tutto questo \u00e8 ben incapsulato, e per il programmatore che scrive la logica di business \u00e8 trasparente. Tuttavia, \u00e8 emerso uno strato molto complesso. Ma siamo disposti a tollerarlo in cambio dei vantaggi che abbiamo ottenuto.<\/p>\n<p>E qui sorge nuovamente un certo conflitto.<\/p>\n<p>All'inizio dicevo che conservare tutto su dischi rigidi locali \u00e8 sbagliato. E ora dico che ci \u00e8 piaciuto.<\/p>\n<p>S\u00ec, in effetti, con il passare del tempo la situazione \u00e8 cambiata notevolmente, e ora questo approccio ha molti vantaggi. Prima di tutto, otteniamo un utilizzo decisamente pi\u00f9 semplice.<\/p>\n<p>In secondo luogo, \u00e8 pi\u00f9 efficiente, perch\u00e9 non abbiamo quegli automatic controllers, le connessioni ai rack di archiviazione.<\/p>\n<p>L\u00ec c'\u00e8 una grande macchina, mentre qui ci sono semplicemente alcuni dischi che sono stati messi in RAID proprio qui sulla macchina.<\/p>\n<p>Ma ci sono anche svantaggi.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/3c090e0801f1a686dc0d5fefce697c56.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c8 circa 1,5 volte pi\u00f9 costoso rispetto all'utilizzo di SAN, anche ai prezzi attuali. Pertanto, abbiamo deciso di non convertire cos\u00ec audacemente tutto il nostro grande cluster in macchine con dischi rigidi locali e abbiamo optato per una soluzione ibrida.<\/p>\n<p>La met\u00e0 delle nostre macchine lavora con dischi rigidi (beh, non met\u00e0, ma circa il 30%, credo). E la parte rimanente \u00e8 composta da vecchie macchine che avevano precedentemente la prima configurazione di backup. Le abbiamo semplicemente rimontate, poich\u00e9 non abbiamo bisogno di dati nuovi o altro, abbiamo solo spostato i mount da un host fisico a due.<\/p>\n<p>E abbiamo ottenuto un grande margine di lettura, e ci siamo espansi. Se prima montavamo un solo storage su una macchina, ora ne montiamo quattro su una coppia, ad esempio. E questo funziona bene.<\/p>\n<p>Diamo una breve sintesi di ci\u00f2 che abbiamo realizzato, per cosa abbiamo lottato e se abbiamo raggiunto i nostri obiettivi.<\/p>\n<h3>Conclusioni<\/h3>\n<p>\nAbbiamo utenti \u2014 ben 33 milioni.<\/p>\n<p>Abbiamo tre punti di presenza \u2014 Praga, Miami, Hong Kong.<\/p>\n<p>In questi punti \u00e8 presente uno strato di caching, che consiste in macchine con dischi locali veloci (SSD), su cui gira un semplice sistema basato su NGINX, il suo access.log e demoni in Python che gestiscono e amministrano il cache.<\/p>\n<p>Se lo desiderate, nel vostro progetto, se per voi le immagini non sono cos\u00ec critiche come per noi, o se il trade-off tra il controllo e la velocit\u00e0 di sviluppo e uso delle risorse pende dall'altra parte, allora potete tranquillamente sostituirlo con un CDN, i moderni CDN lo fanno molto bene.<\/p>\n<p>Successivamente c'\u00e8 lo strato di storage, su cui abbiamo cluster di coppie di macchine che si riservano a vicenda, con file che vengono copiati in modo asincrono da una all'altra in caso di qualsiasi modifica.<\/p>\n<p>Parte di queste macchine lavora con dischi rigidi locali.<\/p>\n<p>Parte di queste macchine sono collegate a SAN.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/5ddbc4f73d86aa1f83734885d8c9dea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDa un lato, \u00e8 pi\u00f9 comodo da gestire e un po' pi\u00f9 performante, dall'altro lato, \u00e8 vantaggioso in termini di densit\u00e0 e prezzo per gigabyte.<\/p>\n<p>Questa \u00e8 una breve panoramica dell'architettura che abbiamo sviluppato e come si \u00e8 evoluta.<\/p>\n<p>Alcuni ulteriori consigli da parte del capo, molto semplici.<\/p>\n<p>In primo luogo, se all'improvviso decidete che avete urgenza di migliorare la vostra infrastruttura di immagini, prima misurate, perch\u00e9, probabilmente, non c'\u00e8 bisogno di miglioramenti.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/7770f41d0b190eb78ae0d19f4c8182a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFaccio un esempio. Abbiamo un cluster di macchine che restituiscono fotografie dagli allegati nelle chat, e l\u00ec funziona ancora lo schema del 2009, e nessuno ne risente. Tutti stanno bene, a tutti piace.<\/p>\n<p>Per misurare, prima appendete un sacco di metriche, date un'occhiata e poi decidete cosa non vi soddisfa e cosa bisogna migliorare. Per fare queste misurazioni, abbiamo uno strumento fantastico chiamato Pinba.<\/p>\n<p>Esso consente di raccogliere statistiche molto dettagliate da NGINX per ogni richiesta e codici di risposta, e distribuzione dei tempi \u2014 tutto ci\u00f2 che desiderate. Ha binding per vari sistemi di analisi, e potete quindi visualizzare tutto in modo chiaro.<\/p>\n<p>Prima misurate \u2014 poi migliorate.<\/p>\n<p>Avanti. Ottimizziamo la lettura con la cache, la scrittura con lo sharding, ma questo \u00e8 un punto ovvio.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f53a4777f1a2c7793eba4a72c94263a4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAvanti. Se state iniziando ora a costruire il vostro sistema, \u00e8 molto meglio trattare le fotografie come file immutabili. Poich\u00e9 cos\u00ec eliminate subito tutta una serie di problemi relativi all'invalidazione della cache, a come la logica deve trovare la versione corretta della fotografia e cos\u00ec via.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/f345c59681275326cda1320b4f188ce9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSupponiamo di aver caricato cento foto, poi avendole ruotate, assicuratevi che si tratti fisicamente di un file diverso. Cio\u00e8, non pensate: ora risparmio un po' di spazio, scrivo nello stesso file, cambio versione. Funziona sempre male, e poi ci si ritrova con molti mal di testa.<\/p>\n<p>Punto successivo. Riguardo al resize al volo.<\/p>\n<p>In passato, quando gli utenti caricavano una fotografia, creavamo subito una serie di dimensioni per ogni evenienza, per diversi clienti, e tutto ci\u00f2 era salvato su disco. Ora abbiamo abbandonato questo approccio.<\/p>\n<p>Abbiamo mantenuto solo tre dimensioni principali: piccola, media e grande. Tutto il resto lo riduciamo dalla dimensione che ci \u00e8 richiesta in Uport, facciamo semplicemente un downscale e restituiamo all'utente.<\/p>\n<p>Il costo della cache della CPU qui risulta molto pi\u00f9 economico rispetto a se generassimo continuamente queste dimensioni su ogni storage. Supponiamo di voler aggiungere una nuova dimensione, ci vorr\u00e0 un mese \u2014 eseguire uno script ovunque che faccia tutto questo senza bloccare il cluster. Cio\u00e8, se c'\u00e8 la possibilit\u00e0 di scegliere ora, \u00e8 meglio creare il minor numero possibile di dimensioni fisiche, ma affinch\u00e9 ci sia almeno una certa distribuzione, diciamo, tre. E tutto il resto semplicemente ridimensionato al volo tramite moduli gi\u00e0 pronti. Adesso \u00e8 tutto molto facile e accessibile.<\/p>\n<p>E il backup incrementale asincrono \u00e8 una buona cosa.<\/p>\n<p>Come ha mostrato la nostra esperienza, uno schema del genere funziona molto bene con la copia differita dei file modificati.<\/p>\n<p><img decoding=\"async\" alt=\"Architettura di archiviazione e restituzione delle fotografie in Badoo\" src=\"\/wp-content\/uploads\/2020\/01\/0e550721e838654e61e1fa4d08f9bb93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL'ultimo punto \u00e8 anche ovvio. Se nella tua infrastruttura non ci sono attualmente problemi simili, ma c'\u00e8 qualcosa che potrebbe rompersi, si romper\u00e0 sicuramente quando ce ne sar\u00e0 un po' di pi\u00f9. Quindi \u00e8 meglio pensarci in anticipo e non affrontare problemi. Per me \u00e8 tutto.<\/p>\n<h3>Contatti<\/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 dell'azienda Badoo<\/a><\/noindex><\/p>\n<blockquote><p>Questa relazione \u00e8 la trascrizione di una delle migliori presentazioni alla conferenza degli sviluppatori di sistemi ad 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>. Manca meno di un mese alla conferenza HighLoad++ 2017.<\/p>\n<p>Abbiamo gi\u00e0 pronto <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2017\/abstracts\">Programma della conferenza<\/a><\/noindex>, ora ci stiamo attivamente organizzando.<\/p>\n<p>Quest'anno continuiamo a esplorare il tema delle architetture e della scalabilit\u00e0:<\/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\">Come servire un miliardo di utenti e gestire terabit di traffico<\/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\">Come riscrivere da zero il database dei messaggi personali di VKontakte e migrarvi senza 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\">La morte da svendita: come Yandex.Money ha tentato di accelerarsi in vista del Black Friday e resistere<\/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\">Architettura a prova di guasto del sistema frontale della banca<\/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\">Architettura del sistema di pagamento: quasi enterprise<\/a><\/noindex> \/ \u0424\u0438\u043b\u0438\u043f\u043f \u0414\u0435\u043b\u044c\u0433\u044f\u0434\u043e<\/li>\n<\/ul>\n<p>\nAlcuni di questi materiali sono utilizzati anche nel nostro corso online di formazione sullo sviluppo di sistemi ad 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> \u00e8 una serie di email, articoli, materiali, video appositamente selezionati. Gi\u00e0 ora nel nostro manuale ci sono oltre 30 materiali unici. Unisciti a noi!\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.1.1 - 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\/it\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Architettura di archiviazione e distribuzione di fotografie in Badoo | ProHoster","description":"Artem Denisov (","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/arhitektura-hraneniya-i-otdachi-fotografij-v-badoo","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/55009","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=55009"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/55009\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=55009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=55009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=55009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}