Оптимизация пропускной способности сети Linux с помощью настройки параметров sysctl TCP/IP
Практическая настройка TCP sysctl в Linux для повышения пропускной способности, буферов, управления перегрузкой и безопасного тестирования.
Оптимизация пропускной способности сети Linux с помощью настройки параметров sysctl TCP/IP
Настройка пропускной способности сети Linux начинается с скучного вопроса: что именно медленно? Сервер, который выдает максимум 300 Мбит/с на канале 10 Гбит/с, может иметь проблему с окном TCP, проблему с диском, проблему с прерываниями ЦП, плохую настройку виртуального сетевого интерфейса, проблему с потерей пакетов или приложение, которое отправляет данные крошечными фрагментами. Настройка sysctl помогает только с некоторыми из них.
Вот почему я отношусь к изменениям sysctl TCP/IP как к контролируемым экспериментам, а не как к волшебным рецептам производительности. Начните с базового уровня, измените одну небольшую группу настроек, протестируйте снова и ведите записи. Если вы скопируете огромный блок настроек из интернета в /etc/sysctl.conf, вы можете улучшить одну рабочую нагрузку и незаметно навредить другой.
Приведенные ниже настройки полезны, когда вы запускаете высокопроизводительные сервисы: репозитории артефактов, серверы резервного копирования, шлюзы объектного хранения, загруженные обратные прокси, реплики баз данных, передающие большие журналы, или хосты Linux, передающие трафик по каналам большой протяженности. Они вряд ли помогут, если узким местом является ЦП шифрования TLS, медленное хранилище, блокировки приложений, ограничения облачного провайдера или потеря пакетов за пределами хоста.
Перед любыми изменениями соберите быстрый базовый уровень:
ip -s link
ss -s
nstat -az | egrep 'TcpRetransSegs|TcpExtTCPLoss|TcpExtTCPTimeouts|TcpExtListenOverflows'
sar -n DEV,TCP,ETCP 1 10
iperf3 -c test-host -P 4 -t 30
Если вы видите рост повторных передач, сначала исправьте потери, прежде чем увеличивать буферы. Если ЦП уже загружен на 100% в top, mpstat или perf, sysctl могут скрыть симптом, но не устранить узкое место. Если iperf3 работает быстро, а ваше приложение медленно, сначала посмотрите на путь приложения, прежде чем настраивать ядро.
Как sysctl вписывается в настройку сети
sysctl предоставляет доступ к параметрам ядра во время работы системы. Сетевые настройки обычно находятся в net.ipv4, net.ipv6 и net.core. Вы можете прочитать значение так:
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_rmem
sysctl net.core.rmem_max
Вы можете протестировать временное изменение так:
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
Временные изменения исчезают после перезагрузки. Постоянные изменения должны находиться в выделенном файле, например /etc/sysctl.d/90-network-throughput.conf, а не разбросаны по /etc/sysctl.conf без объяснений.
sudo install -m 0644 /dev/null /etc/sysctl.d/90-network-throughput.conf
sudo editor /etc/sysctl.d/90-network-throughput.conf
sudo sysctl --system
Используйте отдельный файл, потому что откат прост: переместите файл и снова выполните sudo sysctl --system. Это важно, когда настройка ведет себя плохо под производственным трафиком.
Буферы TCP: дайте длинным соединениям пространство для дыхания
Первое, на что смотрят люди, — это размер буферов. TCP нуждается в достаточном пространстве окна отправки и приема, чтобы данные оставались в пути, пока подтверждения путешествуют по сети. Полезная ментальная модель — это произведение задержки на пропускную способность: высокоскоростное соединение с высокой задержкой требует больше данных в пути, чем низкоскоростное соединение в локальной сети.
Например, передача 1 Гбит/с по пути в центре обработки данных с задержкой 1 мс требует гораздо меньше данных в пути, чем передача 1 Гбит/с по WAN-каналу с задержкой 70 мс. Если окно приема слишком мало, отправитель приостанавливается, даже если канал свободен.
Linux использует массивы из трех значений для настройки памяти TCP:
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_wmem = 4096 131072 33554432
Три числа — это минимальный, стандартный и максимальный размеры буфера на сокет в байтах. Точные значения должны соответствовать вашей рабочей нагрузке, бюджету памяти и поведению ядра. В приведенном выше примере максимальный размер увеличен до 32 МиБ, что часто достаточно для загруженных серверов без излишеств. Некоторые системы с большой протяженностью или интенсивным хранением используют большие значения, но это следует тестировать с реальным трафиком.
Ограничения net.core ограничивают буферы сокетов:
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
Если tcp_rmem говорит, что TCP может вырасти до 32 МиБ, но net.core.rmem_max намного ниже, на практике побеждает более низкое ограничение. Держите ограничения согласованными с максимумами TCP, если у вас нет причин поступать иначе.
Не увеличивайте буферы вслепую на машине с большим количеством одновременных соединений. Файловый сервер с несколькими большими потоками может позволить себе большие буферы на поток. Прокси, обрабатывающий сотни тысяч соединений, может быстро сжечь память, если сделать каждый сокет подходящим для огромных буферов.
Автонастройка уже выполняет некоторую работу
Современные ядра Linux уже автоматически настраивают буферы TCP. Это означает, что вам обычно не нужно устанавливать огромные фиксированные буферы сокетов в приложении. Ядро увеличивает буферы, когда соединение выигрывает от большего пространства.
Ваша задача — в основном убедиться, что потолок не слишком низок. Если пропускная способность низкая на длинном толстом канале и ss -tin показывает маленькие окна приема или отправитель заблокирован получателем, увеличение tcp_rmem, tcp_wmem, rmem_max и wmem_max может помочь.
Проверьте активные соединения с помощью:
ss -tin dst <peer-ip>
Ищите такие поля, как cwnd, rtt, rto, bytes_acked, bytes_received и счетчики повторных передач. Они рассказывают лучшую историю, чем один тест скорости.
Управление перегрузкой: CUBIC, BBR и реальность
Алгоритм управления перегрузкой определяет, как TCP увеличивает или уменьшает скорость отправки. На многих системах Linux CUBIC используется по умолчанию и хорошо работает для обычного интернет-трафика и трафика центров обработки данных. BBR может улучшить пропускную способность и задержку на некоторых каналах с потерями или большой протяженностью, поскольку он моделирует пропускную способность узкого места и время кругового пути вместо реакции только на потерю пакетов.
Проверьте доступные алгоритмы:
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
Включите BBR только в том случае, если ваше ядро его поддерживает:
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
Для постоянства:
net.ipv4.tcp_congestion_control = bbr
Некоторые системы также требуют планировщик пакетов с справедливой очередью для хорошего поведения BBR:
net.core.default_qdisc = fq
Не предполагайте, что BBR всегда быстрее. Он может изменить справедливость по отношению к другим потокам, и разные версии BBR ведут себя по-разному в разных ядрах. Тестируйте его на том же шаблоне трафика, который вам важен: много маленьких вызовов API, несколько массовых передач, реплицированный трафик базы данных или смешанная производственная нагрузка.
Очереди прослушивания: исправляйте потери, прежде чем они станут загадками
Проблемы с пропускной способностью иногда проявляются как сбои соединения во время всплесков трафика. Если сервис принимает новые TCP-соединения медленнее, чем клиенты их создают, очереди ядра заполняются.
Соответствующие настройки:
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
somaxconn ограничивает очередь завершенных соединений, запрашиваемую приложениями через listen(2). tcp_max_syn_backlog влияет на емкость очереди полуоткрытых SYN. Их увеличение может помочь загруженным веб-серверам, прокси и балансировщикам нагрузки, но приложение также должно запрашивать достаточно большой backlog. Nginx, HAProxy, Envoy и серверы приложений часто имеют свои собственные настройки backlog.
Следите за переполнениями:
nstat -az | egrep 'ListenOverflows|ListenDrops|Syncookies'
ss -ltn
Если ListenOverflows растет, очереди ядра не справляются. Если ЦП насыщен или приложение заблокировано нижестоящими сервисами, увеличение размеров очередей может временно уменьшить ошибки клиентов, но не исправит сервис.
Backlog и обработка пакетов
net.core.netdev_max_backlog контролирует, сколько пакетов может ожидать во входной очереди, когда ядро получает пакеты быстрее, чем может их обработать.
net.core.netdev_max_backlog = 250000
Это может помочь на высокоскоростных интерфейсах во время всплесков, особенно при виртуализированной сети. Это также может увеличить задержку, если вы превратите хост в большую комнату ожидания пакетов. Сначала проверьте потери на интерфейсе:
ip -s link show dev eth0
ethtool -S eth0 | egrep 'drop|err|timeout|miss|fifo'
Если потери на уровне драйвера растут, также проверьте размеры колец NIC, распределение прерываний, очереди RSS и привязку к ЦП. Это выходит за рамки sysctl, но часто они важнее, чем буферы TCP на хостах с 10 Гбит/с и выше.
TIME_WAIT и истощение портов
Высокопроизводительные клиенты, прокси и исполнители заданий могут исчерпать эфемерные порты или накопить много сокетов в состоянии TIME_WAIT. Будьте осторожны, потому что старые советы по настройке могут быть вредными.
Проверьте текущий диапазон:
sysctl net.ipv4.ip_local_port_range
ss -tan state time-wait | wc -l
Разумной настройкой на стороне клиента является расширение диапазона эфемерных портов:
net.ipv4.ip_local_port_range = 10240 60999
Избегайте старых советов, которые рекомендуют tcp_tw_recycle; он был удален из Linux, потому что нарушал работу легитимного трафика, особенно за NAT. tcp_tw_reuse существует во многих ядрах, но его поведение со временем изменилось. Не включайте его как настройку пропускной способности по умолчанию. Если вы думаете, что он вам нужен, тщательно протестируйте ваше точное ядро и шаблон трафика.
Для серверов куча сокетов TIME_WAIT часто является нормой. Для клиентов истощение портов обычно означает, что вам нужен пул соединений, keep-alive, HTTP/2, меньше короткоживущих исходящих соединений или больше исходных IP-адресов.
Консервативный начальный файл
Вот практическая отправная точка для высокопроизводительного сервера. Она намеренно не экстремальна:
# /etc/sysctl.d/90-network-throughput.conf
# Более высокие потолки автонастройки TCP для путей с высокой пропускной способностью или большой задержкой.
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_wmem = 4096 131072 33554432
# Более длинные очереди для пикового входящего трафика.
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
net.core.netdev_max_backlog = 250000
# Опционально: тестировать перед глобальным включением.
# net.core.default_qdisc = fq
# net.ipv4.tcp_congestion_control = bbr
Примените:
sudo sysctl --system
Затем измерьте снова. Используйте тот же размер теста, временное окно, количество параллельных потоков и сетевой путь. Тест "до и после", который меняет пять переменных, не является доказательством.
Распространенные ошибки
Первая ошибка — настройка на пути с потерями. TCP воспринимает потери как перегрузку. Большие буферы могут немного увеличить пропускную способность, но они также могут увеличить задержку и скрыть реальную проблему. Сначала исправьте плохие кабели, перегруженные виртуальные коммутаторы, полицейский контроль пакетов, несоответствие MTU и нестабильные VPN-пути.
Вторая ошибка — предположение, что iperf3 -P 8 доказывает производительность приложения. Параллельные потоки могут заполнить канал, даже если одно реальное соединение приложения не может. Это полезная информация, но это не вся история.
Третья ошибка — установка огромных буферов на общих хостах. Более высокие потолки — это нормально, когда ядро увеличивает буферы только по мере необходимости, но давление памяти меняет все. Отслеживайте free, slabtop, память TCP и память приложений после изменений.
Четвертая ошибка — забыть об откате. Сохраните предыдущие значения в вашей заявке на изменение или runbook:
sysctl -a | egrep 'net.core.rmem_max|net.core.wmem_max|net.ipv4.tcp_rmem|net.ipv4.tcp_wmem|net.ipv4.tcp_congestion_control'
Когда sysctl не является решением
Если одно ядро ЦП загружено, а другие простаивают, посмотрите на обработку прерываний, RSS, RPS/XPS и многопоточность приложения. Если высока загрузка диска, сеть может ждать хранилище. Если TLS потребляет ЦП, тестируйте с шифрованием и без него и рассмотрите оборудование, выбор шифра или повторное использование соединений. Если на пути находится Kubernetes или облачный балансировщик нагрузки, проверьте ограничения на уровне сервиса и таблицы conntrack.
Для хостов с интенсивным NAT также проверьте conntrack:
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
Это не настройка пропускной способности TCP, но истощение conntrack может выглядеть как случайная медленная работа сети или разрывы соединений.
Тестирование без самообмана
Используйте iperf3 как сетевой инструмент, а не как доказательство того, что приложение исправлено. Тест с одним потоком полезен, потому что он показывает, что может сделать одно TCP-соединение:
iperf3 -c test-host -t 30
Параллельный тест показывает, может ли канал быть заполнен несколькими потоками:
iperf3 -c test-host -P 8 -t 30
Если параллельные потоки быстры, а один поток медленный, посмотрите на управление перегрузкой, рост окна TCP, RTT и потерю пакетов. Если оба медленные, смотрите ниже: ошибки интерфейса, ограничения пропускной способности облака, насыщение ЦП, MTU, проверка брандмауэра или хранилище за отправителем и получателем.
Держите тестовый путь реалистичным. Тестирование двух хостов в одной стойке не скажет вам много о задаче резервного копирования, пересекающей регионы. Тестирование с крошечным файлом не выявит установившуюся пропускную способность. Тестирование через VPN может измерять больше VPN-устройство, чем Linux TCP.
После каждого изменения фиксируйте те же счетчики:
nstat -az > /tmp/nstat-after.txt
ss -s
sar -n DEV,TCP,ETCP 1 10
Полезный результат — это не просто "число выросло". Вы хотите знать, упали ли повторные передачи, перестали ли переполняться очереди, остался ли ЦП разумным и не стала ли задержка хуже для маленьких запросов.
Хорошая настройка сети Linux измеряется и обратима. Увеличивайте потолки буферов TCP, когда путь требует больших окон. Тестируйте управление перегрузкой, а не предполагайте, что один алгоритм выигрывает везде. Увеличивайте очереди прослушивания, когда видите потери в очередях, и исправляйте приложение, если оно не может принимать достаточно быстро. sysctl полезен, но это один слой в большой системе.