Увеличение максимального количества соединений TCP / IP в Linux
Я программирую сервер, и кажется, что мое количество подключений ограничено, поскольку пропускная способность не насыщается, даже если я установил количество подключений как "неограниченное".
Как я могу увеличить или исключить максимальное количество подключений, которое мой Ubuntu Linux может открывать одновременно? ОС ограничивает это, или это маршрутизатор или провайдер? Или что-то еще?
5 ответов
На максимальное количество соединений влияют определенные ограничения как на стороне клиента, так и на стороне сервера, хотя и немного по-разному.
На стороне клиента: увеличьте диапазон эфермального порта и уменьшите 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-записи. Я предпочитаю использовать буфер, в который я помещаю данные, которые я хочу отправить клиенту, а затем в соответствующих точках записываю буферизованные данные в реальный сокет. Этот метод позволяет мне использовать большие пакеты данных, уменьшить фрагментацию, уменьшить загрузку процессора как на уровне пользователя, так и на уровне ядра.
Есть пара переменных для установки максимального количества соединений. Скорее всего, у вас заканчиваются номера файлов в первую очередь. Проверьте 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 и т. Д.), Имейте в виду, что вы можете превзойти его возможности с тысячами соединений.
Я надеюсь, что это поможет. Вы действительно задаете сетевой вопрос.
Чтобы улучшить ответ Дерберта,
Вы можете определить, какое ограничение на количество подключений к вашей ОС вы можете, выполнив команду 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}'
На уровне приложения разработчик может сделать следующее:
Со стороны сервера:
Проверьте, правильно ли работает балансировщик нагрузки (если есть).
Превратите медленные тайм-ауты 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
Мы можем также поработать на стороне клиента:
Попробуйте группировать звонки в пакетном режиме, уменьшить трафик и общее количество запросов ч / б клиент и сервер.
Попробуйте построить кэш среднего уровня для обработки ненужных дубликатов запросов.
я пытаюсь решить эту проблему в 2022 году на балансировщиках нагрузки, и один из способов, который я нашел, - это подключить еще один IPv4 (или, в конечном итоге, IPv6) к сетевой карте, поэтому лимит теперь удвоен. Конечно, вам нужно настроить второй IP-адрес для службы, которая пытается подключиться к машине (в моем случае это другая запись DNS).