Как сервер обрабатывает большое количество одновременных запросов
Что проверяют
Понимаете ли вы разницу моделей обработки и знаете ли, где узкое место на практике.
Как отвечать
Модели по возрастанию эффективности:
- поток на соединение: просто, но каждый поток стоит около мегабайта стека, а переключение контекста дорого. Тысячи соединений упираются в память и в планировщик;
- пул потоков: потоки переиспользуются, число ограничено, запросы ждут в очереди. Классическая модель сервлетов;
- событийный цикл с неблокирующим вводом-выводом: один поток обслуживает тысячи соединений через epoll или kqueue. Nginx, Node.js, Netty;
- виртуальные потоки (Java 21): код пишется в блокирующем стиле, а рантайм снимает поток с ожидания, объединяя удобство первой модели с эффективностью третьей.
Дальше по слоям: несколько экземпляров приложения за балансировщиком, keep-alive и мультиплексирование в HTTP/2, кэш, очередь для тяжёлых операций.
Что стоит сказать про реальное узкое место: обычно это не веб-сервер, а база и пул соединений к ней. Тысяча одновременных запросов не означает тысячу соединений к базе: пул на два-три десятка обслуживает их очередью, и именно там образуется затор. Отсюда практика: короткие транзакции, никаких внешних вызовов внутри них, кэширование горячих чтений, реплики для чтения.
И про измерение: пропускную способность и время ответа меряют на перцентилях, а не по среднему, иначе хвост остаётся невидимым.
Где спотыкаются
Считают, что больше потоков значит больше пропускной способности.
Забывают про пул соединений к базе.
Не различают конкурентность и параллелизм.
Меряют среднее время ответа.