Aumentando il numero massimo di connessioni TCP / IP in Linux


214

Sto programmando un server e sembra che il mio numero di connessioni sia limitato poiché la mia larghezza di banda non viene saturata anche quando ho impostato il numero di connessioni su "illimitato".

Come posso aumentare o eliminare un numero massimo di connessioni che la mia casella Ubuntu Linux può aprire contemporaneamente? Il sistema operativo limita questo o è il router o l'ISP? O è qualcos'altro?


2
@Software Monkey: ho risposto comunque perché spero che questo possa essere utile a qualcuno che in realtà sta scrivendo un server in futuro.
derobert

1
@derobert: ho visto quel +1. In realtà, ho avuto lo stesso pensiero dopo il mio commento precedente, ma ho pensato di lasciare il commento in piedi.
Lawrence Dol,

Risposte:


396

Il numero massimo di connessioni è influenzato da determinati limiti sia lato client che lato server, anche se in modo leggermente diverso.

Sul lato client: aumentare l'intervallo di porte ephermal e diminuire il valoretcp_fin_timeout

Per scoprire i valori predefiniti:

sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.tcp_fin_timeout

L'intervallo di porte ephermal definisce il numero massimo di socket in uscita che un host può creare da un determinato indirizzo IP. La fin_timeoutdefinisce il tempo minimo queste prese rimarranno in TIME_WAITstato (inutilizzabile dopo essere stato usato una volta). I valori predefiniti di sistema usuali sono:

  • net.ipv4.ip_local_port_range = 32768 61000
  • net.ipv4.tcp_fin_timeout = 60

Ciò significa sostanzialmente che il tuo sistema non può garantire costantemente più di (61000 - 32768) / 60 = 470prese al secondo. Se non sei soddisfatto, potresti iniziare con l'aumento di port_range. Impostare l'intervallo su 15000 61000è abbastanza comune in questi giorni. È possibile aumentare ulteriormente la disponibilità diminuendo il fin_timeout. Supponiamo che tu faccia entrambe le cose, dovresti vedere più di 1500 connessioni in uscita al secondo, più facilmente.

Per modificare i valori :

sysctl net.ipv4.ip_local_port_range="15000 61000"
sysctl net.ipv4.tcp_fin_timeout=30

Quanto sopra non deve essere interpretato come i fattori che influenzano la capacità del sistema di stabilire connessioni in uscita al secondo. Ma piuttosto questi fattori influenzano la capacità del sistema di gestire connessioni simultanee in modo sostenibile per lunghi periodi di "attività".

I valori predefiniti di Sysctl su una tipica scatola Linux per tcp_tw_recycle& tcp_tw_reusesarebbero

net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=0

Questi non consentono una connessione da una presa "usata" (in stato di attesa) e costringono le prese a durare l'intero time_waitciclo. Consiglio di impostare:

sysctl net.ipv4.tcp_tw_recycle=1
sysctl net.ipv4.tcp_tw_reuse=1 

Ciò consente il ciclo rapido delle prese nello time_waitstato e il loro riutilizzo. Prima di apportare questa modifica, tuttavia, assicurarsi che ciò non sia in conflitto con i protocolli da utilizzare per l'applicazione che necessita di questi socket. Assicurati di leggere il post " Far fronte al TCP TIME-WAIT" di Vincent Bernat per capire le implicazioni. L' net.ipv4.tcp_tw_recycle opzione è piuttosto problematica per i server pubblici in quanto non gestirà le connessioni da due computer diversi dietro lo stesso dispositivo NAT , il che è un problema difficile da rilevare e in attesa di morderti. Si noti che net.ipv4.tcp_tw_recycleè stato rimosso da Linux 4.12.

Sul lato server: il net.core.somaxconnvalore ha un ruolo importante. Limita il numero massimo di richieste in coda a un socket di ascolto. Se sei sicuro della capacità della tua applicazione server, aumentalo da 128 a qualcosa come 128 a 1024. Ora puoi approfittare di questo aumento modificando la variabile di ascolto del backlog nella chiamata di ascolto della tua applicazione, a un numero intero uguale o superiore.

sysctl net.core.somaxconn=1024

txqueuelenAnche il parametro delle tue schede Ethernet ha un ruolo da svolgere. I valori predefiniti sono 1000, quindi aumentali fino a 5000 o anche di più se il tuo sistema è in grado di gestirlo.

ifconfig eth0 txqueuelen 5000
echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local

Allo stesso modo aumentare i valori per net.core.netdev_max_backloge net.ipv4.tcp_max_syn_backlog. I loro valori predefiniti sono rispettivamente 1000 e 1024.

sysctl net.core.netdev_max_backlog=2000
sysctl net.ipv4.tcp_max_syn_backlog=2048

Ora ricordati di avviare le applicazioni lato client e lato server aumentando gli ultrasuoni FD, nella shell.

Oltre alla precedente tecnica più popolare utilizzata dai programmatori è quella di ridurre il numero di chiamate in scrittura tcp . La mia preferenza è quella di utilizzare un buffer in cui invio i dati che desidero inviare al client e quindi, nei punti appropriati, scrivo i dati bufferizzati nel socket effettivo. Questa tecnica mi consente di utilizzare pacchetti di dati di grandi dimensioni, ridurre la frammentazione, ridurre l'utilizzo della CPU sia a livello di utente che a livello di kernel.


4
Risposta brillante! Il mio problema era un po 'diverso, cioè stavo cercando di spostare le informazioni sulla sessione da un archivio di sessioni a livello di applicazione a redis tramite PHP. Per qualche motivo, non ho potuto aggiungere più di 28230 sessioni senza aggiungere un sacco di sonno in una volta sola, senza errori visti né nei registri php né nei registri redis. Abbiamo rotto la testa su questo per un giorno intero fino a quando ho pensato che forse il problema non è con php / redis ma nello strato tcp / ip che collega i due e siamo arrivati ​​a questa risposta. Riuscito a risolvere il problema in pochissimo tempo :) Grazie mille!
1313

27
Non dimenticare che parliamo sempre della porta IP +. Puoi avere socket "illimitati" aperti sulla porta XY da molti IP diversi. Il limite di 470 si applica solo ai socket aperti simultanei allo stesso IP. Un altro IP può avere le sue 470 connessioni alle stesse porte.
Marki555,

6
@ Marki555: il tuo commento è MOLTO CORRETTO. Le applicazioni sviluppate per generare e supportare un gran numero di connessioni in uscita, devono avere una "consapevolezza" degli IP disponibili per la creazione di connessioni in uscita e devono quindi associarsi in modo appropriato a questi indirizzi IP utilizzando una sorta di "algoritmo round robin" e mantenere un "quadro di valutazione".
mk

8
Questa risposta ha degli errori. Innanzitutto, net.ipv4.tcp_fin_timeout è solo per lo stato FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). In secondo luogo, come diceva @Eric, "470 socket in qualsiasi momento" non è corretto.
Sharvanath,

3
@mdk: non sono chiaro con questa parte di calcolo (61000 - 32768) / 60 = 470 sockets per second. Potete per favore elaborare questo?
Tom Taylor,

64

Esistono un paio di variabili per impostare il numero massimo di connessioni. Molto probabilmente, prima esaurisci i numeri dei file. Controlla ulimit -n. Dopodiché, ci sono impostazioni in / proc, ma quelle predefinite sono decine di migliaia.

Ancora più importante, sembra che tu stia facendo qualcosa di sbagliato. Una singola connessione TCP dovrebbe essere in grado di utilizzare tutta la larghezza di banda tra due parti; se non lo è:

  • Controlla se la tua finestra TCP è abbastanza grande. Le impostazioni predefinite di Linux sono valide per tutto tranne che per il collegamento inet molto veloce (centinaia di mbps) o per i collegamenti satellitari veloci. Qual è il tuo ritardo di larghezza di banda *?
  • Controlla la perdita di pacchetti usando il ping con pacchetti di grandi dimensioni ( ping -s 1472...)
  • Verificare la limitazione della velocità. Su Linux, questo è configurato contc
  • Conferma che la larghezza di banda che ritieni esista effettivamente esiste, ad es. iperf
  • Conferma che il tuo protocollo è sano. Ricorda la latenza.
  • Se questo è un gigabit + LAN, puoi usare pacchetti jumbo? Tu sei?

Forse ho frainteso. Forse stai facendo qualcosa come Bittorrent, dove hai bisogno di molte connessioni. In tal caso, è necessario capire quante connessioni si stanno effettivamente utilizzando (provare netstato lsof). Se quel numero è sostanziale, potresti:

  • Hanno molta larghezza di banda, ad es. 100 Mbps +. In questo caso, potrebbe essere necessario aumentare il ulimit -n. Tuttavia, ~ 1000 connessioni (impostazione predefinita sul mio sistema) sono piuttosto poche.
  • Problemi di rete che rallentano le connessioni (ad es. Perdita di pacchetti)
  • Avere qualcos'altro che ti rallenta, ad esempio la larghezza di banda IO, specialmente se stai cercando. Hai controllato iostat -x?

Inoltre, se stai utilizzando un router NAT di qualità consumer (Linksys, Netgear, DLink, ecc.), Fai attenzione che potresti superare le sue capacità con migliaia di connessioni.

Spero che questo ti aiuti. Stai davvero facendo una domanda di rete.


16

Per migliorare la risposta data da derobert,

È possibile determinare quale sia il limite di connessione del sistema operativo catturando nf_conntrack_max.

Ad esempio: cat / proc / sys / net / netfilter / nf_conntrack_max

È possibile utilizzare il seguente script per contare il numero di connessioni tcp su un determinato intervallo di porte tcp. Per impostazione predefinita 1-65535.

Ciò confermerà se si sta massimizzando il limite di connessione del sistema operativo.

Ecco la sceneggiatura.

#!/bin/bash
OS=$(uname)

case "$OS" in
    'SunOS')
            AWK=/usr/bin/nawk
            ;;
    'Linux')
            AWK=/bin/awk
            ;;
    'AIX')
            AWK=/usr/bin/awk
            ;;
esac

netstat -an | $AWK -v start=1 -v end=65535 ' $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ {
    if ($1 ~ /\./)
            {sip=$1}
    else {sip=$4}

    if ( sip ~ /:/ )
            {d=2}
    else {d=5}

    split( sip, a, /:|\./ )

    if ( a[d] >= start && a[d] <= end ) {
            ++connections;
            }
    }
    END {print connections}'

3
which awkè il tuo amico per determinare il percorso verso Awk, anche SunOS ha un link ad esso :)
Panagiotis Moustafellos

2
@PanagiotisM. whichsi affida al programma per essere nel PATHqual caso puoi semplicemente usare awkinvece di fornire il percorso completo. (detto questo, non sono sicuro che la soluzione nella sceneggiatura sia più vicina alla perfezione, ma non è questo lo scopo della sceneggiatura).
Michael Krelin - hacker,

5
Adoro il modo in cui questo script diventa balistico per determinare la awkposizione, ma presume che la shell sia sempre /bin/bash (suggerimento professionale: AIX5 / 6 non ha nemmeno bash di default).
Kubanczyk,

Il awkrilevamento è utile? Personalmente, suppongo semplicemente di avere PATHun'alternativa corretta, ma una ragionevole potrebbe essere /usr/bin/env awke /usr/bin/env bashrispettivamente. Per quello che vale, ha sbagliato la posizione sul mio sistema Linux. Non lo /usr/bin/awkè/bin/awk
Wolph,

1
quando eseguo questo script ottengo 798, quindi cosa significa?

10

A livello di applicazione, ecco qualcosa che uno sviluppatore può fare:

Dal lato server:

  1. Controlla se il bilanciamento del carico (se presente) funziona correttamente.

  2. Trasforma i timeout TCP lenti in 503 risposta immediata veloce, se il bilanciamento del carico funziona correttamente, dovrebbe scegliere la risorsa di lavoro da servire ed è meglio che appenderti lì con massaggi di errori imprevisti.

Ad esempio: se si utilizza il server dei nodi, è possibile utilizzare toobusy da npm. Implementazione qualcosa del tipo:

var toobusy = require('toobusy');
app.use(function(req, res, next) {
  if (toobusy()) res.send(503, "I'm busy right now, sorry.");
  else next();
});

Perché 503 Ecco alcune informazioni utili per il sovraccarico: http://ferd.ca/queues-don-t-fix-overload.html

Possiamo fare un po 'di lavoro anche sul lato client:

  1. Prova a raggruppare le chiamate in batch, ridurre il traffico e il numero totale di richieste in b / n client e server.

  2. Prova a creare una cache di livello intermedio per gestire richieste duplicate non necessarie.

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.