Попытайтесь повторить это сами
Как правило, настроенный должным образом сервер Nginx на Linux, может обрабатывать 500,000 — 600,000 запросов в секунду. Но этот показатель можно весьма ощутимо увеличить. Хотел бы обратить внимание на тот факт, что настройки описанные ниже, применялись в тестовой среде и, возможно, для ваших боевых серверов они не подойдут.
Минутка банальности.
yum -y install nginx
На всякий пожарный, создадим бэкап исходного конфига.
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
vim /etc/nginx/nginx.conf
А теперь можно и похимичить!
Начнём с директивы worker_processes. Если Nginx выполняет работу нагружающую процессор (например SSL или gzipping), то оптимально установить эту директиву в значение, равное количеству ядер процессора. Выигрыш при большем значении вы получите только в случае обработки очень большого количества статики.
# This number should be, at maximum, the number of CPU cores on your system.
worker_processes 24;
Также, директива worker_processes, умноженная на worker_connections из секции event, даст максимально возможное количество клиентов.
# Determines how many clients will be served by each worker process.
worker_connections 4000;
Последняя пролетарская директива, которую я хочу затронуть — это worker_rlimit_nofile. Данная директива указывает сколько файловых дескрипторов будет использовать Nginx. На каждое соединение надо выделять по два дексриптора, даже для статических файлов (картинки/JS/CSS): один для соединения с клиентом, а второй — для открытия статического файла. Таким образом, значение worker_rlimit_nofile должно быть равным удвоенному значению Max Clients. В системе это значение можно установить из командной строки ulimit -n 200000 или используя /etc/security/limits.conf.
# Number of file descriptors used for Nginx.
worker_rlimit_nofile 200000;
Теперь разберёмся с логированием. Во-первых, оставим логирование только критических ошибок.
# Only log critical errors.
error_log /var/log/nginx/error.log crit
Если вы совсем бесстрашны и хотите отключить логирование ошибок целиком, то помните, что error_log off вам не поможет. Вы просто получите весь лог в файле off. Для отключения логирования ошибок надо делать так:
# Fully disable log errors.
error_log /dev/null crit;
А вот логи доступа не так страшно отключить полностью.
# Disable access log altogether.
access_log off;
Или, хотя бы, включить буфер чтения / записи.
# Buffer log writes to speed up IO.
access_log /var/log/nginx/access.log main buffer=16k;
Для обработки подключений Nginx поддерживает ряд методов. Наиболее эффективным для Linux является метод epoll.
# The effective method, used on Linux 2.6+, optmized to serve many clients with each thread.
use epoll;
Для того, чтобы Nginx пытался принять максимальное количество подключений, необходимо включить директиву multi_accept. Однако при слишком маленьком значении worker_connections, их лимит может быть очень быстро исчерпан.
# Accept as many connections as possible, after nginx gets notification about a new connection.
multi_accept on;
Конечно же, нам не обойтись без кеширования информации о:
- дескрипторах недавно открытых файлов: их размера и даты модификации;
- существовании директорий;
- ошибках при поиске файлов: отсутствие самого файла, отсутствие прав на чтение и т.д.
Советую не копировать значения директив кеширования, а поиграть с ними, подобрав оптимальные для вашего окружения.
# Caches information about open FDs, freqently accessed files.
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
Директива sendfile активирует копирование данных между файловыми дескрипторами средствами ядра, что намного эффективнее связки read() + write(), которая требует обмена данными с пользовательским пространством.
# Sendfile copies data between one FD and other from within the kernel.
sendfile on;
После включения sendfile, можно заставить Nginx отправлять заголовки HTTP-ответов одним пакетом, а не отдельным частями.
# Causes nginx to attempt to send its HTTP response head in one packet, instead of using partial frames.
tcp_nopush on;
Для keep-alive подключений можно выключить буферизацию (алгоритм Нейгла). Это будет полезно при частом запросе маленьких объёмов данных в режиме реального времени, без получения немедленного ответа, когда важна своевременная доставка данных. Классический пример — события наведения мышкой.
# Don't buffer data-sends (disable Nagle algorithm).
tcp_nodelay on;
Стоит обратить внимание на ещё две директивы для keep-alive подключений. Их назначение выглядит очевидным.
# Timeout for keep-alive connections. Server will close connections after this time.
keepalive_timeout 30;
# Number of requests a client can make over the keep-alive connection.
keepalive_requests 1000;
Чтобы высвободить дополнительную память, выделенную под сокеты, включите директиву reset_timedout_connection. Она разрешит серверу закрывать подключение тех клиентов, которые перестали отвечать.
# Allow the server to close the connection after a client stops responding.
reset_timedout_connection on;
Ещё можно существенно уменьшить тайм-ауты для директив client_body_timeout и send_timeout (дефолтное значение обеих — 60 секунд). Первая — ограничивает время на чтение тела запроса от клиента. Вторая — время ответа клиенту. Таким образом, если клиент не начнёт читать данные в указанный промежуток времени, то Nginx закроет подключение.
# Send the client a "request timed out" if the body is not loaded by this time.
client_body_timeout 10;
# If the client stops reading data, free up the stale client connection after this much time.
send_timeout 2;
И, конечно же, сжатие данных. Плюс — единственный и очевидный: уменьшение размера пересылаемого трафика. Минус — единственный и очевидный: не работает для MSIE 6 и ниже. Отключить сжатие для этих браузеров можно директивой gzip_disable, указав в качестве значения специальную маску “msie6”, которая соответствует регулярному выражению “MSIE [4-6]\.”, но работает быстрее (спасибо hell0w0rd за комментарий).
# Compression.
gzip on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "msie6";
Пожалуй, это всё, о чём я хотел рассказать. Скажу лишь ещё раз, что не стоит копировать приведенные настройки один в один. Я советую применять их по одной, каждый раз запуская какую-нибудь утилиту для нагрузочного тестирования (например, Tsung). Это весьма важно для понимания, какие настройки реально ускоряют ваш веб-сервер. Методичность в тестировании сэкономит вам уйму времени.
P.S. Все настройки одним куском для бесстрашных лентяев
# This number should be, at maximum, the number of CPU cores on your system.
worker_processes 24;
# Number of file descriptors used for Nginx.
worker_rlimit_nofile 200000;
# Only log critical errors.
error_log /var/log/nginx/error.log crit
events {
# Determines how many clients will be served by each worker process.
worker_connections 4000;
# The effective method, used on Linux 2.6+, optmized to serve many clients with each thread.
use epoll;
# Accept as many connections as possible, after nginx gets notification about a new connection.
multi_accept on;
}
http {
# Caches information about open FDs, freqently accessed files.
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Disable access log altogether.
access_log off;
# Sendfile copies data between one FD and other from within the kernel.
sendfile on;
# Causes nginx to attempt to send its HTTP response head in one packet, instead of using partial frames.
tcp_nopush on;
# Don't buffer data-sends (disable Nagle algorithm).
tcp_nodelay on;
# Timeout for keep-alive connections. Server will close connections after this time.
keepalive_timeout 30;
# Number of requests a client can make over the keep-alive connection.
keepalive_requests 1000;
# Allow the server to close the connection after a client stops responding.
reset_timedout_connection on;
# Send the client a "request timed out" if the body is not loaded by this time.
client_body_timeout 10;
# If the client stops reading data, free up the stale client connection after this much time.
send_timeout 2;
# Compression.
gzip on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "msie6";
}