Appunti di Load Balancing

multiWanSempre più spesso capita di trovarsi in contesti multi-WAN (più di un accesso a Internet) e ci chiediamo come sfruttare al meglio questa condizione. La soluzione maestra, come è facile intuire, si chiama load balancing (bilanciamento del carico). Naturalmente questa tecnica ha diverse varianti, ma tutte sono basate, sostanzialmente, su due aspetti: il livello (layer) e la politica (policy).

Requisiti

Per mettere in atto una soluzione di questo tipo, occorre una certa dotazione hardware il cui costo è inversamente proporzionale alle vostre conoscenze informatiche e direttamente proporzionale alle vostre esigenze.D145-1044-main In sintesi, il più nerd potrebbe cavarsela anche con un vecchio PC e un OS unix-like, mentre l’informatico medio(cre) sarà costretto a scegliere una soluzione più “user-friendly”: una costosa scatoletta di alluminio con una piattaforma embedded e un OS unix-like corredato da una Web-GUI. Tecnicamente sarebbe l’equivalente del vecchio PC, ma in formato ridotto, con led psichedelici e le etichette sui socket RJ45. Un discorso a parte meritano le soluzioni ultra “off-loadizzate” dei monopolisti del settore, ma, essendo appannaggio di poche aziende (costicchiano!), eviterò di parlarne (anche perché, oltre ad essere fisiologicamente ignorante, chiunque necessiti di soluzioni di fascia alta non può certo pretendere di trovare informazioni utili su uno stupido blog!).

Livello e Politica

Come vi ho anticipato, il bilanciamento può essere attuato in mille salse, ma tutte dipendono da 2 ingredienti: il livello, che indica, nella pila di protocolli, dove avviene la divisione del carico e la politica, che stabilisce dei criteri di distribuzione. osimodel7layersInclusi i livelli “fuffa”  (session, presentation) che piacciono tanto agli accademici, l’onnisciente wikipedia ci dice che esistono 7 livelli, ma noi ci accontenteremo del livello 2 (Link layer), del livello 3 (Network layer) e del livello 4 (Transport layer). Per quanto possano essere ottimizzate le politiche, quello che fa veramente la differenza è il livello. Infatti, più agiamo in basso, migliore potrà essere la distribuzione del carico. Ovviamente, la scelta del livello è quasi sempre dettata dal tipo di connettività che abbiamo a disposizione e dalle tecnologie del fornitore di servizi. Tuttavia, a patto di sacrificare un po’ di goodput e di latenza, è possibile, con opportune tecniche di tunnelling e assistiti da un endpoint dedicato, virtualizzare il livello che ci interessa. Però, come vedremo in seguito, non sempre  conviene adottare una soluzione del genere, soprattutto quando ci sono in gioco linee asimmetriche (es. ADSL), dove il traffico di acknowledgement dei protocolli connection-oriented può facilmente saturare l’upstream ed erodere, di conseguenza, il goodput in maniera non trascurabile.

Premesse

BalancingPrima di darsi all’equilibrismo, occorre conoscere alcuni fatti tutt’altro che scontati. Iniziamo col rassegnarci all’idea che il bilanciamento perfetto è una condizione asintotica, pertanto, pur facendo del nostro meglio, dobbiamo prendere atto che una parte della banda non verrà sfruttata a prescindere. Il motivo è semplice: chi ci fornisce connettività,  quasi sicuramente non ci consentirà di agire sul livello 2, quindi dobbiamo accontenarci di dividere il carico ai “piani alti”, con tutta l’inefficienza del caso. Fatta questa premessa, bisogna ricordarsi che anche latenza e throughput delle singole linee, quasi sicuramente differenti, possono influenzare la resa di alcune tecniche di bilanciamento. Senza andare troppo per le lunghe, quello che segue è una descrizione sintentica di 3 strategie di bilanciamento che ho testato in questi ultimi mesi, in condizioni che definirei quasi ideali: 3 banali linee ADSL col medesimo operatore e, ovviamente, di pari caratteristiche. Il tutto può essere facilmente implementato avendo una discreta dimestichezza con iptables e iproute, in particolare, bisogna saper “mark-are” i pacchetti e instradarli correttamente. Le tecniche che vi descriverò, da prendere solo come una buona base di partenza, sono le seguenti:

  • Multipath routing (L3)
  • Bilanciamento per sessione/connessione
  • VPN bonding (L2 over L7)

Multipath routing

Come avete sicuramente intuito, il succo del bilanciamento consiste nel dividere, secondo alcuni criteri (policy), le rotte su più gateway. Esistono vari modi per fare questa divisione, dal grossolano partizionamento statico dell’indirizzamento IPv4 (bilanciamento per destinazione), ai più complessi processi decisionali implementati con iptables o altri strumenti dedicati. Naturalmente, non potendo trattare adeguatamente le innumerevoli soluzioni, vi consiglio di iniziare con un ottima via di mezzo, ovvero col MultiPath routing. La logica di funzionamento è molto semplice: il sistema, avendo a disposizione più percorsi (multipath) per raggiungere una destinazione, ne sceglie uno e lo mantiene per un certo periodo di tempo (fino al timeout del flusso). Questo ci dice 2 cose importanti: la distribuzione non è per-packet (per farlo esisteva la flag equalize), ma è per-flow (flusso TCP/IP); la rotta, prima o poi, “scade” (timeout del flusso => nuova decisione multipath => probabile cambio di gateway), portandosi con sé tutte le sessioni “sensibili” in essere. Quindi, se vogliamo evitare, ad esempio, che una connessione TCP cada al cambio di rotta, è necessario predisporre il sistema affinché tutti i flussi iniziati con un percorso continuino ad usarlo fino alla fine delle sessioni associate. Questa operazione si rende necessaria a causa di un limite dei flussi di livello 3 che, essendo identificati solamente dai campi sorgente, destinazione e protocollo ip, non possono descrivere lo stato delle sessioni TCP/UDP sovrastanti e terminano con un banale timeout. A questo punto entrano in gioco le tecniche di marking di cui parlavo poc’anzi e l’analisi di iptables (netfilter) che ci permette di conoscere lo stato delle sessioni/connessioni associate ai vari flussi. La procedura si può dividere, sostanzialmente, in 2 step:

  • marcare le nuove sessioni dopo il processo decisionale di routing (POSTROUTING)
  • marcare tutti i pacchetti appartenenti ad una sessione prima del routing (PREROUTING)

Naturalmente, affinché i pacchetti siano instradati correttamente, è necessario anche inserire delle opportune regole di routing che tengano conto del marking.  Nell’ambito di iproute, queste regole si basano sul selettore fwmark (firewall mark) che smisterà i pacchetti “marchiati” sulle rispettive tabelle di routing create per l’occasione, una per ogni connessione xDSL. Diamo un occhiata al diagramma al lato e immaginiamo di avere una nuova connessione TCP in uscita. Il primo pacchetto (syn), appartenendo ad una nuova sessione, quindi non ancora  markato,  passerà indenne al restore mark (un meccanismo che marka il pacchetto col medesimo valore con il quale è markata la sessione/connessione) e subirà un processo decisionale di tipo multipath, ovvero il sistema sceglierà uno dei percorsi disponibili (=bilanciamento).  Quando la decisione viene presa e il pacchetto si accinge ad uscire dall’interfaccia relativa, un altro processo (Connmark) markerà la (potenziale) nuova sessione/connessione col valore che abbiamo scelto per quel percorso/interfaccia. Infine, tutti pacchetti successivi appartenenti a quella sessione, questa volta, saranno markati dal restore mark e il seguente processo di routing, trovandosi di fronte a pacchetti markati, sceglierà il percorso indicato dalle regole di fwmark, ignorando il multipath e garantendo, così, che il flusso associato mantenga il medesimo percorso fino alla fine dei tempi (four-way handshake per TCP o time-out), Amen.

Un’ implementazione rapida

Immagino che, dopo tutte queste chiacchiere, vi aspettiate qualche esempio di implementazione da copia-incollare senza troppi complimenti. Ebbene, poiché oggi sono meno pigro del solito,  vi lascerò un paio di righe. Prendiamo il caso banale di 3 adsl identiche. Per prima cosa occorre creare 3 nuove tabelle di routing e, per farlo, possiamo editare il file  /etc/iproute2/rt_tables aggiungendo le nostre tabelle:

#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep
101     adsl1
102     adsl2
103     adsl3

Il prossimo step prevede di inserire le regole di routing:

ip rule add fwmark 0x1 table adsl1
ip rule add fwmark 0x2 table adsl2
ip rule add fwmark 0x3 table adsl3
# via $GW può essere omesso in caso di point-to-point
ip route add table adsl1 default via $GW1 dev ppp1
ip route add table adsl2 default via $GW2 dev ppp2
ip route add table adsl3 default via $GW3 dev ppp3
ip route add default scope global nexthop via $GW1 dev ppp1 weight 1 \
 nexthop via $GW2 dev ppp2 weight 1 nexthop via $GW3 dev ppp3 weight 1

Infine le regole di iptables:

# Assumiamo 172.16.0.0/16 come local net
iptables -t mangle -A PREROUTING -s 172.16.0.0/16 -j CONNMARK --restore-mark
 
# Per il traffico generato localmente (necessita in ogni caso di SNAT/MASQUERADE)
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
 
iptables -t mangle -A POSTROUTING -o ppp1 -m state --state NEW -j CONNMARK --set-mark 0x1
iptables -t mangle -A POSTROUTING -o ppp2 -m state --state NEW -j CONNMARK --set-mark 0x2
iptables -t mangle -A POSTROUTING -o ppp3 -m state --state NEW -j CONNMARK --set-mark 0x3

That’s all, folks! Il masquerading lo lascio a voi..

Bilanciamento per sessione/connessione

Se avete ben compreso il multipath routing, allora potete implementare il bilanciamento per sessione/connessione con poco sforzo. Per quanto le 2 tecniche si assomiglino, quest’ultima ci consente di lavorare a un livello di granularità più fine e, quindi, ci garantisce una distribuzione potenzialmente più equa. [..]

Al momento sono troppo pigro per completare questo articolo, ma prometto di farlo entro 21 Dicembre 2012.

VPN Bonding

Al momento sono troppo pigro per completare questo articolo, ma prometto di farlo entro 21 Dicembre 2012.

3 commenti su “Appunti di Load Balancing
  1. Next scrive:

    …sarei curioso di imparare il bilanciamento per sessione prima della fine del mondo! :-)
    …Ottima guida comunque!

  2. Darkman scrive:

    Abbi fede :)
    Intanto potresti iniziare a leggerti qualcosa sul modulo nth e random di iptables.
    Se hai capito già come si marka, il resto è una passeggiata…

  3. emanuele scrive:

    leggo l’articolo oggi 14 marzo 2015….

    molto interessante.

    io ne essitavo del routing asimmetrico per poter avere un troughput molto alto in upload tramite link aggregation di più connessioni LTE e un download con linea adsl.
    perchè questo?
    perchè le società di telefonia monitorano solo il traffico download e le linee lte sono molto più veloci per poter uplodare filmeti e dati.

    grazie degli spunti che potrai offrirmi.
    emanuele

Lascia un Commento

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *

*

È possibile utilizzare questi tag ed attributi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>