web-dev-qa-db-fra.com

Augmentation du nombre maximal de connexions TCP / IP sous Linux

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

Comment puis-je augmenter ou éliminer un nombre maximal de connexions que ma machine Ubuntu Linux peut ouvrir à la fois? Est-ce que le système d'exploitation limite cela ou est-ce le routeur ou le FAI? Ou s'agit-il d'autre chose?

186
jbu

Certaines limites, tant du côté client que du côté serveur, ont un impact sur le nombre maximal de connexions, bien que ce soit un peu différemment.

Du côté client: Augmentez la plage de ports éphermaux 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 ports éphermiques définit le nombre maximal de sockets sortants qu'un hôte peut créer à partir d'un I.P. donné. adresse. Le fin_timeout définit le temps minimum pendant lequel ces sockets resteront dans l'état TIME_WAIT (inutilisable après avoir été utilisé une fois). Les paramètres par défaut du système sont:

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

En gros, cela signifie que votre système ne peut pas toujours garantir plus de (61000 - 32768) / 60 = 470 sockets par seconde. Si cela ne vous convient pas, vous pouvez commencer par augmenter le port_range. La définition de la plage sur 15000 61000 est assez courante de nos jours. Vous pouvez augmenter encore la disponibilité en diminuant le fin_timeout. Supposons que vous fassiez les deux, vous devriez voir plus de 1 500 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

Ce qui précède ne doit pas être interprété comme un facteur ayant une incidence sur la capacité du système à établir des connexions sortantes par seconde. Mais ces facteurs affectent plutôt la capacité du système à gérer les connexions simultanées de manière durable pendant de longues périodes "d'activité".

Les valeurs Sysctl par défaut sur une machine Linux typique pour tcp_tw_recycle & tcp_tw_reuse seraient

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

Celles-ci ne permettent pas une connexion depuis une socket "utilisée" (en attente) et forcent les sockets à durer le cycle complet time_wait. Je recommande le réglage:

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

Cela permet de cycler rapidement les sockets dans l'état time_wait et de les réutiliser. Mais avant de procéder à cette modification, 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 message "Composer avec TCP TIME-WAIT" de Vincent Bernat pour comprendre les implications. L'option net.ipv4.tcp_tw_recycle est assez problématique pour les serveurs faisant face au public, car elle ne gère pas les connexions de deux ordinateurs différents derrière le même périphérique NAT , qui est un problème difficile à détecter et à attendre pour vous mordre. Notez que net.ipv4.tcp_tw_recycle a été supprimé de Linux4.12.

Côté serveur: La valeur net.core.somaxconn a un rôle important. Il limite le nombre maximal de demandes en file d'attente à un socket d'écoute. Si vous êtes sûr de la capacité de votre application serveur, augmentez-la de 128 par défaut à 128 à 1024. Vous pouvez maintenant tirer parti de cette augmentation en modifiant la variable backlog d'écoute dans l'appel d'écoute de votre application, en un entier égal ou supérieur.

sysctl net.core.somaxconn=1024

Les paramètres txqueuelen de vos cartes Ethernet ont également un rôle à jouer. Les valeurs par défaut sont 1000, alors augmentez-les jusqu'à 5000, voire davantage si votre système peut le gérer.

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

De même, bump up les valeurs pour net.core.netdev_max_backlog et net.ipv4.tcp_max_syn_backlog. Leurs valeurs par défaut sont 1000 et 1024 respectivement.

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

Pensez maintenant à démarrer vos applications côté client et serveur en augmentant le nombre de FD dans le shell.

Outre la technique ci-dessus, une autre technique couramment utilisée par les programmeurs consiste à réduire le nombre d'appels tcp write. Ma propre préférence est d'utiliser un tampon dans lequel je pousse les données que je souhaite envoyer au client, puis aux points appropriés, j'écris les données mises en mémoire tampon dans le socket actuel. Cette technique me permet d’utiliser des paquets de données volumineux, de réduire la fragmentation et d’utiliser mon processeur aussi bien au niveau de l’utilisateur qu’au niveau du noyau.

353
mdk

Deux variables permettent de définir le nombre maximal de connexions. Très probablement, vous commencez par manquer de numéros de fichiers. Vérifiez ulimit -n. Après cela, il y a des paramètres dans/proc, mais ceux par défaut sont des dizaines de milliers.

Plus important encore, on dirait que vous faites 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 valeurs par défaut de Linux conviennent à tout sauf aux liaisons inet très rapides (des centaines de Mbps) ou aux liaisons par satellite rapides. Quel est votre produit de délai de bande passante *?
  • Vérifiez la perte de paquets en utilisant ping avec des paquets volumineux (ping -s 1472 ...)
  • Vérifiez la limitation du taux. Sous Linux, ceci est configuré avec tc
  • Confirmez que la bande passante que vous pensez existe existe réellement en utilisant, par exemple, iperf
  • Confirmez que votre protocole est sain d'esprit. Rappelez-vous la latence.
  • S'il s'agit d'un réseau local Gigabit +, pouvez-vous utiliser des paquets Jumbo? Es-tu?

J'ai peut-être mal compris. Peut-être que vous faites quelque chose comme Bittorrent, où vous avez besoin de beaucoup de connexions. Si tel est le cas, vous devez déterminer le nombre de connexions que vous utilisez réellement (essayez netstat ou lsof). Si ce nombre est important, vous pourriez:

  • Utilisez beaucoup de bande passante, par exemple 100 Mbps +. Dans ce cas, vous devrez peut-être utiliser le ulimit -n. Malgré tout, environ 1 000 connexions (par défaut sur mon système) en représentent quelques-unes.
  • Avoir des problèmes de réseau qui ralentissent vos connexions (par exemple, perte de paquets)
  • Demandez à quelque chose d'autre qui vous ralentisse, par exemple IO bande passante, surtout si vous recherchez. Avez-vous vérifié iostat -x?

De même, si vous utilisez un routeur NAT de grande qualité (Linksys, Netgear, DLink, etc.), prenez garde de dépasser ses capacités avec des milliers de connexions.

J'espère que cela fournit de l'aide. Vous posez vraiment une question de mise en réseau.

59
derobert

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

Vous pouvez déterminer votre limite de connexion au système d'exploitation en accédant à 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 confirmera si vous atteignez ou non votre limite de connexion au 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}'
15
whitehat237

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

Du côté du serveur:

  1. Vérifiez si l'équilibreur de charge (le cas échéant) fonctionne correctement.

  2. Transformez lentement le délai d'attente TCP en réponse rapide 503; si le chargement de l'équilibreur fonctionne correctement, il doit sélectionner la ressource de travail à servir et il vaut mieux que de rester avec des massages d'erreur inattendus.

Exemple: si vous utilisez un serveur de nœud, vous pouvez utiliser toobusy à partir de npm. Mise en œuvre 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 bonnes idées contre la surcharge: http://ferd.ca/queues-don-t-fix-overload.html

Nous pouvons également travailler du côté client:

  1. Essayez de grouper les appels par lots, réduisez le trafic et le nombre total de demandes client n/b et serveur.

  2. Essayez de créer une couche intermédiaire de cache pour gérer les demandes de doublons inutiles.

10
Kev