Storicamente, l'industria IT si è divisa in due campi: quelli 'favoriscono' e quelli 'contrario'. Gli argomenti di discussione possono essere i più disparati. Quale sistema operativo è migliore: Win o Linux? Su uno smartphone, Android o iOS? Conservare tutto nel cloud o affidarsi a fredde memorie RAID? I programmatori PHP possono veramente definirsi tali? Queste discussioni a volte assumono un carattere puramente esistenziale e non si basano su nulla di più che su un interesse sportivo.
Con l'arrivo dei container e di tutta questa nostra amata tecnologia con Docker e Kubernetes, sono iniziati anche i dibattiti 'favorire' e 'contrario' sull'uso delle nuove opportunità in vari ambiti del backend. (Pre-annunciamo che, sebbene molto spesso in questa discussione si indichi Kubernetes come orchestratore, la scelta di questo strumento non è fondamentale. Puoi sostituirlo con qualsiasi altro che ritieni più conveniente e familiare.)
E, a prima vista, sembrerebbe un semplice dibattito tra due fazioni della stessa medaglia. È egualmente privo di senso e implacabile, come la eterna opposizione tra Win e Linux, dove persone ragionevoli esistono sicuramente a metà strada. Eppure, nel caso della containerizzazione, le cose non sono così semplici. Solitamente in queste discussioni non ci sono vere e proprie parti giuste, ma nel caso di 'utilizzare' o 'non utilizzare' i container per la memorizzazione dei database, tutto si capovolge. Perché, in un certo senso, sia i sostenitori che gli oppositori di questo approccio hanno il loro ragione.
Lato Luminoso
Riassumere l'argomentazione del Lato Luminoso può essere fatto con una frase: “Ehi, 2k19 è qui fuori!” Suona certamente come populismo, ma se si esamina la situazione in dettaglio, ci sono dei vantaggi. Ed è proprio ciò che ora analizzeremo.
Immagina di avere un grande progetto web. Potrebbe essere stato inizialmente costruito sulla base di un approccio a microservizi, oppure averci raggiunto in modo evolutivo — in realtà questo non è così importante. Hai suddiviso il tuo progetto in singoli microservizi, hai configurato l'orchestrazione, il bilanciamento del carico e la scalabilità. E ora, con buona coscienza, ti godi un mojito in un'amaca durante gli effetti dell'Hubra, invece di dover ripristinare i server caduti. Ma in ogni azione bisogna essere coerenti. Spesso solo l'applicazione — il codice — viene containerizzata. E cosa abbiamo oltre al codice?
Esatto, i dati. Il cuore di ogni progetto sono i suoi dati: possono essere un tipico DBMS — MySQL, Postgre, MongoDB, o archivi utilizzati per la ricerca (ElasticSearch), archivi chiave-valore per la cache — ad esempio, Redis, ecc. Oggi non parleremo delle implementazioni problematiche del backend, quando il database va giù a causa di query male scritte, ma invece discuteremo dell'assicurazione della resilienza del database sotto il carico client. Infatti, quando containerizziamo la nostra applicazione e le permettiamo di scalare liberamente per gestire qualsiasi numero di richieste in arrivo, questo inevitabilmente aumenta anche il carico sul database.
In effetti, il canale per accedere al database e il server su cui è in esecuzione diventano il collo di bottiglia nel nostro magnifico backend containerizzato. Il principale motivo della virtualizzazione dei container è la mobilità e la flessibilità della struttura, che consente di organizzare la distribuzione del carico di picco su tutta l'infrastruttura disponibile nel modo più efficiente. Cioè, se non containerizziamo e non distribuiamo nel cluster tutti gli elementi del sistema, stiamo commettendo un errore molto serio.
È molto più logico clusterizzare non solo l'applicazione, ma anche i servizi responsabili della memorizzazione dei dati. Durante la clusterizzazione e il dispiegamento di server web indipendenti che si distribuiscono il carico tra loro in Kubernetes, stiamo già affrontando il problema della sincronizzazione dei dati — come i commenti ai post, se vogliamo fare un esempio con un media o una piattaforma di blog. In ogni caso, si crea una rappresentazione interna al cluster, anche se virtuale, del database come ExternalService. La questione è che il database non è ancora clusterizzato — i server web distribuiti nel cluster raccolgono informazioni sulle modifiche dal nostro database operativo statico, che gira separatamente.
Sentite l'inganno? Utilizziamo Kubernetes o Swarm per distribuire il carico ed evitare il crollo del principale. il server web., ma non facciamo questo per il database. Ma se il database si guasta, allora non ha senso per tutta la nostra infrastruttura clusterizzata — cosa ci facciamo con pagine web vuote che restituiscono errori di accesso al database?
Ecco perché è necessario clusterizzare non solo i server web, come di solito si fa, ma anche l'infrastruttura del database. Solo in questo modo possiamo garantire una struttura che funzioni a pieno regime ma resti indipendente l'una dall'altra. Anche se metà del nostro backend crolla sotto il carico, la parte restante sopravvive e il sistema di sincronizzazione del database tra cluster e la possibilità di scalare indefinitamente e di distribuire nuovi cluster ci aiuteranno a raggiungere rapidamente la potenza necessaria — a patto che ci siano rack nel data center.
Inoltre, il modello di database distribuito in cluster consente di spostare il database dove è realmente necessario; se parliamo di un servizio globale, ha poco senso avere un cluster web da qualche parte vicino a San Francisco e far passare i pacchetti per accedere al database a Podmoskovye e ritorno.
La containerizzazione del database consente inoltre di costruire tutti gli elementi del sistema su un unico livello di astrazione. Questo, a sua volta, rende possibile la gestione del sistema direttamente dal codice, dai programmatori, senza il bisogno di coinvolgere attivamente gli amministratori. Se i programmatori decidono che è necessario un database separato per un nuovo sottoprogetto — fatto! Hanno scritto un file yaml, lo hanno caricato nel cluster ed è pronto.
Inoltre, la gestione interna diventa di gran lunga più semplice. Diteci, quante volte vi siete tapparvi gli occhi quando un nuovo membro del team ha messo le mani nel database di produzione? Che è l'unico che avete e sta funzionando in questo momento? Certo, siamo tutti adulti e abbiamo da qualche parte un backup fresco, e più in là — dietro al barattolo di cetrioli di nonna e sugli sci vecchi — un altro backup, forse anche su uno storage a freddo, perché un giorno il vostro ufficio ha preso fuoco. Tuttavia, ogni nuovo membro del team con accesso all'infrastruttura di produzione e, naturalmente, al database di produzione è un vero e proprio attacco di ansia per tutti gli altri. Chi conosce quel nuovo arrivato? Potrebbe essere maldestro? Spaventoso, ammettetelo.
La containerizzazione e, fondamentalmente, la topologia fisica distribuita del database del vostro progetto aiutano a evitare momenti di ansia simili. Non vi fidate del nuovo arrivato? Va bene! Creiamo un cluster dedicato per il suo lavoro e lo scolleghiamo dagli altri cluster del database — la sincronizzazione sarà solo tramite push manuale e la rotazione sincronizzata di due chiavi (una per il team leader e l'altra per l'amministratore). E tutti saranno felici.
E ora è arrivato il momento di cambiare prospettiva e diventare contrari alla clusterizzazione del database.
Lato Oscuro
Riflettendo su perché non si dovrebbe containerizzare il database e continuare a farlo girare su un unico server centrale, server, non scenderemo sul piano della retorica degli ortodossi e delle affermazioni come "i nostri antenati usavano i server, e noi faremo lo stesso!" Invece, proviamo a immaginare una situazione in cui la containerizzazione possa realmente portare benefici tangibili.
D'accordo, i progetti che realmente hanno bisogno di un database in un container possono essere conteggiati sulle dita di una mano non particolarmente abile. Nella maggior parte dei casi, persino l'uso di k8s o Docker Swarm è eccessivo — spesso questi strumenti vengono utilizzati a causa dell'hype generale e delle indicazioni "superiori" riguardo a mettere tutto nel cloud e nei container. Beh, perché ora è di moda e così fanno tutti.
In almeno metà dei casi, l'uso di Kubernetes o semplicemente di Docker su un progetto è superfluo. Il problema è che non tutti i team o le aziende di outsourcing assunte per gestire l'infrastruttura del cliente ne sono consapevoli. Peggio ancora, quando i container vengono imposti, poiché ciò rappresenta un certo costo per il cliente.
Si ritiene generalmente che Docker e la mafia di Kubernetes stiano semplicemente accaparrandosi i clienti che esternalizzano queste questioni infrastrutturali. Infatti, per lavorare con i cluster, sono necessari ingegneri capaci e che comprendano l'architettura della soluzione implementata. Abbiamo già descritto il nostro caso con l'uscita di Republic — lì abbiamo addestrato il team del cliente a lavorare con Kubernetes, e tutti sono rimasti soddisfatti. E questo è stato molto positivo. Tuttavia, spesso coloro che implementano k8s prendono in ostaggio l'infrastruttura del cliente — ora solo loro capiscono come funziona tutto, non ci sono specialisti nel cliente.
E ora immaginate che in questo modo non stiamo solo delegando la parte server web a un fornitore esterno, ma anche la gestione del database. Abbiamo detto che il database è il cuore, e perdere il cuore è fatale per qualsiasi organismo vivente. In breve, le prospettive non sono delle migliori. Quindi, invece di affidarci a un Kubernetes iper-moderno, molti progetti dovrebbero semplicemente investire in un piano adeguato su AWS, che risolverebbe tutti i problemi di carico sul loro sito/progetto. Ma AWS non è più in voga, e purtroppo, i vezzi costano più dei soldi, anche nell'IT.
Okay. Forse la clusterizzazione è realmente necessaria per un progetto, ma se con le applicazioni stateless tutto è chiaro, come si può garantire una connettività adeguata per un database clusterizzato?
Se parliamo di una soluzione ingegneristica senza soluzione di continuità, come quella proposta dal passaggio a k8s, la nostra principale preoccupazione è la replica dei dati in un database clusterizzato. Alcuni DBMS sono inizialmente piuttosto favorevoli alla distribuzione dei dati tra le varie istanze. Molti altri, invece, non sono così accoglienti. E spesso, il principale argomento nella scelta di un DBMS per il nostro progetto non è affatto la capacità di replicarsi con costi minimi in termini di risorse e ingegneria. Soprattutto se il progetto non è stato inizialmente concepito come microservizio, ma è semplicemente evoluto in questa direzione.
Credo che non ci sia bisogno di raccontare di quanto siano lenti i dischi di rete. Cioè, non abbiamo realmente la possibilità, se necessario, di ricollegare un'istanza DBMS altrove, dove ci sono, ad esempio, più potenza di calcolo o RAM disponibile. Ci fermeremo molto rapidamente alle prestazioni del sistema di archiviazione virtualizzato. Pertanto, il DBMS deve essere legato al proprio set personale di macchine, che si trovano nelle immediate vicinanze. Oppure bisogna trovare un modo per garantire una sincronizzazione dei dati sufficientemente veloce verso le risorse di backup previste.
Continuando il tema dei file system virtuali: i Docke Volumes, purtroppo, non sono privi di problemi. In generale, per qualcosa come l'archiviazione dati a lungo termine e affidabile, si vorrebbero utilizzare schemi tecnici il più semplice possibile. E aggiungere un nuovo strato di astrazione dal file system del contenitore a quello dell'host principale è già di per sé un rischio. Ma quando compaiono difficoltà nella trasmissione dei dati tra questi strati nel sistema di supporto alla containerizzazione, allora è davvero un disastro. Attualmente, la maggior parte dei problemi noti sembra essere stata risolta. Ma come ben sapete, più il meccanismo è complicato, più è facile che si rompa.
Alla luce di tutte queste 'avventure', è molto più vantaggioso e semplice mantenere il database in un unico posto, e anche se avete bisogno della containerizzazione dell'applicazione, lasciate che essa operi autonomamente e comunichi simultaneamente con un database che verrà letto e scritto solo una volta e in un unico luogo. Questo approccio riduce la probabilità di errori e de-sincronizzazioni al minimo.
A cosa stiamo tentando di arrivare? Al fatto che la containerizzazione del database è appropriata solo dove c'è una reale necessità. Non si può mettere un database di un'app full-stack e farlo funzionare come se aveste una ventina di microservizi — così non funziona. E questo deve essere ben chiaro.
Invece dell'output
Se state aspettando una chiara conclusione su 'virtualizzare o meno il database', vi deluderò: non ci sarà. Perché nella creazione di qualsiasi soluzione infrastrutturale bisogna seguire non le mode e i progressi, ma prima di tutto il buon senso.
Ci sono progetti per i quali i principi e gli strumenti derivanti da Kubernetes si adattano perfettamente, e in tali progetti si ottiene almeno un certo livello di pace nell'area backend. E ci sono progetti che non hanno bisogno di containerizzazione, ma di un'infrastruttura server vera e propria, perché non possono essere riprogettati per un modello cluster di microservizi, altrimenti collasseranno.
Fonte: habr.com
