
Il mondo non si ferma. Il progresso crea nuove sfide tecnologiche. In linea con le esigenze mutate, anche l'architettura dei sistemi informativi deve evolversi. Oggi parleremo di architettura orientata agli eventi, concorrenza, parallelismo, asincronicità e di come si possa convivere con tutto questo in Erlang.
Introduzione
A seconda delle dimensioni del sistema progettato e dei requisiti associati, noi sviluppatori scegliamo il metodo di scambio delle informazioni. Nella maggior parte dei casi, per organizzare l'interazione tra i servizi, una soluzione praticabile potrebbe essere l'adozione di uno schema con un broker, ad esempio basato su RabbitMQ o kafka. Tuttavia, a volte il flusso degli eventi, i SLA e il livello di controllo del sistema sono tali che una soluzione di messaging pronta non è adeguata. Certamente, si può complicare un po' il sistema assumendosi la responsabilità del livello di trasporto e della formazione del cluster, ad esempio utilizzando ZeroMQ o nanomsg. Ma se il sistema può gestire le capacità e le funzionalità del cluster standard di Erlang, allora la questione dell'inserimento di un'entità supplementare richiede un'analisi dettagliata e una giustificazione economica.
Il tema delle applicazioni reattive distribuite è piuttosto vasto. Per rimanere nel formato di questo articolo, oggi discuteremo solo degli ambienti omogenei basati su Erlang/Elixir. L'ecosistema Erlang/OTP consente di implementare un'architettura reattiva con il minimo sforzo. In ogni caso, avremo bisogno di uno strato di scambio di messaggi.
Fondamenta teoriche
La progettazione inizia con la definizione di obiettivi e vincoli. L'obiettivo principale non è quello di sviluppare per il gusto di farlo. Dobbiamo ottenere uno strumento sicuro e scalabile su cui costruire, e soprattutto, sviluppare applicazioni moderne di vari livelli: partendo da singoli server che servono un pubblico ristretto, che in seguito possono evolversi in cluster fino a 50-60 nodi, fino a federazioni di cluster. Pertanto, l'obiettivo principale è massimizzare i profitti riducendo i costi di sviluppo e possesso del sistema finale.
Identifichiamo 4 requisiti principali per il sistema finale:
- Corientamento agli eventi.
Il sistema è sempre pronto a gestire flussi di eventi e a compiere le azioni necessarie; - Mscalabilità.
I singoli blocchi possono scalare sia verticalmente che orizzontalmente. L'intero sistema dovrebbe essere in grado di crescere orizzontalmente in modo infinito; - maggiore numero di partizioni.tolleranza ai guasti.
Tutti i livelli e tutti i servizi devono essere in grado di riprendersi automaticamente in caso di guasti; - Garantito tempo di risposta.
Il tempo è prezioso e gli utenti non devono aspettare troppo a lungo.
Ricorda la vecchia favola su “The little engine that could”, il “Trenino che poteva”? Affinché il sistema progettato passi con successo dalla fase di prototipo e diventi progressivo, le sue fondamenta devono soddisfare i requisiti minimi. POTUTO.
A messaging come strumento di infrastruttura e base per tutti i servizi si aggiunge un ulteriore punto: l'usabilità per i programmatori.
Orientamento agli eventi
Per consentire all'applicazione di crescere da una sola server Per il cluster, la sua architettura deve garantire un basso accoppiamento. Questo requisito è soddisfatto dal modello asincrono, in cui il mittente e il destinatario si prendono cura del carico informativo del messaggio senza preoccuparsi della trasmissione e del routing all'interno del sistema.
Scalabilità
La scalabilità e l'efficienza del sistema vanno di pari passo. I componenti dell'applicazione devono saper sfruttare tutte le risorse disponibili. Più efficientemente possiamo utilizzare le capacità e più ottimali sono i nostri metodi di elaborazione, minori saranno le spese per l'attrezzatura.
All'interno di una singola macchina, Erlang crea un ambiente altamente concorrente. Il bilanciamento tra concorrenza e parallelismo può essere impostato scegliendo il numero di thread del sistema operativo disponibili per l'Erlang VM e il numero di scheduler che utilizzano questi thread.
I processi Erlang non hanno stato condiviso e funzionano in modalità non bloccante. Questo consente una latenza relativamente bassa e una maggiore larghezza di banda rispetto alle tradizionali applicazioni basate su sincronizzazione bloccante. Il pianificatore Erlang si occupa di una distribuzione equa delle risorse CPU e IO, e l'assenza di blocchi consente all'applicazione di rispondere anche durante i picchi di carico o in caso di guasti.
A livello di cluster, esiste anche un problema di utilizzo. È importante che tutte le macchine nel cluster siano caricate uniformemente e che la rete non sia sovraccarica. Immaginiamo una situazione: il traffico utente arriva ai bilanciatori di carico (haproxy, nginx, ecc.), che distribuiscono uniformemente le richieste per l'elaborazione tra un set di backend disponibili. Nell'infrastruttura dell'applicazione, il servizio che implementa l'interfaccia richiesta è solo l'ultima miglio e dovrà richiedere una serie di altri servizi per rispondere alla richiesta iniziale. Anche le richieste interne richiedono instradamento e bilanciamento.
Per gestire efficacemente i flussi di dati, il messaging deve fornire agli sviluppatori un'interfaccia per gestire la routing e il bilanciamento del carico. In questo modo, gli sviluppatori potranno, utilizzando modelli microservizi (aggregatore, proxy, catena, ramo, ecc.), affrontare sia compiti standard che situazioni rare.
Dal punto di vista aziendale, la scalabilità è uno degli strumenti per la gestione del rischio. L'obiettivo principale è soddisfare le richieste dei clienti, utilizzando in modo ottimale l'hardware:
- Con l'aumento della potenza dell'hardware grazie ai progressi tecnologici, esso non rimarrà inattivo a causa delle imperfezioni del software. Erlang si scala perfettamente in verticale e sarà sempre in grado di sfruttare tutti i core della CPU e la memoria disponibile;
- Nelle ambienti cloud, possiamo gestire la quantità di hardware in base al carico attuale o previsto e garantire SLA.
Affidabilità
Consideriamo due assiomi: "I guasti sono inaccettabili" e "I guasti accadranno sempre". Per un'azienda, un guasto software significa perdita di denaro e, peggio ancora, reputazione. Bilanciando tra le possibili perdite e il costo dello sviluppo di software resiliente, è spesso possibile trovare un compromesso.
Nel breve termine, un'architettura progettata per la resilienza consente di risparmiare sull'acquisto di soluzioni di clustering pronte all'uso. Queste sono costose e possono contenere difetti.
Nel lungo termine, un'architettura resiliente ripaga ampiamente i costi sostenuti per la sua implementazione in tutte le fasi dello sviluppo.
La messaggistica all'interno del codice già nelle fasi di sviluppo consente di definire in dettaglio le interazioni tra i componenti del sistema. Questo semplifica la gestione delle risposte e dei guasti, poiché tutti i componenti responsabili gestiscono i malfunzionamenti e il sistema finale sa come ripristinare automaticamente il suo stato normale dopo un guasto per progettazione.
Reattività
Indipendentemente dai guasti, l'applicazione deve rispondere alle richieste e soddisfare SLA. La realtà è che le persone non vogliono aspettare, quindi il business deve adattarsi. Sempre più applicazioni si aspettano un'alta reattività.
Le applicazioni reattive funzionano in modalità quasi in tempo reale. L'Erlang VM opera in modalità di soft real-time. Per alcuni settori, come il trading azionario, la medicina e la gestione di attrezzature industriali, è importante la modalità di hard real-time.
I sistemi reattivi migliorano l'esperienza utente e sono utili per le aziende.
Risultato preliminare
Pianificando questo articolo, volevo condividere l'esperienza di creazione di un broker di messaggi e la costruzione di sistemi complessi su di esso. Tuttavia, la parte teorica e motivazionale è risultata piuttosto ampia.
Nella seconda parte dell'articolo parlerò delle sfide nella realizzazione dei punti di scambio, dei modelli di messaggistica e del loro utilizzo.
Nella terza parte esamineremo le questioni comuni relative all'organizzazione dei servizi, al instradamento e al bilanciamento del carico. Discuteremo l'aspetto pratico della scalabilità e della resilienza dei sistemi.
Fine della prima parte.
Foto .
Fonte: habr.com
