Ottimizzazione dei parametri di routing IP di Linux - secret_interval e tcp_mem


30

Oggi abbiamo avuto un piccolo problema di failover con una delle nostre macchine virtuali HAProxy. Quando abbiamo scavato, abbiamo trovato questo:

26 gennaio 07:41:45 kernel haproxy2: [226818.070059] __ratelimit: soppressione di 10 callback
26 gennaio 07:41:45 kernel haproxy2: [226818.070064] Memoria socket esaurita
26 gennaio 07:41:47 kernel haproxy2: [226819.560048] Memoria socket esaurita
26 gennaio 07:41:49 kernel haproxy2: [226822.030044] Memoria socket esaurita

Che, secondo questo link , apparentemente ha a che fare con impostazioni predefinite basse per net.ipv4.tcp_mem. Quindi li abbiamo aumentati di 4x rispetto ai loro valori predefiniti (questo è Ubuntu Server, non sono sicuro che il sapore di Linux sia importante):

i valori correnti sono: 45984 61312 91968
i nuovi valori sono: 183936 245248 367872

Successivamente, abbiamo iniziato a vedere un bizzarro messaggio di errore:

26 gennaio 08:18:49 kernel haproxy1: [2291.579726] Instrada la catena hash troppo a lungo!
26 gennaio 08:18:49 kernel haproxy1: [2291.579732] Modifica il tuo intervallo_s Segreto!

Shh .. è un segreto !!

Apparentemente ciò ha a che fare con i /proc/sys/net/ipv4/route/secret_intervalvalori predefiniti a 600 e controlla lo svuotamento periodico della cache del percorso

Il secret_intervalindica al kernel la frequenza di soffiare via tutte le voci percorso hash a prescindere da come nuovo / vecchio sono. Nel nostro ambiente questo è generalmente negativo. La CPU sarà impegnata a ricostruire migliaia di voci al secondo ogni volta che la cache viene cancellata. Tuttavia, abbiamo impostato questo per funzionare una volta al giorno per tenere a bada le perdite di memoria (anche se non ne abbiamo mai avuto uno).

Sebbene siamo felici di ridurlo, sembra strano raccomandare di eliminare l'intera cache di route a intervalli regolari , anziché semplicemente spostare più velocemente i vecchi valori dalla cache di route.

Dopo alcune indagini, abbiamo scoperto /proc/sys/net/ipv4/route/gc_elasticityche sembra essere un'opzione migliore per tenere sotto controllo le dimensioni della tabella di route:

gc_elasticitypuò essere meglio descritto come la profondità media del bucket accettata dal kernel prima che inizi a scadere le voci hash di route. Ciò contribuirà a mantenere il limite superiore delle rotte attive.

Abbiamo regolato l'elasticità da 8 a 4, nella speranza che la cache del percorso si elimini più aggressivamente. La secret_intervalnon si sente corretto per noi. Ma ci sono un sacco di impostazioni ed è poco chiaro quali siano davvero il modo giusto per andare qui.

  • / proc / sys / net / ipv4 / route / gc_elasticity (8)
  • / proc / sys / net / ipv4 / route / gc_interval (60)
  • / proc / sys / net / ipv4 / route / gc_min_interval (0)
  • / proc / sys / net / ipv4 / route / gc_timeout (300)
  • / proc / sys / net / ipv4 / route / secret_interval (600)
  • / proc / sys / net / ipv4 / route / gc_thresh (?)
  • rhash_entries (parametro del kernel, impostazione predefinita sconosciuta?)

Non vogliamo peggiorare il routing di Linux , quindi abbiamo un po 'paura di incasinare alcune di queste impostazioni.

Qualcuno può consigliare quali parametri di routing sono meglio ottimizzare, per un'istanza HAProxy ad alto traffico?

Risposte:


28

Non ho mai riscontrato questo problema. Tuttavia, dovresti probabilmente aumentare la larghezza della tabella hash per ridurne la profondità. Usando "dmesg", vedrai quante voci hai attualmente:

$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)

È possibile modificare questo valore con il parametro della riga di comando di avvio del kernel rhash_entries. Prima provalo a mano e poi aggiungilo al tuo lilo.confo grub.conf.

Per esempio: kernel vmlinux rhash_entries=131072

È possibile che tu abbia una tabella hash molto limitata perché hai assegnato poca memoria alla tua HAProxy VM (la dimensione dell'hash del percorso viene regolata in base alla RAM totale).

Per quanto riguarda tcp_mem, stai attento. Le tue impostazioni iniziali mi fanno pensare che stavi funzionando con 1 GB di RAM, 1/3 dei quali potevano essere allocati ai socket TCP. Ora hai assegnato 367872 * 4096 byte = 1,5 GB di RAM ai socket TCP. Dovresti stare molto attento a non rimanere senza memoria. Una regola empirica è allocare 1/3 della memoria su HAProxy e un altro 1/3 sullo stack TCP e l'ultimo 1/3 sul resto del sistema.

Ho il sospetto che il tuo messaggio "memoria esaurita" provenga dalle impostazioni predefinite in tcp_rmeme tcp_wmem. Per impostazione predefinita, sono allocati 64 kB in uscita per ciascun socket e 87 kB in ingresso. Ciò significa un totale di 300 kB per una connessione proxy, solo per i buffer socket. Aggiungi a quei 16 o 32 kB per HAProxy e vedi che con 1 GB di RAM supporterai solo 3000 connessioni.

Modificando le impostazioni predefinite di tcp_rmeme tcp_wmem(parametro centrale), è possibile ridurre notevolmente la memoria. Ottengo buoni risultati con valori a partire da 4096 per il buffer di scrittura e 7300 o 16060 in tcp_rmem(5 o 11 segmenti TCP). È possibile modificare tali impostazioni senza riavviare, tuttavia si applicheranno solo alle nuove connessioni.

Se preferisci non toccare troppo i tuoi sistemi , l'ultimo HAProxy, 1.4-dev8, ti consente di modificare quei parametri dalla configurazione globale e per lato (client o server).

Spero che questo aiuti!


8

Il Out of socket memory errorè spesso fuorviante. La maggior parte delle volte, su server con connessione a Internet, non indica alcun problema relativo alla memoria insufficiente. Come ho spiegato in modo molto più dettagliato in un post sul blog , il motivo più comune è il numero di socket orfani. Un socket orfano è un socket non associato a un descrittore di file. In determinate circostanze, il kernel emetterà Out of socket memory erroranche se ci si trova a 2x o 4x dal limite ( /proc/sys/net/ipv4/tcp_max_orphans). Ciò accade spesso nei servizi rivolti a Internet ed è perfettamente normale. Il giusto modo di agire in questo caso è quello di ottimizzare tcp_max_orphansalmeno il doppio del numero di orfani che normalmente vedi con il tuo traffico di picco.

Non ascoltare alcun consiglio che consiglia la messa a punto tcp_memo tcp_rmemo tcp_wmemse non sai davvero cosa stai facendo. Coloro che danno questi consigli in genere no. Il loro voodoo è spesso sbagliato o inappropriato per il tuo ambiente e non risolverà il tuo problema. Potrebbe anche peggiorare le cose.


1
Quando ciò accade, il messaggio è diverso in dmesg, vedi "troppi socket orfani". Tuttavia sono d'accordo con te sul fatto che gli orfani possano consumare un'enorme quantità di memoria.
Willy Tarreau,

Quando si supera il numero /proc/sys/net/ipv4/tcp_max_orphanssi verificherà un errore diverso. L'intero stack Exchange Stack, ad esempio, ha /proc/sys/net/ipv4/tcp_max_orphans65536 e /proc/net/sockstatrisulta in TCP: inuso 2996 orfano 171 tw 15972 alloc 2998 mem 1621 - una differenza che non può essere ignorata.
Geoff Dalgas

-4

Ottimizziamo regolarmente alcuni di questi parametri. Il nostro standard per piattaforme di trading ad alta produttività e bassa latenza è:

net.ipv4.tcp_rmem = 4096 16777216 33554432
net.ipv4.tcp_wmem = 4096 16777216 33554432
net.ipv4.tcp_mem = 4096 16777216 33554432
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 30000
net.core.netdev_max_backlog = 30000

1
secondo la matematica di Willy, ciò significa che la pressione della memoria standard # (numero medio) è di 68 GB ?! Tre volte (rmem, wmem, mem) ??
Jeff Atwood,

10
Questi parametri sintonizzabili sono errati e si trovano molto frequentemente in ambienti da banco, quindi incollati alla cieca. Non avranno alcun problema con solo alcune sessioni simultanee, ma anche con 100 socket TCP, assegnerai 3,2 GB di RAM. Finché la latenza è bassa, non noterai nulla di sospetto. Devi solo scollegare una macchina remota durante un trasferimento per vedere il riempimento dei buffer di output o bloccare un'attività locale e vedere il riempimento del buffer di input. È folle ...
Willy Tarreau,

6
Jeff, non sono tre volte. tcp_mem è in pagine e definisce la dimensione globale. tcp_rmem e tcp_wmem sono in byte e definiscono la dimensione per socket.
Willy Tarreau,

Quei parametri sintonizzabili sembrano sbagliati, per server simultanei con piccoli dati non si desidera riservare così tanti buffer socket e tcp_mem è totalmente diverso da r / wmem, usare gli stessi numeri non ha davvero senso (uno è byte per connessioni l'altro pagine per sistema)
verifica il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.