Archivi tag: ha

Load balancer software basato su LVS e Centos 6

Premessa

Oggigiorno esistono diverse soluzioni basate su distribuzioni Linux che consentono di realizzare dei load balancer piuttosto affidabili e performanti. Personalmente ritengo che la scelta dovrebbe ricadere su due software in particolare, ovvero HAProxy oppure LVS (acronimo di Linux Virtual Server).

Nel primo caso abbiamo a che fare con un applicativo che viene eseguito nello spazio utente, con tutte le limitazioni che questo comporta, soprattutto in termini di velocità e di carico computazionale. Esso, inoltre, lavora a livello 7 ISO/OSI (application).

Nel secondo caso, invece, parliamo di un software che viene eseguito a livello del kernel, riducendo significatamente i tempi di risposta e di elaborazione. Inoltre, esso operera a livello 4 (transport) della pila ISO/OSI.

Ovviamente, da buon freak control, ho scelto LVS per realizzare il mio load balancer. Certo, molti di voi obietteranno dicendo che questa tipologia di bilanciatore non ha la stessa affidabilità, le stesse features e la stessa velocità di una soluzione hardware dedicata. La mia risposta è che se non avete intenzione di vendervi un rene per acquistare una macchina che invece di fare N, fa semplicemente N+1 (o + 2, in base alle migliaia di euro in fattura), allora dovrete accontentarvi (si fa per dire) del load balancer software, che per lo meno è più malleabile.

Installazione di LVS

L’installazione di LVS è abbastanza semplice e può essere effettuata mediante yum:

[root@lb1 ~]#  yum groupinstall "Load Balancer"

[root@lb1 ~]#  yum install httpd

[root@lb1 ~]#  chkconfig --level 2345 pulse on
[root@lb1 ~]#  chkconfig --level 2345 piranha-gui on
[root@lb1 ~]#  chkconfig --level 2345 httpd on

In particolare, httpd è il server Web in ascolto sul load balancer (in quanto il mio intento è quello di realizzare un bilanciatore di carico per le richieste HTTP/HTTPS); pulse è il cuore del servizio LVS e si occupa anche della gestione dell’alta affidabilità (HA) mediante l’uso di heartbeat; piranha-gui è un’utile interfaccia grafica (Web based) per la configurazione del nostro Linux Virtual Server.

Una volta installato il pacchetto piranha-gui, occorre impostarne la password di accesso (trattasi di semplice autentica HTTP):

[root@lb1 ~]#  piranha-passwd

Lo username sarà quello di default, ovvero piranha.

A questo punto occorre abilitare il forwarding tra le varie interfacce di rete della macchina Centos adibita a bilanciatore, lanciando semplicemente il comando:

[root@lb1 ~]#  echo 1 > /proc/sys/net/ipv4/ip_forward

Tale comando va inserito anche all’interno del file rc.local, in modo da abilitare il forwarding dopo ogni reboot della macchina.

Infine, avviamo sia il server Web che piranha-gui:

service httpd start
service piranha-gui start

Prima di entrare nel merito della configurazione di LVS è opportuno introdurre un po’ di nozioni teoriche.

Modalità di funzionamento

LVS può operare in 3 diverse modalità (mutuamente esclusive):

1) NAT;

2) Tunneling;

3) Direct routing (DC).

Nel primo caso il load balancer prenderà in carico le richieste provenienti dai client e le girerà ai frontend mediante un semplice NAT. Le risposte dei frontend verranno quindi inoltrate al load balancer stesso che si occuperà di recapitarle ai client. A rigor di logica, tale modalità di funzionamento è certamente la meno performante, in quanto il load balancer rappresenta il classico collo di bottiglia dell’infrastruttura (dato che tutto il traffico bilanciato dovrà necessariamente utilizzare LVS come crocevia).

Nel secondo caso non viene utilizzato il NAT ma un tunnel ipip creato ad hoc per incapsulare le richieste dei client prese in carico dal load balancer e successivamente inoltrarle ai frontend. In questo caso le risposte verranno instratade ai client direttamente dai frontend, senza passare necessariamente dal director (ovvero la macchina che effettua il bilanciamento nella terminologia LVS).Inoltre, a differenza della modalità NAT, affichè l’infrastruttura possa funzionare correttamente è necessario configurare appositamente anche i frontend.

Infine, la terza modalità (che tratterò nell’ambito di questo post) può essere utilizzata nel caso in cui il director ed i frontend (real server per LVS), si trovino nella stessa subnet. Anche in questo caso i frontend vanno configurati appositamente.

In definitiva, la prima modalità richiede un minor numero di configurazioni a discapito di performance ottimizzate; la seconda e la terza modalità, invece, consentono di superare il problema del collo di bottiglia, ma richiedono alcune variazioni nella configurazione dei frontend.

Modalità di bilanciamento

Le modalità di bilanciamento messe a disposizione da LVS sono molteplici. Senza scendere troppo nel dettaglio, le due che secondo me meritano maggiore attenzione sono le seguenti:

1) round robin (classica o nella variante weighted);

2) least connection (anch’essa disponibile nella forma classica o nella variante weighted).

Nel primo caso le richieste vengono inoltrate ai frontend seguendo l’algoritmo round robin (vedi qui per ulteriori dettagli). Nel caso in cui i frontend non siano tutti dotati della medesima capacità di calcolo e risorse hardware, è possibile assegnare loro un peso specifico che li contraddistinguerà. In questo caso, scegliendo la weighted round robin sarà possibile inoltrare una mole di richieste maggiore ai server più corazzati, riservando un carico inferiore a quelli meno performanti.

Per quanto riguarda, invece, la least connection, un client che instaura la connessione con un frontend continuerà ad essere servito da quel frontend (fino ad un eventuale connection timeout). La modalità weighted tiene conto del peso assegnato a ciascun frontend, ovvero valgono i medesimi ragionamenti fatti per la weighted round robin.

Configurazione di LVS

Lo schema riportato di seguito mostra l’infrastruttura creata per il bilanciamento del traffico HTTP/HTTPS.

 

netschema.PNG

Come si può notare, esistono 2 director configurati in HA (active/standby) e 2 real server, identici dal punto di vista hardware e software.

Colleghiamoci alla GUI installata in precedenza attraverso la seguente URL:

http://ipdirector:3636

dove, banalmente, ipdirector è l’indirizzo IP del server che funge da director e 3636 (TCP) è la porta su cui è in ascolto piranha-gui.

Cliccando sul tab VIRTUAL SERVERS e successivamente sul tasto ADD possiamo creare un nuovo bilanciatore (come riportato nello screenshot sottostante):

 

screen1.PNG

Cliccando sul radio button presente alla nostra sinistra selezioniamo il virtual server appena creato. A questo punto sarà sufficiente cliccare su EDIT per definirne i parametri di configurazione:

screen2.PNG

Oltre al nome del virtual server (lb_cluster), abbiamo configurato la TCP 80 come application port (HTTP), abbiamo scelto il virtual IP (10.2.66.13) a cui dovrà rispondere il load balancer ed abbiamo scelto l’interfaccia virtuale (eth0:1) su cui mettere in bind l’IP in questione (appartenente ad una classe privata, appositamente “nattato” in IP pubblico da un firewall che gestisce le connessioni in ingresso alla LAN). Da notare che alla voce quiesce server il radio button è posizionato su Yes. In questo modo, nel caso in cui venisse aggiunto un nuovo real server, la tabella di bilanciamento presente sul director verrebbe resettata e la nuova macchina verrà coinvolta immediatamente nelle operazioni di smistamento delle richieste.

Adesso cliccliamo su REAL SERVER, su ADD e dopo aver selezionato la nuova entry, clicchiamo su EDIT.

La pagina di configurazione dei real server sarà simile alla seguente:

screen3.PNG

Questa, invece, è l’overview dei real server configurati:

screen4.PNG

Selezioniamo ciascuno di essi e clicchiamo su (DE)ACTIVATE.

Torniamo alla schermata dei virtual server, selezioniamo quello appena creato ed anche in questo caso clicchiamo su (DE)ACTIVATE.

Ora sarà possibile creare un virtual server anche per le richieste HTTPS. E’ sufficiente ricopiare la configurazione utilizzata per l’HTTP, eccezion fatta per i seguenti parametri:

1) Apllication port, che deve essere la 443.

2) Persistence, settata a 320 (ovvero il timeout in secondi della connessione inizializzata dal client).

Quest’ultima è necessaria per il buon funzionamento del protocollo HTTPS, in quanto una sessione di questo tipo deve essere gestita da un solo server per volta (rispettando il principio di autenticazione della fonte e la logica su cui si basa SSL/TLS).

Anche in questo caso cliccando su DE(ACTIVATE) renderemo attivo il bilanciamento per il protocollo in questione.

Occorre, inoltre, fare una precisazione: nel caso in cui il director debba gestire anche le connessioni HTTPS, è necessario installare su di esso (ed anche sui real server), il modulo mod_ssl di Apache:

[root@lb1 ~]# yum install mod_ssl

e successivamente restartare httpd:

[root@lb1 ~]# service httpd restart

in modo che rimanga in ascolto sulla porta 443.

La corretta installazione e configurazione dei certificati sui real server esula dallo scopo del presente post.

Configurazione del cluster (HA)

Anche la configurazione del cluster active/standby (per evitare il famigerato single point of failure) può essere portata a termine mediante piranha-gui.

Nello specifico, è sufficiente cliccare sul tab REDUNDANCY ed impostare l’IP reale del director di backup:

screen5.PNG

Alla fine della fiera, il file di configurazione di LVS presente sul nodo attivo dovrà essere simile al seguente:

[root@lb1 ~]# cat /etc/sysconfig/ha/lvs.cf

serial_no = 77
primary = 10.2.66.11
service = lvs
backup_active = 1
backup = 10.2.66.12
heartbeat = 1
heartbeat_port = 539
keepalive = 6
deadtime = 10
network = direct
debug_level = NONE
monitor_links = 1
syncdaemon = 0
virtual lb_cluster {
     active = 1
     address = 10.2.66.13 eth0:1
     vip_nmask = 255.255.255.255
     port = 80
     send = "GET / HTTP/1.0rnrn"
     expect = "HTTP"
     use_regex = 0
     load_monitor = none
     scheduler = lc
     protocol = tcp
     timeout = 6
     reentry = 15
     quiesce_server = 1
     server vmtest6 {
         address = 10.2.66.7
         active = 1
         weight = 1
     }
     server vmtest7 {
         address = 10.2.66.9
         active = 1
         weight = 1
     }
}
virtual lb_cluster_https {
     active = 1
     address = 10.2.66.13 eth0:1
     vip_nmask = 255.255.255.255
     port = 443
     persistent = 320
     use_regex = 0
     load_monitor = none
     scheduler = lc
     protocol = tcp
     timeout = 6
     reentry = 15
     quiesce_server = 1
     server vmtest6 {
         address = 10.2.66.7
         active = 1
         weight = 1
     }
     server vmtest7 {
         address = 10.2.66.9
         active = 1
         weight = 1
     }
}


Come potete notare, per quanto riguarda il virtual server dedicato alle richeste HTTPS, non sono presenti meccanismi di controllo (identificati dai parametri send ed expect), in quanto non sono pienamente supportati da LVS e la loro presenza potrebbe inficiare il funzionamento del bilanciatore per il tipo di richieste in questione.

Ora copiamo la suddetta configurazione sul server di backup mediante SCP:

[root@lb1 ~]#  scp /etc/sysconfig/ha/lvs.cf root@10.2.66.12:/etc/sysconfig/ha/lvs.cf

A configurazione dei nodi ultimata, possiamo avviare pulse:

[root@lb1 ~]# service pulse start

Controlliamo che il servizio sia effettivamente funzionante e che i real server siano stati attivati correttamente:

[root@lb1 ~]# watch ipvsadm

il cui output dovrebbe essere simile al seguente:

Every 2.0s: ipvsadm                                                                                 Mon Oct 21 11:32:53 2013

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.2.66.13:http lc
-> 10.2.66.7:http               Route   1      0          0
-> 10.2.66.9:http               Route   1      0          0
TCP  10.2.66.13:https lc persistent 320
-> 10.2.66.7:https              Route   1      0          0
-> 10.2.66.9:https              Route   1      0          0

Configurazione dei real server ed il problema delle richieste ARP

Come accennato in precedenza, la modalità Direct Connect prevede un minimo di configurazione anche sui frontend Web. Quindi, fin quando la loro configurazione non verrà ultimata, il bilanciatore non potrà funzionare.

Nello specifico, occorre mettere in bind l’IP dei due virtual server sui frontend, assegnandolo, anche in questo caso, ad un’interfaccia virtuale (eth0:1).

Lanciamo dunque il comando:

ifconfig eth0:1 10.2.66.13 netmask 255.255.255.255 up

ed inseriamo la suddetta stringa all’interno del file /etc/rc.local per rendere attiva l’interfaccia ache dopo un eventual reboot della macchina.

Con il comando:

[root@lb1 ~]# ifconfig

verifichiamo che l’interfaccia virtuale sia effettivamente attiva. L’output dovrà essere simile al seguente:

eth0:1    Link encap:Ethernet  HWaddr 00:0C:29:14:C7:79
           inet addr:10.2.66.13  Bcast:10.2.66.13  Mask:255.255.255.255
           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

Una volta configurata l’interfaccia virtuale occorre risolvere il problema delle richieste ARP. Infatti, poichè sia il director che i due real server rispondono al medesimo indirizzo IP virtuale, nel caso in cui venisse fatta una richiesta da un client, la riposta potrebbe provenire direttamente da uno dei due frontend, senza passare per il director. Tale comportamento è dovuto al fatto che, in una LAN, ogniqualvolta si cerca di contattare un indirizzo IP, viene inoltrata una richiesta ARP (in broadcast) richiedendo l’indirizzo MAC dell’interfaccia a cui quell’indirizzo è stato assegnato. Ovviamente, a tale richiesta potrebbe seguire la risposta di uno dei due frontend o del director, in modo totalmente randomico, inficiando il corretto funzionamento del load balancer stesso.

Per evitare ciò si può installare arptables_jf, una sorta di firewall di livello 2, in modo da bloccare le richieste ARP provenienti dai client:

[root@lb1 ~]# yum install arptables_jf

Una volta installato è necessario configurarlo nel seguente modo:

[root@lb1 ~]# arptables -A IN -d 10.2.66.13 -j DROP
[root@lb1 ~]# arptables -A OUT -s 10.2.66.13 -j mangle --mangle-ip-s 10.2.66.7

La prima entry blocca le richieste ARP in ingresso al real server, contenenti l’indirizzo IP virtuale; la seconda entry, invece, consente di rispondere alla richieste ARP con l’IP reale del frontend (10.2.66.7).

Salviamo la configurazione di arptables lanciando il comando:

[root@lb1 ~]# service arptables_jf save

e successivamente avviamo il servizio:

[root@lb1 ~]# service arptables_jf start

Facciamo anche in modo che il suddetto servizio venga avviato automaticamente ad ogni boot del sistema:

[root@lb1 ~]# chkconfig --levels 2345 arptables_jf on

Per verificare che tutto stia funzionando correttamente spegnamo momentaneamente l’interfaccia virtuale eth0:1 sul director e proviamo a pingare l’IP assegnatogli:

[root@lb1 ~]# ifdown eth0:1

[root@lb1 ~]# ping 10.2.66.13

se al ping non seguirà nessuna reply allora arptables sta funzionando come dovrebbe.

Test di funzionamento per il bilanciamento del traffico HTTP/HTTPS

Un test banale per appurare che il load balancer funziona bene consiste nel creare due pagine Web leggermente differenti tra di loro (ad esempio nel tag <title> oppure nel <body>). Una di queste pagine dovrà essere caricata sul frontend 1 e l’altra sul frontend 2.

Facendo delle richieste all’indirizzo IP pubblico del director (ad esempio 37.88.91.154), a cui corrisponde l’IP locale e virtuale 10.2.66.13, dovremmo essere reindirizzati ad uno o all’altro frontend.

Stessa prova può essere fatta per testare il protocollo HTTPS, facendo attenzione che il timeout impostato per la persistenza delle sessioni venga rispettato.

Test di funzionamento per il cluster active/standby

Per testare il funzionamento del cluster è sufficiente stoppare il servizio pulse sul nodo attivo (per intenderci, quello su cui abbiamo lanciato il comando watch ipvsadm).

Lanciando il suddetto comando sul nodo di backup dovremmo riconoscere lo stesso output visto in precedenza sull’ex nodo attivo.

Test di carico

Per i test di carico vi rimando a questo post.

Fine della guida.

Alla prossima.