Збільшення максимальної кількості з'єднань TCP / IP в Linux


214

Я програмую сервер, і, схоже, кількість моїх з'єднань обмежена, оскільки пропускна здатність не насичується, навіть коли я встановив кількість підключень на "необмежену".

Як я можу збільшити або усунути максимальну кількість підключень, які може відкрити мій ящик Ubuntu Linux за раз? Операційна система це обмежує, чи це маршрутизатор чи провайдер? Або це щось інше?


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. Тепер ви можете скористатися цим збільшенням, змінивши змінну відсталого прослуховування у виклику прослуховування вашої програми на рівне або вище ціле число.

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 ulimts в оболонці.

Окрім перерахованого вище, ще одна популярна методика, яка використовується програмістами, - зменшити кількість викликів на запис tcp . Моє власне вподобання - використовувати буфер, в якому я відштовхую дані, які я хочу надіслати клієнтові, а потім у відповідних точках виписую буферизовані дані у фактичний сокет. Ця методика дозволяє використовувати великі пакети даних, зменшує фрагментацію, зменшує використання процесора як на землі користувача, так і на рівні ядра.


4
Блискуча відповідь! Моя проблема була дещо іншою, тобто я намагався перенести інформацію про сеанс із сховища сесії на рівні програми до редагування через PHP. Чомусь я не зміг додати більше 28230 сеансів без додавання багато сну за один раз, при цьому не було помічено жодних помилок ні в php, ні в журналах redis. Ми ламали голову над цим цілий день, поки я не подумав, що, можливо, проблема не в php / redis, а в шарі tcp / ip, що з'єднує два, і прийшов до цієї відповіді. Вдалося виправити проблему в найкоротші терміни після цього :) Дякую!
s1d

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 корисні для всього, крім дійсно швидкого inet-посилання (сотні Мбіт / с) або швидкого супутникового зв'язку. Який ваш продукт пропускної здатності * затримка?
  • Перевірте втрату пакету за допомогою ping з великими пакетами ( ping -s 1472...)
  • Перевірте обмеження ставок. У Linux це налаштованоtc
  • Переконайтеся, що пропускна здатність, на вашу думку, існує насправді, використовуючи, наприклад, iperf
  • Переконайтеся, що ваш протокол є здоровим. Запам’ятайте затримку.
  • Якщо це гігабіт + LAN, чи можете ви використовувати jumbo пакети? Ти?

Можливо, я неправильно зрозумів. Можливо, ви робите щось на кшталт Bittorrent, де вам потрібно багато зв’язків. Якщо так, вам потрібно розібратися, скільки підключень ви фактично використовуєте (спробуйте netstatабо lsof). Якщо ця кількість значна, ви можете:

  • Мають велику пропускну здатність, наприклад, 100 Мбіт / с. У цьому випадку вам може знадобитися збільшити ulimit -n. І все-таки ~ 1000 підключень (за замовчуванням у моїй системі) досить багато.
  • У вас є проблеми з мережею, які сповільнюють ваші з'єднання (наприклад, втрата пакетів)
  • Запропонуйте вам щось інше, наприклад пропускну здатність IO, особливо якщо ви шукаєте. Ви перевірили 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 (поради: AIX5 / 6 навіть не має баш за замовчуванням).
kubanczyk

Чи awkкорисне виявлення? Я особисто вважаю, що є правильна, PATHале розумна альтернатива може бути /usr/bin/env awkі /usr/bin/env bashвідповідно. Для чого це варто, це неправильне розташування в моїй системі Linux. Це /usr/bin/awkне так/bin/awk
Волф

1
коли я запускаю цей сценарій, я отримую 798, і що це означає?

10

На рівні програми, ось що розробник може зробити:

З боку сервера:

  1. Перевірте, чи працює балансир навантаження (якщо у вас є).

  2. Перетворіть повільні тайм-аути TCP в швидку відповідь 503, якщо ви завантажуєте роботу балансира правильно, він повинен вибрати робочий ресурс для обслуговування, і це краще, ніж висіти там з несподіваними масажами помилок.

Наприклад, якщо ви використовуєте сервер вузлів, ви можете використовувати 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. Постарайтеся групувати дзвінки в пакетному порядку, зменшіть кількість трафіку та загального числа запитів на b / w клієнта та сервера.

  2. Спробуйте створити середній шар кешу для обробки зайвих дублікатів запитів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.