Quels paramètres du noyau ou autres paramètres contrôlent le nombre maximal de sockets TCP pouvant être ouverts sur un serveur Linux? Quels sont les compromis d’autoriser plus de connexions?
J'ai remarqué lors du test de charge d'un serveur Apache avec ab qu'il est assez facile de maximiser les connexions ouvertes sur le serveur. Si vous laissez l'option -k de ab, qui permet la réutilisation de la connexion, et lui faire envoyer plus d'environ 10 000 requêtes, Apache traite les 11 000 premières requêtes environ, puis s'arrête pendant 60 secondes. Un regard sur la sortie netstat montre 11 000 connexions dans l'état TIME_WAIT. Apparemment, c'est normal. Les connexions sont maintenues ouvertes par défaut pendant 60 secondes même après que le client en a fini avec elles pour raisons de fiabilité TCP .
Il semble que ce serait un moyen facile de faire un serveur DoS et je me demande quels sont les réglages et les précautions habituels.
Voici ma sortie de test:
# ab -c 5 -n 50000 http://localhost/
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> Apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.Apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
apr_poll: The timeout specified has expired (70007)
Total of 11655 requests completed
Voici la commande netstat que j'exécute pendant le test:
# netstat --inet -p | grep "localhost:www" | sed -e 's/ \+/ /g' | cut -d' ' -f 1-4,6-7 | sort | uniq -c
11651 tcp 0 0 localhost:www TIME_WAIT -
1 tcp 0 1 localhost:44423 SYN_SENT 7831/ab
1 tcp 0 1 localhost:44424 SYN_SENT 7831/ab
1 tcp 0 1 localhost:44425 SYN_SENT 7831/ab
1 tcp 0 1 localhost:44426 SYN_SENT 7831/ab
1 tcp 0 1 localhost:44428 SYN_SENT 7831/ab
J'ai finalement trouvé le paramètre qui limitait vraiment le nombre de connexions: net.ipv4.netfilter.ip_conntrack_max
. Celui-ci a été fixé à 11 776 et tout ce que je l'ai défini correspond au nombre de demandes que je peux traiter dans mon test avant de devoir attendre tcp_fin_timeout
secondes pour que plus de connexions soient disponibles. La table conntrack
est ce que le noyau utilise pour suivre l'état des connexions donc une fois qu'il est plein, le noyau commence à supprimer les paquets et à l'imprimer dans le journal:
Jun 2 20:39:14 XXXX-XXX kernel: ip_conntrack: table full, dropping packet.
L'étape suivante consistait à amener le noyau à recycler toutes ces connexions dans le TIME_WAIT
état plutôt que de supprimer des paquets. Je pourrais y arriver en activant tcp_tw_recycle
ou en augmentation ip_conntrack_max
doit être supérieur au nombre de ports locaux mis à disposition pour les connexions par ip_local_port_range
. Je suppose qu'une fois que le noyau est hors des ports locaux, il commence à recycler les connexions. Cela utilise plus de connexions de suivi de la mémoire, mais cela semble être la meilleure solution que d'activer tcp_tw_recycle
puisque les documents impliquent que c'est dangereux.
Avec cette configuration, je peux exécuter ab toute la journée et ne jamais manquer de connexions:
net.ipv4.netfilter.ip_conntrack_max = 32768
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_Orphan_retries = 1
net.ipv4.tcp_fin_timeout = 25
net.ipv4.tcp_max_orphans = 8192
net.ipv4.ip_local_port_range = 32768 61000
Le tcp_max_orphans
le réglage n'a eu aucun effet sur mes tests et je ne sais pas pourquoi. Je pense que cela fermerait les connexions dans TIME_WAIT
dire une fois qu'il y en avait 8192 mais ça ne fait pas ça pour moi.
Vous voulez vraiment voir ce que le système de fichiers/proc peut vous offrir à cet égard.
Sur cette dernière page, vous trouverez peut-être les éléments suivants qui vous intéressent:
Je ne pense pas qu'il soit possible de régler cela directement. Cela relève de la catégorie du réglage TCP/IP. Pour savoir ce que vous pouvez régler, essayez 'man 7 tcp'. Le sysctl ('man 8 sysctl') est utilisé pour les définir. 'sysctl -a | grep tcp 'vous montrera la plupart de ce que vous pouvez régler, mais je ne suis pas sûr qu'il les montrera tous. De plus, à moins que cela n'ait changé, les sockets TCP/IP s'ouvrent comme des descripteurs de fichiers. Donc ceci et la section suivante de ce lien pourrait être ce que vous recherchez.
Essayez de définir les paramètres suivants ainsi que tcp_fin_timeout. Cela devrait clôturer TIME_WAIT plus rapidement.
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
Le stock Apache (1) était prédéfini pour ne prendre en charge que 250 connexions simultanées - si vous en vouliez plus, il y avait un fichier d'en-tête à modifier pour autoriser plus de sessions simultanées. Je ne sais pas si cela est toujours vrai avec Apache 2.
En outre, vous devez ajouter une option pour autoriser des charges de descripteurs de fichiers plus ouverts pour le compte qui exécute Apache - quelque chose que les commentaires précédents ne soulignent pas.
Faites attention à vos paramètres de travail et au type de délais d'attente persistants que vous avez dans Apache lui-même, au nombre de serveurs de rechange que vous utilisez en même temps et à la vitesse à laquelle ces processus supplémentaires sont tués.
Vous pouvez réduire le temps passé dans l'état TIME_WAIT (Set net.ipv4.tcp_fin_timeout). Vous pouvez remplacer Apache par YAWS ou nginx ou quelque chose de similaire.
Les compromis de plus de connexions impliquent généralement l'utilisation de la mémoire, et si vous avez un processus de forking, de nombreux processus enfants qui submergent votre CPU.
L'outil d'analyse comparative du serveur HTTP Apache, ab , dans la version 2.4 a l'option - timeout . Voir aussi erreur ab (Apache Bench): apr_poll: le délai spécifié a expiré (70007) sous Windows.
Cette option résout votre problème.
Le nombre absolu de sockets qui peuvent être ouverts sur une seule adresse IP est 2 ^ 16 et est défini par TCP/UDP, pas par le noyau.