Запрос ЦеныЗапрос Цены
Онлайн ЧатОнлайн Чат
Зона КлиентовЗона Клиентов
КонтактыКонтакты
Скрыть
Live Support
Sales department
Technical Support
Nginx на 1 гигабитном интерфейсе, раздающий крупные файлы

Наша история началась с того, что мы увеличили пропускную способность файл-серверов до 1 гигабита. Мы проанализировали графики RRD и обнаружили, что использование пропускной способности осталось почти на том же уровне, что и до улучшения. 1 гигабитный сервис не обходится дёшево, но это не было проблемой. Мы хотели предоставлять лучшие услуги для клиентов, поэтому для нас это оказалось новой загадкой.

Nginx on 1 Gb

В первую очередь мы удостоверились, что интерфейс работает в режиме полного дуплекса. Затем мы проверили порты на сетевом коммутаторе. Мы провели несколько тестов загрузки/закачки. Мы поговорили с техподдержкой датацентра и так далее. Вкратце, это был медленный и скучный процесс. Однако результаты проверки были достаточно интересные.

Мы обнаружили, что после примерно 900 активных соединений, скорость новых сессий ограничивается несколькими килобайтами в секунду.

Это было удивительно. У нас был мощный сервер с Intel Xeon L5410, 6 гигабайтами оперативной памяти и массивом дисков с 20 SATA HDD на аппаратном RAID контроллере. Программное обеспечение было разработано и рассчитано на очень большие загрузки – FreeBSD в качестве операционной системы и Nginx в качестве веб-сервера. FreeBSD является продвинутой операционной системой для современных серверов и известна за хорошую производительность в сетевых приложениях. Nginx является третьим по популярности веб сервером в мире. Он может обрабатывать статический контент (например картинки, стили и джаваскрипт) с большой скоростью, и сильно увеличивает скорость сайта. Теперь мы знаем, что в случае больших файлов поведение Nginx не всегда предсказуемо.

Мы определили, что корнем проблемы был Nginx. Этот вывод был основан на простом тесте. Когда веб-сервер достигал 900 активных соединений, мы попытались скачать тестовый файл. Скорость скачки была примерно 20 килобайт в секунду. В то же время мы начали качать этот файл через FTP. Скорость FTP была больше 20 мегабайт в секунду.

Причина заключается в архитектуре веб-сервера. Nginx основан на асинхронной модели. Он применяет такие запросы к ядру, как epoll, kqueue, сигналы реального времени, и так далее. Вы можете прочитать больше про это здесь: http://people.freebsd.org/~jlemon/papers/kqueue.pdf. Асинхронная модель экономит системные ресурсы и позволяет обрабатывать тысячи сетевых соединений очень быстро и эффективно. Nginx применяет этот концепт без оглядки на дисковые операции ввода-вывода. Диск может быть занят множеством одновременных запросов чтения или записи (учитывайте ограниченную скорость произвольного доступа) и когда процесс Nginx пытается прочитать информацию с этого диска, он зависает. Это случается, когда Nginx раздаёт крупные файлы. Процесс Nginx постоянно блокируется из-за ожидания диска. Стоит сразу сказать, что верного решения этой проблемы не существует. Лучший результат может быть получен при помощи экспериментирования с различными параметрами.

Вот шаги, которые мы провели, чтобы починить проблему:

1)Увеличение количества worker процессов является тем, с чего стоит начать. Существует базовая формула, с которой мы должны начать улучшение. Количество процессов worker должно быть равно количеству ядер процессора в системе плюс один. Именно это мы и сделали. У L5410 есть 4 ядра, каждое из которых имеет 4 потока. Мы установили "worker_processes 17". Ситуация стала немного лучше. Но в определённый момент, все 17 worker-ов работали над тем же диском, что вызывало задержки и время ответа nginx могло достигать половины минуты.

2) Следующим шагом настройки был выбор размера буфера. Буферизация помогает снизить количество операций поиска на диске и уменьшить время задержки процесса. Для нас лучшая комбинация была sndbuf=32K output_buffers=1 512k. Эти параметры значительно улучшили производительность сервера, но мы всё ещё были далеки от использования полной пропускной способности.

3) После этого мы сконцентрировались на директиве send_file. Эта инструкция помогает снизить использование памяти потому, что таким образом не применяется двойная компрессия (больше информации можно найти http://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2).Если вы работаете с файлами больше 4 мегабайт, лучше полностью отключить этот параметр. У нас были также маленькие файлы, поэтому мы применили прямую директиву I/O, чтобы отключить send_file для больших файлов. Отключение параметра send_file привело к появлению ошибок в лог файлах «upstream prematurely closed connection while reading response header from upstream, client». Причиной этого были блокировки диска. Более того, с включённым send_file, подобных ошибок не было, но они появились после отключения send_file.

4) Мы попробовали различные опции в первых трёх шагах, но не смогли достичь нужного результата. В некоторых случаях мы теряли часть соединений, но использовали всю пропускную способность. В других случаях мы не использовали всю пропускную способность, но всё работало стабильно. Чтобы избежать блокировок диска мы включили модуль ядра aio и перекомпилировали Nginx с поддержкой aio. Aio показало хорошие результаты, но имело и свои ограничения. I/O диска так же увеличилось, как и средняя нагрузка серверов.

5) Учитывая наш опыт, мы решили сильно изменить всю схему файл сервера. Мы решили для каждого диска запустить по одному экземпляру Nginx. Главный экземпляр Nginx (мы называем его менеджером соединений) только перенаправляет соединения на необходимый экземпляр, в зависимости от пути к файлу. Он применяет aio и никогда не зависает. Каждый экземпляр диска применяет прямой I/O и даже если один из дисков занят, это не влияет на другие запросы. При помощи следующей конфигурации мы достигли 1 гигабита в секунду.

_______________________________________________________________________________________________________

nginx_main config
user www;
worker_processes 16;
worker_rlimit_nofile 600000;
error_log logs/error.log;

events {
worker_connections 51200;
use kqueue;
}

http {
# Global settings
include mime.types;
default_type application/octet-stream;
sendfile off;
aio on;
output_buffers 1 512k;
keepalive_timeout 15;
send_timeout 30s;
tcp_nopush off;
tcp_nodelay on;
gzip on;
client_body_temp_path /storage/s1/tmp 1 2;
client_max_body_size 102400m;
reset_timedout_connection on;
server_names_hash_bucket_size 512;

log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent”‘;

# Main virtual host
server {
listen ip1:80 sndbuf=32K;
# Put here your vhost stuff
# and do not forget to change ip
}
}

__________________________________________________________________________________________________
 

nginx_hdd1 config
user www;
worker_processes 2;
worker_priority -10;
worker_rlimit_nofile 600000;
error_log logs/error.log;

events {
worker_connections 51200;
use kqueue;
}

http {
# Global settings
include mime.types;
default_type application/octet-stream;
sendfile on;
aio off;
output_buffers 1 2m;
keepalive_timeout 15;
send_timeout 30s;
tcp_nopush on;
tcp_nodelay on;
client_body_temp_path /storage/s1/tmp 1 2;
client_max_body_size 102400m;
reset_timedout_connection on;

# Logging
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent”‘;

# Виртуальный хост для диска с1
server {
listen ip2;
# Вставьте здесь ваши строки vhost
# и не забудьте изменить ip
}
}

Запросить цену
Заполните форму и мы свяжемся с Вами в ближайшее время
Вход для клиентов
Система запросов и другие полезные сервисы для наших клиентов
Свяжитесь с нами
Мы с удовольствием ответим на все ваши вопросы