TCP/IP - решение C10K с помощью потока на клиентский подход
После прочтения известной статьи C10k и поиска в Интернете о том, как все сложилось с момента ее написания, я хотел бы знать, возможно ли сегодня стандартный сервер для обработки > 10000 одновременных соединений с использованием потока на соединение (возможно, с помощью пула потоков, чтобы избежать процесса создания/убийства).
Некоторые детали, которые могут повлиять на подход к проблеме:
- Вход, промежуточная обработка и вывод.
- Длина каждого соединения.
- Технические характеристики сервера (ядра, процессоры, оперативная память и т.д.)
- Объединение этой системы с альтернативными методами, такими как AIO, опрос, зеленые темы и т.д.
Очевидно, я не эксперт в этом вопросе, поэтому любые замечания или советы будут высоко оценены:)
Ответы
Ответ 1
Совершенно верно. Стандартный сервер может обрабатывать более 10K одновременных соединений, используя модель с одним потоком для каждого соединения. Я создал такое приложение, и пять лет назад он работал с более чем 50K параллельными подключениями к каждому процессу на стандартном сервере Linux. В настоящее время должно быть возможно запустить одно и то же приложение с более чем 250K параллельными соединениями на текущем оборудовании.
Следует иметь в виду лишь несколько вещей:
- Повторное использование потоков с помощью пула потоков. Нет необходимости убивать потоки, если они не используются, потому что использование ресурсов должно быть оптимизировано для пиковых нагрузок.
- Размер стека: по умолчанию каждый поток Linux резервирует 8 МБ для своего стека. Это составляет до 80 ГБ для потоков 10K. Вы должны установить размер стека по умолчанию для некоторого значения между 64k и 512k, что не является проблемой, поскольку большинство приложений не требуют более глубоких стеков вызовов.
- Если соединения недолговечны, оптимизируйте новые соединения, создав несколько сокетов на одной конечной точке с опцией
SO_REUSEPORT
.
- Увеличьте пользовательские пределы:
open files
(по умолчанию 1.024), max user processes
- Увеличение системных ограничений, например.
/proc/sys/kernel/pid_max
(по умолчанию 32K), /proc/sys/kernel/threads-max
и /proc/sys/vm/max_map_count
(по умолчанию 65K).
Приложение, упомянутое выше, было первоначально разработано для обработки только 2K параллельных соединений. Однако с ростом использования нам не пришлось вносить существенные изменения в код, чтобы масштабировать до 50K соединений.
Ответ 2
Вам может понравиться недавняя последующая работа по теме: Секрет на 10 миллионов параллельных подключений - Ядро - это проблема, а не решение.
Ответ 3
Обычными подходами для серверов являются: (a) поток на соединение (часто с пулом потоков) или (b) однопоточная с асинхронным IO (часто с epoll или kqueue). Я думаю, что некоторые элементы этих подходов могут и часто должны быть объединены для использования асинхронного ввода-вывода (с epoll или kqueue), а затем передать запрос соединения в пул потоков для обработки. Этот подход объединил бы эффективную отправку асинхронного ввода-вывода с parallelism, предоставляемым пулом потоков.
Я написал такой сервер для развлечения (на С++), который использует epoll для Linux и kqueue на FreeBSD и OSX вместе с пулом потоков. Мне просто нужно запустить его в своих шагах для тяжелых испытаний, выполнить некоторую очистку кода, а затем выбросить его на github (надеюсь, скоро).