Увеличение максимального количества соединений TCP / IP в Linux


214

Я программирую сервер, и кажется, что мое количество подключений ограничено, поскольку пропускная способность не насыщается, даже если я установил количество подключений как «неограниченное».

Как я могу увеличить или исключить максимальное количество соединений, которые может одновременно открывать мой Ubuntu Linux box? ОС ограничивает это, или это маршрутизатор или провайдер? Или что-то еще?


2
@Software Monkey: Я все равно ответил на это, потому что надеюсь, что это может пригодиться тому, кто на самом деле пишет сервер в будущем.
Дероберт

1
@derobert: Я видел это +1. На самом деле, у меня была та же мысль после моего предыдущего комментария, но я решил оставить комментарий.
Лоуренс Дол

Ответы:


396

На максимальное количество соединений влияют определенные ограничения как на стороне клиента, так и на стороне сервера, хотя и немного по-разному.

На стороне клиента: увеличьте диапазон эфермального порта и уменьшитеtcp_fin_timeout

Чтобы узнать значения по умолчанию:

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

Диапазон внешних портов определяет максимальное количество исходящих сокетов, которое хост может создать с определенного IP-адреса. fin_timeoutОпределяет минимальное время эти розетки будет находиться в TIME_WAITсостоянии (непригодным для использования после того , как используется один раз). Обычные системные настройки по умолчанию:

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

Это в основном означает, что ваша система не может постоянно гарантировать больше (61000 - 32768) / 60 = 470сокетов в секунду. Если вас это не устраивает, вы можете начать с увеличения port_range. Установка диапазона 15000 61000довольно распространена в наши дни. Вы можете еще больше увеличить доступность, уменьшив fin_timeout. Предположим, что вы делаете оба, вы должны видеть более 1500 исходящих подключений в секунду, с большей готовностью.

Чтобы изменить значения :

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

Вышесказанное не следует интерпретировать как факторы, влияющие на способность системы устанавливать исходящие соединения в секунду. Но скорее эти факторы влияют на способность системы обрабатывать параллельные соединения устойчивым образом в течение больших периодов «активности».

Значения Sysctl по умолчанию в стандартном окне Linux для tcp_tw_recycle& tcp_tw_reuseбудут

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

Они не разрешают соединение из «используемого» сокета (в состоянии ожидания) и заставляют сокеты длиться полный time_waitцикл. Я рекомендую установить:

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

Это позволяет быстро переключать сокеты в time_waitсостояние и повторно использовать их. Но перед тем, как вы сделаете это изменение, убедитесь, что оно не конфликтует с протоколами, которые вы используете для приложения, которому нужны эти сокеты. Обязательно прочитайте пост «Как справиться с TCP-TIME-WAIT» от Винсента Берната, чтобы понять последствия. Эта net.ipv4.tcp_tw_recycle опция довольно проблематична для общедоступных серверов, поскольку она не будет обрабатывать соединения от двух разных компьютеров за одним и тем же устройством NAT , что является проблемой, которую трудно обнаружить и которая ждет вас. Обратите внимание, что net.ipv4.tcp_tw_recycleбыло удалено из Linux 4.12.

На стороне сервера:net.core.somaxconn значение играет важную роль. Это ограничивает максимальное количество запросов в очереди к сокету прослушивания. Если вы уверены в возможностях вашего серверного приложения, увеличьте его значение по умолчанию со 128 до 128 - 1024. Теперь вы можете воспользоваться этим увеличением, изменив переменную listen backlog в вызове listen вашего приложения на равное или большее целое число.

sysctl net.core.somaxconn=1024

txqueuelenПараметр ваших карт Ethernet также играют свою роль. Значения по умолчанию - 1000, поэтому увеличьте их до 5000 или даже больше, если ваша система справится с этим.

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

Аналогичным образом увеличьте значения для net.core.netdev_max_backlogи net.ipv4.tcp_max_syn_backlog. Их значения по умолчанию 1000 и 1024 соответственно.

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

Теперь не забудьте запустить как клиентские, так и серверные приложения, увеличивая значения FD в оболочке.

Помимо вышесказанного, еще одна популярная техника, используемая программистами, заключается в сокращении количества вызовов tcp-записи . Я предпочитаю использовать буфер, в который я помещаю данные, которые я хочу отправить клиенту, а затем в соответствующих точках записываю буферизованные данные в реальный сокет. Этот метод позволяет мне использовать большие пакеты данных, уменьшить фрагментацию, уменьшить загрузку процессора как на уровне пользователя, так и на уровне ядра.


4
Блестящий ответ! Моя проблема была немного другой, то есть я пытался переместить информацию о сеансе из хранилища сеансов уровня приложения в redis через PHP. По какой-то причине я не мог добавить более 28230 сессий, не добавляя много сна за один раз, без ошибок ни в php, ни в журналах redis. Мы ломали голову над этим целый день, пока я не подумал, что, возможно, проблема не в php / redis, а в слое tcp / ip, соединяющем их, и пришел к этому ответу. Удалось исправить проблему в кратчайшие сроки после этого :) Большое спасибо!
2013 г.

27
Не забывайте, что мы всегда говорим о IP + порту. Вы можете иметь «неограниченные» сокеты, открытые для порта XY с разных IP-адресов. Ограничение 470 применяется к одновременно открытым сокетам только для одного и того же IP. Другой IP может иметь свои 470 подключений к тем же портам.
Marki555

6
@ Marki555: Ваш комментарий очень правильный. Приложения, разработанные для создания и поддержки большого количества исходящих соединений, должны иметь «осведомленность» о доступных IP-адресах для создания исходящих соединений, а затем должны соответствующим образом связываться с этими IP-адресами, используя своего рода «алгоритм циклического перебора», и поддерживать «Табло».
MDK

8
Этот ответ имеет ошибки. Прежде всего, net.ipv4.tcp_fin_timeout предназначен только для состояния FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). Во-вторых, как сказал @Eric, «470 сокетов в любой момент времени» не является правильным.
Шарванатх

3
@mdk: мне не совсем понятна эта часть расчета (61000 - 32768) / 60 = 470 sockets per second. Можете ли вы уточнить это?
Том Тейлор

64

Есть пара переменных, чтобы установить максимальное количество соединений. Скорее всего, у вас заканчиваются номера файлов в первую очередь. Проверьте ulimit -n. После этого в / proc есть настройки, но они по умолчанию равны десяткам тысяч.

Что еще более важно, кажется, что вы делаете что-то не так. Одно TCP-соединение должно иметь возможность использовать всю полосу пропускания между двумя сторонами; если это не так:

  • Проверьте, достаточно ли велика настройка окна TCP. Стандартные настройки Linux хороши для всего, кроме очень быстрой инет-связи (сотни Мбит / с) или быстрой спутниковой связи. Какова ваша пропускная способность * задержка продукта?
  • Проверьте потерю пакетов с помощью ping с большими пакетами (ping -s 1472 ...)
  • Проверьте ограничение скорости. В Linux это настроено сtc
  • Убедитесь, что полоса пропускания, которую вы считаете существующей, действительно существует, например, iperf
  • Подтвердите, что ваш протокол вменяемый. Запомни латентность.
  • Если это гигабит + локальная сеть, можете ли вы использовать гигантские пакеты? Ты?

Возможно, я неправильно понял. Может быть, вы делаете что-то вроде Bittorrent, где вам нужно много соединений. Если это так, вам нужно выяснить, сколько соединений вы на самом деле используете (попробуйте netstatили lsof). Если это число является существенным, вы можете:

  • Имеют большую пропускную способность, например, 100 Мбит / с +. В этом случае, возможно , на самом деле нужно вверх по ulimit -n. Тем не менее, ~ 1000 подключений (по умолчанию в моей системе) довольно много.
  • Проблемы с сетью, которые замедляют ваши соединения (например, потеря пакетов)
  • Есть что-то еще, что замедляет вас, например, пропускная способность ввода-вывода, особенно если вы ищете. Вы проверяли iostat -x?

Кроме того, если вы используете NAT-маршрутизатор потребительского уровня (Linksys, Netgear, DLink и т. Д.), Имейте в виду, что вы можете превзойти его возможности с тысячами соединений.

Я надеюсь, что это поможет. Вы действительно задаете сетевой вопрос.


16

Чтобы улучшить ответ Дерберта,

Вы можете определить, какое ограничение на количество подключений к вашей ОС вы можете, выполнив команду nf_conntrack_max.

Например: cat / proc / sys / net / netfilter / nf_conntrack_max

Вы можете использовать следующий скрипт для подсчета количества соединений tcp с заданным диапазоном портов tcp. По умолчанию 1-65535.

Это подтвердит, превышаете ли вы максимальный лимит соединения с вашей ОС.

Вот сценарий.

#!/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ваш друг, чтобы определить путь к awk, SunOS также имеет ссылку на него :)
Panagiotis Moustafellos

2
@PanagiotisM. whichполагается на программу, в PATHкоторой вы можете просто использовать awkвместо предоставления полного пути. (при этом я не уверен, что решение в сценарии ближе к совершенству, но это не то, о чем сценарий).
Майкл Крелин - хакер

5
Мне нравится, как этот сценарий баллистичен для определения awkместоположения, но предполагает, что оболочка всегда /bin/bash (pro tip: AIX5 / 6 даже не имеет bash по умолчанию).
Кубанчик

awkПолезно ли обнаружение? Лично я бы просто предположил, что есть правильная, PATHно разумная альтернатива может быть /usr/bin/env awkи /usr/bin/env bashсоответственно. Что бы это ни стоило, в моей системе Linux неправильно указано местоположение. Это /usr/bin/awkне/bin/awk
Вольф

1
когда я запускаю этот скрипт, я получаю 798, что это значит?

10

На уровне приложения разработчик может сделать следующее:

Со стороны сервера:

  1. Проверьте, правильно ли работает балансировщик нагрузки (если есть).

  2. Превратите медленные тайм-ауты TCP в 503 Fast Immediate: если вы правильно работаете с балансировщиком нагрузки, он должен выбрать рабочий ресурс для обслуживания, и это лучше, чем зависать там с неожиданными сообщениями об ошибках.

Например: если вы используете сервер узлов, вы можете использовать toobusy из npm. Реализация что-то вроде:

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

Почему 503? Вот некоторые хорошие идеи для перегрузки: http://ferd.ca/queues-don-t-fix-overload.html

Мы можем также поработать на стороне клиента:

  1. Попробуйте сгруппировать звонки в пакетном режиме, уменьшить трафик и общее количество запросов по ч / б клиенту и серверу.

  2. Попробуйте построить кэш среднего уровня для обработки ненужных дубликатов запросов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.