257 votes

Augmenter le nombre maximum de connexions TCP/IP sous Linux

Je suis en train de programmer un serveur et il semble que le nombre de connexions soit limité car ma bande passante n'est pas saturée même si j'ai réglé le nombre de connexions sur "illimité".

Comment puis-je augmenter ou supprimer le nombre maximal de connexions que ma boîte Ubuntu Linux peut ouvrir à la fois ? Est-ce le système d'exploitation qui limite ce nombre, ou est-ce le routeur ou le fournisseur d'accès ? Ou bien est-ce quelque chose d'autre ?

498voto

mdk Points 966

Le nombre maximal de connexions est influencé par certaines limites, tant du côté client que du côté serveur, mais de manière un peu différente.

Du côté du client : Augmentez la portée du port éphémère, et diminuez le tcp_fin_timeout

Pour connaître les valeurs par défaut :

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

La plage de port éphémère définit le nombre maximum de sockets sortants qu'un hôte peut créer à partir d'une adresse I.P. particulière. L'adresse fin_timeout définit le temps minimum pendant lequel ces sockets resteront en TIME_WAIT (inutilisable après avoir été utilisé une fois). Les valeurs par défaut habituelles du système sont :

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

Cela signifie essentiellement que votre système ne peut pas garantir de manière constante plus que (61000 - 32768) / 60 = 470 sockets par seconde. Si vous n'êtes pas satisfait de ce résultat, vous pouvez commencer par augmenter le nombre de sockets par seconde. port_range . Réglage de la gamme sur 15000 61000 est assez courante de nos jours. Vous pouvez encore augmenter la disponibilité en diminuant le nombre d'heures d'utilisation. fin_timeout . Supposons que vous fassiez les deux, vous devriez voir plus de 1500 connexions sortantes par seconde, plus facilement.

Pour modifier les valeurs :

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

Les données ci-dessus ne doivent pas être interprétées comme les facteurs ayant un impact sur la capacité du système à établir des connexions sortantes par seconde. Mais plutôt ces facteurs affectent la capacité du système à gérer des connexions simultanées de manière durable pendant de grandes périodes d'"activité".

Valeurs par défaut de Sysctl sur une boîte Linux typique pour tcp_tw_recycle & tcp_tw_reuse serait

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

Ceux-ci ne permettent pas de se connecter à partir d'une socket "utilisée" (en état d'attente) et forcent les sockets à durer toute la durée de l'opération. time_wait cycle. Je recommande de le régler :

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

Cela permet un cycle rapide des prises dans time_wait et de les réutiliser. Mais avant d'effectuer ce changement, assurez-vous que cela n'entre pas en conflit avec les protocoles que vous utiliseriez pour l'application qui a besoin de ces sockets. Assurez-vous de lire le post "Faire face au TCP TIME-WAIT" de Vincent Bernat pour comprendre les implications. Le site net.ipv4.tcp_tw_recycle est assez problématique pour les serveurs ouverts au public, car elle ne permet pas de gérer les connexions provenant de deux ordinateurs différents situés derrière le même dispositif NAT. Il s'agit d'un problème difficile à détecter qui ne demande qu'à être résolu. Notez que net.ipv4.tcp_tw_recycle a été supprimé de Linux 4.12.

Du côté du serveur : Le site net.core.somaxconn a un rôle important. Elle limite le nombre maximal de requêtes mises en file d'attente sur un socket d'écoute. Si vous êtes sûr des capacités de votre application serveur, augmentez la valeur par défaut de 128 à quelque chose comme 128 à 1024. Vous pouvez maintenant tirer parti de cette augmentation en modifiant la variable listen backlog dans l'appel listen de votre application, avec un nombre entier égal ou supérieur.

sysctl net.core.somaxconn=1024

txqueuelen Les paramètres de vos cartes ethernet ont également un rôle à jouer. Les valeurs par défaut sont de 1000, alors augmentez-les à 5000 ou même plus si votre système peut le supporter.

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

De même, augmentez les valeurs de net.core.netdev_max_backlog y net.ipv4.tcp_max_syn_backlog . Leurs valeurs par défaut sont respectivement 1000 et 1024.

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

Maintenant, n'oubliez pas de démarrer vos applications côté client et côté serveur en augmentant les ulimts FD, dans le shell.

En plus de ce qui précède, une autre technique populaire utilisée par les programmeurs consiste à réduire le nombre d'éléments suivants tcp écrire appels. Ma préférence va à l'utilisation d'une mémoire tampon dans laquelle je pousse les données que je souhaite envoyer au client, puis, aux endroits appropriés, j'écris les données mises en mémoire tampon dans le socket réel. Cette technique me permet d'utiliser de gros paquets de données, de réduire la fragmentation, de réduire l'utilisation du CPU tant au niveau de l'utilisateur qu'au niveau du noyau.

71voto

derobert Points 26258

Il existe plusieurs variables pour définir le nombre maximal de connexions. Le plus probable est que vous soyez d'abord à court de numéros de fichiers. Vérifiez ulimit -n . Ensuite, il y a des paramètres dans /proc mais ceux-ci se chiffrent par défaut en dizaines de milliers.

Plus important encore, on dirait que tu fais quelque chose de mal. Une seule connexion TCP devrait pouvoir utiliser toute la bande passante entre deux parties, si ce n'est pas le cas :

  • Vérifiez si le paramètre de votre fenêtre TCP est suffisamment grand. Les paramètres par défaut de Linux sont bons pour tout, sauf pour les liaisons Internet très rapides (centaines de mbps) ou les liaisons satellites rapides. Quel est votre produit bande passante*délai ?
  • Vérifiez la perte de paquets en utilisant ping avec de gros paquets ( ping -s 1472 ...)
  • Vérifiez si le taux est limité. Sous Linux, ceci est configuré avec tc
  • Confirmez que la bande passante que vous pensez exister existe réellement en utilisant par exemple, iperf
  • Confirmez que votre protocole est sain. N'oubliez pas la latence.
  • S'il s'agit d'un réseau local gigabit+, pouvez-vous utiliser des paquets jumbo ? Le pouvez-vous ?

Il est possible que j'aie mal compris. Peut-être faites-vous quelque chose comme Bittorrent, où vous avez besoin de beaucoup de connexions. Si c'est le cas, vous devez déterminer le nombre de connexions que vous utilisez réellement (essayer netstat o lsof ). Si ce nombre est important, vous pourriez :

  • Vous disposez d'une bande passante importante, par exemple 100 Mbps+. Dans ce cas, il se peut que vous ayez besoin d'augmenter la valeur du ulimit -n . Néanmoins, ~1000 connexions (par défaut sur mon système), c'est beaucoup.
  • Vous avez des problèmes de réseau qui ralentissent vos connexions (par exemple, perte de paquets).
  • Quelque chose d'autre vous ralentit, par exemple la bande passante IO, surtout si vous êtes en recherche. Avez-vous vérifié iostat -x ?

De même, si vous utilisez un routeur NAT grand public (Linksys, Netgear, DLink, etc.), sachez que vous risquez de dépasser ses capacités avec des milliers de connexions.

J'espère que cela vous aidera. Vous posez vraiment une question de mise en réseau.

21voto

whitehat237 Points 66

Pour améliorer la réponse donnée par derobert,

Vous pouvez déterminer la limite de connexion de votre système d'exploitation en consultant le fichier nf_conntrack_max.

Par exemple : cat /proc/sys/net/netfilter/nf_conntrack_max

Vous pouvez utiliser le script suivant pour compter le nombre de connexions tcp à une plage donnée de ports tcp. Par défaut 1-65535.

Cela permettra de confirmer si vous avez atteint ou non la limite de connexion de votre système d'exploitation.

Voici le script.

#!/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}'

10voto

Kev Points 111

Au niveau de l'application, voici ce qu'un développeur peut faire :

Du côté du serveur :

  1. Vérifiez si l'équilibreur de charge (si vous en avez un), fonctionne correctement.

  2. Transformez les délais d'attente TCP lents en réponse immédiate rapide 503. Si votre équilibreur de charge fonctionne correctement, il devrait choisir la ressource fonctionnelle à servir, et c'est mieux que de rester là avec des messages d'erreur inattendus.

Par exemple, si vous utilisez un serveur node, vous pouvez utiliser toobusy de npm. Implémentation quelque chose comme :

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

Pourquoi 503 ? Voici quelques bons points de vue sur la surcharge : http://ferd.ca/queues-don-t-fix-overload.html

Nous pouvons aussi travailler du côté client :

  1. Essayez de regrouper les appels par lots, afin de réduire le trafic et le nombre total de demandes entre le client et le serveur.

  2. Essayez de construire une couche intermédiaire de cache pour traiter les demandes inutiles en double.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X