La chiave per ridimensionare un livello di bilanciamento del carico HTTP è aggiungere prima un altro livello di bilanciamento del carico di livello inferiore (IP o TCP). Questo livello può essere costruito interamente con software open source, sebbene otterrai risultati migliori se disponi di router moderni.
I flussi (sessioni TCP) devono essere sottoposti a hash usando intestazioni come porte IP e TCP di origine / destinazione, per decidere a quale frontend vanno. È inoltre necessario un meccanismo per assicurarsi che quando un frontend muore, smette di abituarsi.
Esistono varie strategie, ho intenzione di delineare un paio che ho usato in produzione su siti che servono milioni di utenti, in modo da poter avere l'idea. Sarebbe troppo lungo per spiegare tutto nei dettagli, ma spero che questa risposta ti dia abbastanza informazioni / indicazioni per iniziare. Per implementare queste soluzioni avrai bisogno di qualcuno che sia veramente ben informato sulla rete.
È vero che ciò che sto descrivendo qui è molto più difficile da implementare rispetto a quanto descritto in altre risposte, ma questo è davvero lo stato dell'arte se si dispone di un sito Web a traffico elevato con grandi problemi di scalabilità e requisiti di disponibilità superiori al 99,9% . A condizione che tu abbia già un ingegnere di rete un po 'a bordo, costa meno per l'installazione e l'esecuzione (sia in capex che in opex) rispetto agli apparecchi di bilanciamento del carico e può essere ulteriormente ridimensionato senza costi aggiuntivi (rispetto all'acquisto di un nuovo, ancora di più apparecchio costoso quando si supera il modello attuale).
Prima strategia: con un firewall
Presumibilmente hai un paio di router su cui sono collegati i tuoi uplink ISP. L'ISP fornisce 2 collegamenti (attivo / passivo, utilizzando VRRP). Sui router, usi anche VRRP e instrada il traffico diretto alla tua rete pubblica verso un firewall. Anche i firewall ( FW 1
e FW 2
inferiori) sono attivi / passivi e filtrano il traffico e inviano ciascun flusso a un server frontend integro (i bilanciatori del carico HTTP FE 1
e FE 2
inferiori).
+ -------------- + + -------------- +
| Router ISP A | | Router ISP B |
+ -------------- + + -------------- +
| |
== # ====================== # == (rete pubblica)
| |
+ --------------- + + --------------- +
| Il tuo router A | | Il tuo router B |
+ --------------- + + --------------- +
| |
== # ===== # ========== # ===== # == (rete privata RFC 1918)
| | | |
+ ------ + + ------ + + ------ + + ------ +
| AI 1 | | FE 1 | | FE 2 | | AI 2 |
+ ------ + + ------ + + ------ + + ------ +
L'obiettivo è avere un flusso simile al seguente:
- L'ISP indirizza il traffico diretto ai tuoi IP verso il tuo router attivo.
- I router indirizzano il traffico a un VIP che utilizza un indirizzo RFC 1918 . Questo VIP è di proprietà del firewall attivo, proprio come VRRP. Se usi OpenBSD per le tue esigenze di firewall, puoi usare CARP , un'alternativa senza brevetti a VRRP / HSRP.
- Il tuo firewall applica il filtro (es. "Consenti solo 80 / tcp e 443 / tcp andando a questo particolare indirizzo IP").
- Il firewall funge anche da router e inoltra i pacchetti a un frontend sano.
- Il frontend termina la connessione TCP.
Ora la magia avviene nei passaggi 4 e 5, quindi vediamo più in dettaglio cosa fanno.
Il tuo firewall conosce l'elenco dei frontend ( FE 1
e FE 2
) e ne sceglierà uno in base a un aspetto particolare del flusso (ad es. Eseguendo l'hashing dell'IP e della porta di origine, tra le altre intestazioni). Ma deve anche assicurarsi che inoltri il traffico a un frontend sano, altrimenti si creerà un blackhole. Se usi OpenBSD, ad esempio, puoi usare relayd
. Che cosarelayd
fa è semplice: controlla l'integrità di tutti i tuoi frontend (ad esempio inviando loro una richiesta HTTP probe) e ogni volta che un frontend è integro lo aggiunge a una tabella che il firewall utilizza per selezionare l'hop successivo dei pacchetti di un determinato flusso . Se un frontend non supera i controlli di integrità, viene rimosso dalla tabella e non viene più inviato alcun pacchetto. Quando si inoltra un pacchetto a un frontend, tutto il firewall non fa altro che scambiare l'indirizzo MAC di destinazione del pacchetto con quello del frontend scelto.
Nel passaggio 5, i pacchetti dell'utente vengono ricevuti dal bilanciamento del carico (che si tratti di vernice, nginx o altro). A questo punto, il pacchetto è ancora destinato al tuo indirizzo IP pubblico, quindi devi alias i tuoi VIP sull'interfaccia di loopback. Questo si chiama DSR (Direct Server Return), perché i front-end terminano la connessione TCP e il firewall in mezzo vede solo il traffico simplex (solo pacchetti in entrata). Il router instraderà i pacchetti in uscita direttamente ai router dell'ISP. Ciò è particolarmente utile per il traffico HTTP perché le richieste tendono ad essere più piccole delle risposte, a volte in modo significativo. Giusto per essere chiari: questa non è una cosa specifica di OpenBSD ed è ampiamente usata nei siti Web ad alto traffico.
grattacapi:
- Gli utenti finali si collegheranno direttamente ai server frontend perché si utilizza DSR. Forse era già il caso, ma in caso contrario, è necessario assicurarsi che siano adeguatamente protetti.
- Se usi OpenBSD, fai attenzione che il kernel è a thread singolo, quindi le prestazioni di un singolo core della CPU limiteranno il throughput di un firewall. Potrebbe essere un problema a seconda del tipo di scheda NIC e della frequenza dei pacchetti che stai vedendo. Esistono modi per risolvere questo problema (ulteriori informazioni qui di seguito).
Seconda strategia: senza firewall
Questa strategia è più efficiente ma più difficile da configurare perché dipende più dalle specifiche dei router che hai. L'idea è di bypassare il firewall sopra e far eseguire ai router tutto il lavoro svolto dai firewall.
Avrai bisogno di router che supportino ACL L3 / L4 per porta, BGP ed ECMP e Policy Based Routing (PBR). Solo i router di fascia alta supportano queste funzionalità e spesso hanno costi di licenza aggiuntivi per utilizzare BGP. Questo è in genere ancora più economico dei sistemi di bilanciamento del carico hardware ed è anche molto più facile da scalare. La cosa positiva di questi router di fascia alta è che tendono ad essere a velocità di linea (ad esempio, possono sempre massimizzare il collegamento, anche su interfacce 10GbE, perché tutte le decisioni che prendono vengono prese in hardware dagli ASIC).
Sulle porte su cui hai i tuoi uplink ISP, applica l'ACL che era sul firewall (ad esempio "consenti solo a 80 / tcp e 443 / tcp di andare a questo particolare indirizzo IP"). Quindi fai in modo che ognuno dei tuoi frontend mantenga una sessione BGP con il tuo router. Puoi usare l'eccellente OpenBGPD (se i tuoi frontend sono su OpenBSD) o Quagga . Il tuo router ECMP il traffico verso i front-end che sono sani (perché mantengono le loro sessioni BGP). Il router indirizzerà inoltre il traffico in modo appropriato utilizzando PBR.
perfezionamenti
- Con la soluzione di accoppiamento firewall, è bello poter sincronizzare gli stati TCP tra i firewall, in modo che quando un firewall si guasta, tutto si interrompe senza problemi con l'altro. Puoi farlo con
pfsync
.
- Tieni presente che
pfsync
in genere raddoppierà la velocità dei pacchetti sui tuoi firewall.
- HTTP è un protocollo senza stato, quindi non è la fine del mondo se si ripristinano tutte le connessioni durante un failover del firewall perché non si utilizza
pfsync
.
- Se si supera un singolo firewall, è possibile utilizzare ECMP sul router per indirizzare il traffico a più di una coppia di firewall.
- Se usi più di una coppia di firewall, potresti anche renderli tutti attivi / attivi. È possibile ottenere ciò facendo in modo che i firewall mantengano una sessione BGP con i router, proprio come i frontend devono mantenerne uno nel 2o progetto senza firewall.
relayd
Config. Campione
Vedi anche HOWTO su https://calomel.org/relayd.html
vip = "1.2.3.4" # Il tuo indirizzo IP pubblico
# (puoi averne più di uno, ma non è necessario)
fe1 = "10.1.2.101"
Fe2 = "10.1.2.102"
Fe3 = "10.1.2.103"
fe4 = "10.1.2.104" # Puoi avere un numero qualsiasi di frontend.
int_if = "em0"
tabella <fe> {$ fe1 riprovare 2, $ fe2 riprovare 2, $ fe3 riprovare 2, $ fe4 riprovare 2}
tabella <fallback> {127.0.0.1}
reindirizzare webtraffic {
ascolta su $ vip port 80
timeout della sessione 60
percorso a <fe> controlla http "/healthcheck.html" digest "(il sha1sum di healthcheck.html)" interfaccia $ int_if
}