Erhöhen der maximalen Anzahl von TCP / IP-Verbindungen unter Linux

214

Ich programmiere einen Server und es scheint, dass meine Anzahl von Verbindungen begrenzt ist, da meine Bandbreite nicht gesättigt ist, selbst wenn ich die Anzahl von Verbindungen auf "unbegrenzt" eingestellt habe.

Wie kann ich die maximale Anzahl von Verbindungen erhöhen oder beseitigen, die meine Ubuntu Linux-Box gleichzeitig öffnen kann? Beschränkt das Betriebssystem dies oder ist es der Router oder der ISP? Oder ist es etwas anderes?

red0ct
quelle
2
@ Software Monkey: Ich habe dies trotzdem beantwortet, weil ich hoffe, dass dies für jemanden nützlich sein könnte, der in Zukunft tatsächlich einen Server schreibt.
Derobert
1
@derobert: Ich habe das +1 gesehen. Eigentlich hatte ich nach meinem vorherigen Kommentar den gleichen Gedanken, dachte aber, ich würde den Kommentar stehen lassen.
Lawrence Dol

Antworten:

395

Die maximale Anzahl von Verbindungen wird durch bestimmte Einschränkungen sowohl auf Client- als auch auf Serverseite beeinflusst, wenn auch etwas unterschiedlich.

Auf der Client-Seite: Erhöhen Sie den ephermalen Portbereich und verringern Sie dentcp_fin_timeout

So ermitteln Sie die Standardwerte:

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

Der ephermale Portbereich definiert die maximale Anzahl ausgehender Sockets, die ein Host aus einer bestimmten IP-Adresse erstellen kann. Das fin_timeoutdefiniert die Mindestzeit, in der diese Sockets im TIME_WAITStatus bleiben (unbrauchbar nach einmaliger Verwendung). Übliche Systemstandards sind:

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

Dies bedeutet im Grunde, dass Ihr System nicht durchgehend mehr als (61000 - 32768) / 60 = 470Sockets pro Sekunde garantieren kann . Wenn Sie damit nicht zufrieden sind, können Sie mit der Erhöhung der beginnen port_range. Das Einstellen des Bereichs 15000 61000ist heutzutage ziemlich üblich. Sie können die Verfügbarkeit weiter erhöhen, indem Sie die verringern fin_timeout. Angenommen, Sie tun beides, und Sie sollten leichter mehr als 1500 ausgehende Verbindungen pro Sekunde sehen.

So ändern Sie die Werte :

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

Das Obige sollte nicht als die Faktoren interpretiert werden, die die Systemfähigkeit zum Herstellen ausgehender Verbindungen pro Sekunde beeinflussen. Vielmehr beeinflussen diese Faktoren die Fähigkeit des Systems, gleichzeitige Verbindungen über große Zeiträume von "Aktivitäten" auf nachhaltige Weise zu handhaben.

Standardwerte für Sysctl auf einer typischen Linux-Box für tcp_tw_recycle& tcp_tw_reusewären

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

Diese erlauben keine Verbindung von einem "gebrauchten" Socket (im Wartezustand) und zwingen die Sockets, den gesamten time_waitZyklus zu dauern . Ich empfehle die Einstellung:

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

Dies ermöglicht ein schnelles Durchlaufen der Steckdosen im time_waitStatus und deren Wiederverwendung. Bevor Sie diese Änderung vornehmen, stellen Sie jedoch sicher, dass dies nicht mit den Protokollen in Konflikt steht, die Sie für die Anwendung verwenden würden, die diese Sockets benötigt. Lesen Sie unbedingt den Beitrag "Umgang mit dem TCP TIME-WAIT" von Vincent Bernat , um die Auswirkungen zu verstehen. Die net.ipv4.tcp_tw_recycle Option ist für öffentlich zugängliche Server ziemlich problematisch, da sie keine Verbindungen von zwei verschiedenen Computern hinter demselben NAT-Gerät verarbeitet. Dies ist ein Problem, das schwer zu erkennen ist und darauf wartet, Sie zu beißen. Beachten Sie, dass net.ipv4.tcp_tw_recyclewurde entfernt von Linux 4.12.

Auf der Serverseite: Der net.core.somaxconnWert spielt eine wichtige Rolle. Es begrenzt die maximale Anzahl von Anforderungen, die an einen Listen-Socket in die Warteschlange gestellt werden. Wenn Sie sich sicher sind, dass Ihre Serveranwendung in der Lage ist, erhöhen Sie sie von Standard 128 auf 128 bis 1024. Jetzt können Sie diese Erhöhung nutzen, indem Sie die Listen-Backlog-Variable im Listen-Aufruf Ihrer Anwendung auf eine gleiche oder eine höhere Ganzzahl ändern.

sysctl net.core.somaxconn=1024

txqueuelenParameter Ihrer Ethernet-Karten spielen ebenfalls eine Rolle. Die Standardwerte sind 1000. Erhöhen Sie sie also auf 5000 oder sogar mehr, wenn Ihr System damit umgehen kann.

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

Erhöhen Sie in ähnlicher Weise die Werte für net.core.netdev_max_backlogund net.ipv4.tcp_max_syn_backlog. Ihre Standardwerte sind 1000 bzw. 1024.

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

Denken Sie jetzt daran, sowohl Ihre clientseitigen als auch Ihre serverseitigen Anwendungen zu starten, indem Sie die FD-Grenzen in der Shell erhöhen.

Neben der oben genannten ist eine weitere beliebte Technik, die von Programmierern verwendet wird, die Anzahl der TCP-Schreibaufrufe zu reduzieren . Ich bevorzuge es, einen Puffer zu verwenden, in dem ich die Daten, die ich an den Client senden möchte, weitergebe und dann an geeigneten Stellen die gepufferten Daten in den eigentlichen Socket schreibe. Diese Technik ermöglicht es mir, große Datenpakete zu verwenden, die Fragmentierung zu reduzieren und die CPU-Auslastung sowohl im Benutzerland als auch auf Kernelebene zu reduzieren.

mdk
quelle
4
Geniale Antwort! Mein Problem war etwas anders, dh ich habe versucht, Sitzungsinformationen aus einem Sitzungsspeicher auf Anwendungsebene über PHP nach Redis zu verschieben. Aus irgendeinem Grund konnte ich nicht mehr als 28230 Sitzungen hinzufügen, ohne viel Schlaf auf einmal hinzuzufügen, ohne dass Fehler in PHP oder Redis-Protokollen auftraten. Wir haben uns einen ganzen Tag lang den Kopf gebrochen, bis ich dachte, das Problem liege nicht in PHP / Redis, sondern in der TCP / IP-Ebene, die die beiden verbindet, und kam zu dieser Antwort. Hat es geschafft, das Problem in kürzester Zeit zu beheben :) Vielen Dank!
s1d
27
Vergessen Sie nicht, dass wir immer über IP + Port sprechen. Sie können "unbegrenzte" Sockets für Port XY von vielen verschiedenen IPs aus öffnen. Das Limit von 470 gilt nur für gleichzeitig geöffnete Sockets mit derselben IP. Eine andere IP kann über eigene 470 Verbindungen zu denselben Ports verfügen.
Marki555
6
@ Marki555: Dein Kommentar ist SEHR RICHTIG. Anwendungen, die zum Generieren und Aufrechterhalten einer großen Anzahl von ausgehenden Verbindungen entwickelt wurden, müssen über ein "Bewusstsein" für verfügbare IPs zum Erstellen ausgehender Verbindungen verfügen und dann mithilfe eines "Round-Robin-Algorithmus" angemessen an diese IP-Adressen gebunden und gewartet werden eine "Anzeigetafel".
Mdk
8
Diese Antwort hat Fehler. Erstens gilt net.ipv4.tcp_fin_timeout nur für den Status FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). Zweitens ist, wie @Eric sagte, "470 Sockets zu einem bestimmten Zeitpunkt" nicht korrekt.
Sharvanath
3
@mdk: Ich bin mit diesem Berechnungsteil nicht klar (61000 - 32768) / 60 = 470 sockets per second. Können Sie das bitte näher erläutern?
Tom Taylor
64

Es gibt einige Variablen, um die maximale Anzahl von Verbindungen festzulegen. Höchstwahrscheinlich gehen Ihnen zuerst die Dateinummern aus. Überprüfen Sie ulimit -n. Danach gibt es Einstellungen in / proc, aber diese sind standardmäßig Zehntausende.

Noch wichtiger ist, dass Sie etwas falsch machen. Eine einzelne TCP-Verbindung sollte in der Lage sein, die gesamte Bandbreite zwischen zwei Parteien zu nutzen. wenn nicht:

  • Überprüfen Sie, ob Ihre TCP-Fenstereinstellung groß genug ist. Die Linux-Standardeinstellungen sind für alles gut, außer für wirklich schnelle Inet-Verbindungen (Hunderte von Mbit / s) oder schnelle Satellitenverbindungen. Was ist Ihr Produkt für die Verzögerung der Bandbreite *?
  • Überprüfen Sie den Paketverlust mithilfe von Ping mit großen Paketen ( ping -s 1472...)
  • Überprüfen Sie die Geschwindigkeitsbegrenzung. Unter Linux ist dies mit konfigurierttc
  • Bestätigen Sie, dass die Bandbreite, von der Sie glauben, dass sie tatsächlich vorhanden ist, z. iperf
  • Bestätigen Sie, dass Ihr Protokoll korrekt ist. Denken Sie an die Latenz.
  • Wenn dies ein Gigabit + LAN ist, können Sie Jumbo-Pakete verwenden? Bist du?

Möglicherweise habe ich falsch verstanden. Vielleicht machst du so etwas wie Bittorrent, wo du viele Verbindungen brauchst. In diesem Fall müssen Sie herausfinden, wie viele Verbindungen Sie tatsächlich verwenden (versuchen Sie es netstatoder lsof). Wenn diese Zahl erheblich ist, können Sie:

  • Haben Sie viel Bandbreite, z. B. 100 MBit / s +. In diesem Fall müssen Sie möglicherweise tatsächlich die ulimit -n. Trotzdem sind ~ 1000 Verbindungen (Standard auf meinem System) ziemlich viele.
  • Haben Sie Netzwerkprobleme, die Ihre Verbindungen verlangsamen (z. B. Paketverlust)?
  • Lassen Sie sich von etwas anderem verlangsamen, z. B. der E / A-Bandbreite, insbesondere wenn Sie suchen. Hast du nachgesehen iostat -x?

Wenn Sie einen NAT-Router für Endverbraucher (Linksys, Netgear, DLink usw.) verwenden, achten Sie darauf, dass Sie dessen Fähigkeiten mit Tausenden von Verbindungen möglicherweise überschreiten.

Ich hoffe das hilft. Sie stellen wirklich eine Netzwerkfrage.

derobert
quelle
16

Um die Antwort von derobert zu verbessern,

Sie können das Verbindungslimit Ihres Betriebssystems bestimmen, indem Sie nf_conntrack_max catten.

Zum Beispiel: cat / proc / sys / net / netfilter / nf_conntrack_max

Mit dem folgenden Skript können Sie die Anzahl der TCP-Verbindungen zu einem bestimmten Bereich von TCP-Ports zählen. Standardmäßig 1-65535.

Dadurch wird bestätigt, ob Sie Ihr Betriebssystemverbindungslimit voll ausschöpfen.

Hier ist das Skript.

#!/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}'
whitehat237
quelle
3
which awkist dein Freund, um den Weg zu awk zu bestimmen, SunOS hat auch einen Link dazu :)
Panagiotis Moustafellos
2
@ PanagiotisM. In diesem Fall können Sie nur whichdas Programm PATHverwenden, awkanstatt den vollständigen Pfad anzugeben. (Das heißt, ich bin nicht sicher, ob die Lösung im Skript der Perfektion näher kommt, aber darum geht es im Skript nicht).
Michael Krelin - Hacker
5
Ich mag es, wie dieses Skript ballistisch ist, um den awkStandort zu bestimmen , gehe aber davon aus, dass die Shell immer ist /bin/bash (Pro-Tipp: AIX5 / 6 hat standardmäßig nicht einmal Bash).
Kubanczyk
Ist die awkErkennung nützlich? Persönlich würde ich einfach annehmen , um ein korrektes habe PATHaber eine vernünftige Alternative könnte sein , /usr/bin/env awkund /usr/bin/env bashjeweils. Für das, was es wert ist, hat es den falschen Speicherort auf meinem Linux-System. Es ist /usr/bin/awknicht in/bin/awk
Wolph
1
Wenn ich dieses Skript ausführe, erhalte ich 798. Was bedeutet das?
10

In einer Anwendungsebene kann ein Entwickler Folgendes tun:

Von der Serverseite:

  1. Überprüfen Sie, ob der Load Balancer (falls vorhanden) ordnungsgemäß funktioniert.

  2. Verwandeln Sie langsame TCP-Zeitüberschreitungen in 503 Fast Immediate-Antwort. Wenn Sie den Load Balancer ordnungsgemäß ausführen, sollte er die zu bedienende Arbeitsressource auswählen und ist besser, als dort mit unerwarteten Fehlermassagen zu hängen.

Beispiel: Wenn Sie einen Knotenserver verwenden, können Sie ab npm toobusy verwenden. Implementierung so etwas wie:

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

Warum 503? Hier sind einige gute Erkenntnisse zur Überlastung: http://ferd.ca/queues-don-t-fix-overload.html

Wir können auch auf Kundenseite arbeiten:

  1. Versuchen Sie, Anrufe im Stapel zu gruppieren, den Datenverkehr und die Gesamtzahl der Anfragen zwischen Client und Server zu reduzieren.

  2. Versuchen Sie, einen Cache in der Mitte der Ebene zu erstellen, um unnötige doppelte Anforderungen zu verarbeiten.

Kev
quelle