Apache исторически использует префорковую модель обработки. В этой модели каждый запрос == отдельный процесс операционной системы (ОС). Он вызывает «prefork», потому что Apache разветвляет некоторые запасные процессы и обрабатывает запрос внутри. Если количество предварительно разветвленных процессов недостаточно - Apache разветвляется. Плюсы: процесс может выполнять другие модули или процессы и не заботиться о том, что они делают; минусы: каждый запрос = один процесс, слишком много используемой памяти и разветвление ОС также может быть медленным для ваших запросов.
Другая модель Apache — рабочий MPM. Почти то же самое, что и prefork, но с использованием не процессов ОС, а потоков ОС. Thread - это как бы облегченный процесс. Один процесс ОС может запускать множество потоков, используя одно пространство памяти. Рабочий MPM использовал гораздо меньше памяти, а новые потоки создавались быстрее. Минусы: модули должны поддерживать потоки, сбой модуля может привести к сбою всех потоков всего процесса ОС (но это не важно для вас, потому что вы используете apache только как обратный прокси). Другие минусы: процессор переключает контекст при переключении между потоками.
Так что да, worker намного лучше, чем prefork в вашем случае, но...
Но у нас есть Nginx :) Nginx использует другую модель (кстати, у Apache тоже есть event MPM). В этом случае у вас есть только один процесс (ну может быть несколько процессов, см. ниже). Как это устроено. Новое специальное событие запроса, процесс ОС просыпается, получает запрос, готовит ответ, записывает ответ и уходит в сон.
Вы можете сказать «вау, но это же не многозадачность» и будете правы. Но есть одно большое отличие этой модели от простой последовательной обработки запросов. Что произойдет, если вам нужно записать большие данные на медленный клиент? В синхронном режиме ваш процесс должен ждать подтверждения о получении данных и только после этого обрабатывать новый запрос. Модель событий Nginx и Apache использует асинхронную модель. Nginx говорит ОС отправить некоторый фрагмент данных, записать эти данные в буфер ОС и... уйти в сон или обработать новые запросы. Когда ОС отправит часть данных - в nginx будет отправлено специальное событие. Итак, основное отличие - Nginx не ждет ввода-вывода (например, подключение, чтение, запись), Nginx сообщает ОС, что он хочет, и ОС отправляет событие в Nginx, чем эта задача готова (сокет подключен, данные записаны или новые данные готовы к чтению). в локальном буфере). Кроме того, современные ОС могут работать с HDD асинхронно (чтение/запись) и даже отправлять файлы с HDD на TCP-сокет напрямую.
Конечно, все математические операции в этом процессе Nginx будут блокировать этот процесс и его остановку для обработки новых и существующих запросов. Но когда основным рабочим процессом является работа с сетью (обратный прокси, перенаправление запросов на FastCGI или другой внутренний сервер) плюс отправка статических файлов (тоже асинхронная) — Nginx может обслуживать тысячи одновременных запросов в одном процессе ОС! Кроме того, поскольку один процесс ОС (и один поток) - ЦП будет выполнять его в одном контексте.
Как я уже говорил, Nginx может запускать несколько процессов ОС, и каждый из этих процессов будет назначен ОС на отдельное ядро ЦП. Практически нет причин форкнуть больше процессов ОС Nginx (причина только одна: если нужно сделать какие-то блокирующие операции, а простой реверс-прокси с балансировкой бэкенда — не тот случай)
Итак, плюсы: меньшее переключение контекста процессора, меньше памяти (по сравнению с рабочим MPM тоже), быстрая обработка соединения. Дополнительные плюсы: Nginx создан как балансировщик нагрузки HTTP и имеет множество опций для него (и даже больше в коммерческом Nginx Plus). Минусы: если вам нужна сложная математика внутри процесса ОС, этот процесс будет заблокирован (но все, что вам нужно, это математика в Tomcat, поэтому Nginx только балансировщик).
PS: исправление опечатки будет позже, не вовремя. Кроме того, мой английский плохой, поэтому исправления всегда приветствуются :)
PPS: Ответьте на вопрос о номере темы TC, заданный в комментариях (был слишком длинным для публикации в качестве комментария):
Лучший способ это узнать — протестировать с помощью инструментов стресс-нагрузки. Потому что это число зависит от профиля приложения. Время отклика недостаточно, чтобы помочь ответить. Потому что, например, большая разница между 200 мс 100% математики (100% привязка к процессору) и 50 мс математики + 150 мс ожидания ответа базы данных.
Если приложение на 100% привязано к процессору - возможно, один поток на одно ядро, но в реальных случаях все приложения также тратят некоторое время на ввод-вывод (получение запроса, отправка ответа клиенту).
Если приложение работает с вводом-выводом и ему нужно ждать ответов от других служб (например, базы данных), это приложение проводит некоторое время в спящем состоянии, а ЦП может выполнять другие задачи.
Таким образом, лучшее решение для создания количества запросов, близкого к реальной нагрузке, и запуска стресс-теста, увеличивающего количество одновременных запросов (и, конечно, количество рабочих TC). Найдите приемлемое время отклика и зафиксируйте это количество потоков. Конечно, нужно проверить перед тем, что это не ошибка базы данных.
Конечно, здесь я говорю только о динамическом контенте, запросы на статические файлы с диска должны обрабатываться до tomcat (например, Nginx).
person
Dmitry MiksIr
schedule
10.09.2016