Полностью конфиг не приводил. Указал только location.
А вообще, да. И aio и thread_pool, и много чего еще пробовал ))
Числа были несколько другие только.
Все-таки, думаю, было мало worker_rlimit_nofile.
Было 4К то-ли из коробки, то-ли сам делал, не помню уже. Хотя, 4к на воркер должно бы хватать чисто умозрительно. Но вот сейчас сделал 64к и на запросы сервер стал отвечать стабильнее.
Вероятно Вы правы.
Очень возможно, что у меня просто не хватало worker_rlimit_nofile в nginx.
Но почему тогда fastcgi_pass помог? Ведь это тоже «файл» для воркера.
php не принципиально. Наверное, лучше было бы сделать на питоне.
Но даже в том виде что сейчас (раздача nginx — fastcgi — php) все свистит и не грузит систему. Мне самое главное, что получился очень быстрый коннект. Т.е. отдача на запрос начинается очень быстро. По большому счету, на соединении большой скорости и не нужно. Но этих соединений много.
mhddfs/aufs, в принципе неплохая штука если надо логически объединить несколько каталогов/дисков. Из плюсов — каждый файл целиком лежит в одном месте. И при гибели одного диска остальное все целое.
Вот только большой трафик через эту прослойку гонять накладно для CPU.
Обычно на раздаче файлов много чтений и мало записей, поэтому писать в общую точку с автоматическим распределением, а читать из настоящего месторасположения — самое то.
LVM это тот-же RAID0, только чуть по-другому. Все равно «прослойка». И все плюсы с минусами от этого. LVM несколько удобнее — позволяет легко расширять дисковое пространство.
У обоих невозможно определить, где находится файл «по-настоящему», у обоих при смерти одного диска помирает все. И в обоих случаях, когда диск занят чем-то своим (это особенно касается SSD), доступ ко всему массиву в ступоре.
RAID0 (особенно аппаратный) хорошо помогает поднять IOPS если используются HDD. С SSD все на много печальнее. SSD периодически сами наводят у себя «порядок». Ну и весь массив будет недоступен пока какой-то диск занят своими делами.
Как-то тут на хабрахабре проскакивала статья про RAID из SSD. Человек делал эксперименты, замерял результаты. Получилась плохая латентность. Как раз IOPS сильно падал.
Я сознательно не стал собирать RAID, хотя железо вполне позволяет.
Данные не настолько критичные, но потерять все равно жалко. Ну и было у меня несколько случаев, когда из-за смерти диска/контроллера терялся весь массив.
Может вам лучше иметь каждый диск отдельно, писать на него через mhddfs/aufs, а при считывании находить где находится на самом деле и читать от-туда? Можно nginx(ом) это разрулить.
Ну, у меня не совсем обычные HDD.
SAS-3, 12Gb/s, контроллер соответствующий.
И таких 8 штук. Пишется на них через «прокладку» aufs примерно равномерно. Так что чтение тоже примерно равномерное.
По гигабиту больше 950 Мб и не получится. Когда скорость отдачи подошла к 500 Мб (и кратковременные всплески до 800) поставили сетевую на 10 Гб. На тестах (1 URL * 200 потоков) получал 2,8 Гб выхлоп. Но это 1 URL, вероятно читает из кеша.
Сколько получится в реальности буду посмотреть.
await дисков мониторится, больше 10 мс не бывает.
Хм… Хотя отдача и по http, но это не Веб. Т.е. клиенты не используют какой-либо браузер. Используются специализированные «железяки» или специализированный софт (ПК, Smart-TV, Android). Список доступного контента и ссылки на него получают тоже через http с другого сервера. Этот просто раздает.
Каким образом зоопарк?.. Так сложилось. Такова жизнь. Слава богу клиенты этот зоопарк понимают. Хм… wmv вроде не понимают, но такого и не видел.
Вообще-то написал тут не особо заморачиваясь на видео.
Есть задача: раздавать произвольные части больших бинарных файлов. Так уж получилось, что это видео. В принципе, без разницы что это. Ну и как эту задачу лучше выполнить.
Всегда считал, что nginx для этого «самое то». Ну и когда уперся, начал экспериментировать. Получилось, что раздавать части файлов эффективнее через fastcgi. И даже php не принципиально, использовал что было «под рукой».
Т.е. связка nginx (без буферизации) — fastcgi оказалась эффективной для такой задачи.
Ну и решил поделиться своим удивлением ))
Приводить к одному формату, к сожалению, невозможно. Там реально зоопарк.
По железу. Нет цели «забить весь канал». Но думаю, 2-3 Gb в итоге потребуется.
CPU хватит за глаза. Диски… 8 штук, каждый гарантированно выдаст 50 МБ/с. В реальности больше (dd if=xxx.avi of=/dev/null выдает всегда больше 100 МБ/с). Итого в битах 8*50*8=3200 Мб.
Памяти бы добавить для кеша — это планируется.
Добавлю.
В php.ini для php-fpm отключены все дополнительные модули (mysql, mysqli и прочее).
Т.е. практически «голый» php. По-идее, можно было бы вообще пересобрать php5-fpm без cripto, ssl, xml и прочего, в данном случае не нужного. В результате потребление памяти сократилось бы еще. Но и так, 1 МБ на процесс, меня вполне устраивает.
pm = dynamic
pm.max_children = 500 // пока хватает. расчеты и мониторинг показывают, что можно довести до 2000
pm.start_servers = 20 // т.е. 20 штук всегда будут ожидать подключение. обеспечивается скорость ответа
pm.min_spare_servers = 20
pm.max_spare_servers = 100
pm.max_requests = 50 // боялся утечек памяти, вроде нормально.
Памяти на борту 20 G. Вот сейчас (в nginx еще остались настройки на собственную отдачу, пока не убираю, жду выходных). 100 соединений, 300 Мб выхлоп:
# free -m
total used free shared buffers cached
Mem: 20114 19382 732 410 374 16318
-/+ buffers/cache: 2689 17425
Swap: 16363 0 16363
..../status:
pool: www
process manager: dynamic
start time: 27/Nov/2017:11:39:48 +1000
start since: 167057
accepted conn: 92179
listen queue: 0
max listen queue: 0
listen queue len: 0
idle processes: 39
active processes: 65
total processes: 104
max active processes: 151
max children reached: 0
slow requests: 0
Цинус в том, что эти child-потоки потребляют очень мало ресурсов. Собственной памяти порядка 0,5-1 МБ каждый. Затраты на CPU тоже мизерные. Там главный процесс — чтение диска.
Это тоже самое что и «echo fread()». Читаются данные в свой некоторый буфер php. Затем эти данные выплевываются в STDOUT. PHP, прежде чем прочитать данные, запросит у системы память в объеме указанного буфера. Соответственно, скрипт будет потреблять приватной памяти не меньше этого буфера. Если читаем по 100К, то вроде не страшно. Но скорость отдачи получается низкая. В ходе экспериментов выяснил, что делать буфер меньше 2М нельзя. Т.е. скрипт будет съедать памяти 2М под буфер + ~0,5М для своих нужд. Итого, 1000 клиентов съедят 2,5 GB.
В моем же варианте «fpassthru($fd)» или «passthru('/bin/dd ...')» на 1000 клиентов придется максимум 1 GB.
Затраты на сам /bin/dd + «прокладка» sh — это мелочи. Приватной памяти они потребляют мизер (меньше 2К вместе). Затраты памяти на сам исполняемый код можно не учитывать — они в памяти в одном экземпляре.
Затраты времени на вызов системной команды маленькие — все нужное уже в памяти.
Там читался текстовый файл. У меня бинарные.
Больше подошел бы stream_copy_to_stream, но в нем сложно копировать произвольную часть файла.
И этот stream_copy_to_stream в указанной статье дал примерно тот-же memory_get_peak_usage что и получилось у меня с passthru('/bin/dd ....').
Но у меня еще в скрипте дополнительно куча логики, которая ест память.
Так что не то. Функционала мало.
У меня в диски и канал пока не упирается. Канал 10 Gb.
По факту в выходные было 850 Mb. На используемых дисках await выше 10 ms не поднимается. Обычно 2 — 5.
Склеивать у меня не выход. Надо уметь отдавать произвольную часть файла. проблема именно в этом. И в том, что практически все запросы такие.
Это из питона? В принципе можно и на нем делать. Но тут принципиальной разницы нет. Все равно "$line = fgets($f)" сожрет кучу памяти. Если делать на рабочей машине — нормально. А на сервере, да на каждый запрос…
Нафиг-нафиг, ночью бежать до серверной чтобы ребутнуть сервер.
Модули nginx http_flv_module и http_mp4_module не подходят.
Сейчас имеется много контента, который этими модулями не поддерживаются.
hls тоже не в тему — клиенты не поддерживают. И изменить что-то у клиента невозможно.
Проблема у меня возникла именно с блокирующим чтением диска при обработке range-bytes запросов. Если кто предложит способ обойти именно эту проблему — подсказывайте плиз.
А вообще, да. И aio и thread_pool, и много чего еще пробовал ))
Числа были несколько другие только.
Все-таки, думаю, было мало worker_rlimit_nofile.
Было 4К то-ли из коробки, то-ли сам делал, не помню уже. Хотя, 4к на воркер должно бы хватать чисто умозрительно. Но вот сейчас сделал 64к и на запросы сервер стал отвечать стабильнее.
Очень возможно, что у меня просто не хватало worker_rlimit_nofile в nginx.
Но почему тогда fastcgi_pass помог? Ведь это тоже «файл» для воркера.
php не принципиально. Наверное, лучше было бы сделать на питоне.
Но даже в том виде что сейчас (раздача nginx — fastcgi — php) все свистит и не грузит систему. Мне самое главное, что получился очень быстрый коннект. Т.е. отдача на запрос начинается очень быстро. По большому счету, на соединении большой скорости и не нужно. Но этих соединений много.
Вот только большой трафик через эту прослойку гонять накладно для CPU.
Обычно на раздаче файлов много чтений и мало записей, поэтому писать в общую точку с автоматическим распределением, а читать из настоящего месторасположения — самое то.
LVM это тот-же RAID0, только чуть по-другому. Все равно «прослойка». И все плюсы с минусами от этого. LVM несколько удобнее — позволяет легко расширять дисковое пространство.
У обоих невозможно определить, где находится файл «по-настоящему», у обоих при смерти одного диска помирает все. И в обоих случаях, когда диск занят чем-то своим (это особенно касается SSD), доступ ко всему массиву в ступоре.
RAID0 (особенно аппаратный) хорошо помогает поднять IOPS если используются HDD. С SSD все на много печальнее. SSD периодически сами наводят у себя «порядок». Ну и весь массив будет недоступен пока какой-то диск занят своими делами.
О! Нашел статью: habrahabr.ru/company/webzilla/blog/227927
Я сознательно не стал собирать RAID, хотя железо вполне позволяет.
Данные не настолько критичные, но потерять все равно жалко. Ну и было у меня несколько случаев, когда из-за смерти диска/контроллера терялся весь массив.
Может вам лучше иметь каждый диск отдельно, писать на него через mhddfs/aufs, а при считывании находить где находится на самом деле и читать от-туда? Можно nginx(ом) это разрулить.
SAS-3, 12Gb/s, контроллер соответствующий.
И таких 8 штук. Пишется на них через «прокладку» aufs примерно равномерно. Так что чтение тоже примерно равномерное.
По гигабиту больше 950 Мб и не получится. Когда скорость отдачи подошла к 500 Мб (и кратковременные всплески до 800) поставили сетевую на 10 Гб. На тестах (1 URL * 200 потоков) получал 2,8 Гб выхлоп. Но это 1 URL, вероятно читает из кеша.
Сколько получится в реальности буду посмотреть.
await дисков мониторится, больше 10 мс не бывает.
Каким образом зоопарк?.. Так сложилось. Такова жизнь. Слава богу клиенты этот зоопарк понимают. Хм… wmv вроде не понимают, но такого и не видел.
Вообще-то написал тут не особо заморачиваясь на видео.
Есть задача: раздавать произвольные части больших бинарных файлов. Так уж получилось, что это видео. В принципе, без разницы что это. Ну и как эту задачу лучше выполнить.
Всегда считал, что nginx для этого «самое то». Ну и когда уперся, начал экспериментировать. Получилось, что раздавать части файлов эффективнее через fastcgi. И даже php не принципиально, использовал что было «под рукой».
Т.е. связка nginx (без буферизации) — fastcgi оказалась эффективной для такой задачи.
Ну и решил поделиться своим удивлением ))
Timing buffered disk reads: 624 MB in 3.00 seconds = 207.74 MB/sec
Конвертировать неоправданно. «Продвинутых» клиентов сильно мало.
По железу. Нет цели «забить весь канал». Но думаю, 2-3 Gb в итоге потребуется.
CPU хватит за глаза. Диски… 8 штук, каждый гарантированно выдаст 50 МБ/с. В реальности больше (dd if=xxx.avi of=/dev/null выдает всегда больше 100 МБ/с). Итого в битах 8*50*8=3200 Мб.
Памяти бы добавить для кеша — это планируется.
В php.ini для php-fpm отключены все дополнительные модули (mysql, mysqli и прочее).
Т.е. практически «голый» php. По-идее, можно было бы вообще пересобрать php5-fpm без cripto, ssl, xml и прочего, в данном случае не нужного. В результате потребление памяти сократилось бы еще. Но и так, 1 МБ на процесс, меня вполне устраивает.
pm.max_children = 500 // пока хватает. расчеты и мониторинг показывают, что можно довести до 2000
pm.start_servers = 20 // т.е. 20 штук всегда будут ожидать подключение. обеспечивается скорость ответа
pm.min_spare_servers = 20
pm.max_spare_servers = 100
pm.max_requests = 50 // боялся утечек памяти, вроде нормально.
Памяти на борту 20 G. Вот сейчас (в nginx еще остались настройки на собственную отдачу, пока не убираю, жду выходных). 100 соединений, 300 Мб выхлоп:
# free -m
total used free shared buffers cached
Mem: 20114 19382 732 410 374 16318
-/+ buffers/cache: 2689 17425
Swap: 16363 0 16363
..../status:
pool: www
process manager: dynamic
start time: 27/Nov/2017:11:39:48 +1000
start since: 167057
accepted conn: 92179
listen queue: 0
max listen queue: 0
listen queue len: 0
idle processes: 39
active processes: 65
total processes: 104
max active processes: 151
max children reached: 0
slow requests: 0
Цинус в том, что эти child-потоки потребляют очень мало ресурсов. Собственной памяти порядка 0,5-1 МБ каждый. Затраты на CPU тоже мизерные. Там главный процесс — чтение диска.
В моем же варианте «fpassthru($fd)» или «passthru('/bin/dd ...')» на 1000 клиентов придется максимум 1 GB.
Затраты на сам /bin/dd + «прокладка» sh — это мелочи. Приватной памяти они потребляют мизер (меньше 2К вместе). Затраты памяти на сам исполняемый код можно не учитывать — они в памяти в одном экземпляре.
Затраты времени на вызов системной команды маленькие — все нужное уже в памяти.
Linux backup 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u2 (2016-01-02) x86_64 GNU/Linux
#cat /etc/debian_version
8.3
Добавлено в sysctl.conf:
net.ipv4.tcp_keepalive_time = 180
net.netfilter.nf_conntrack_tcp_timeout_established = 3000
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_generic_timeout = 300
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_established = 300
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 120
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 120
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 180
net.netfilter.nf_conntrack_icmp_timeout = 10
net.netfilter.nf_conntrack_events_retry_timeout = 15
net.ipv4.netfilter.ip_conntrack_generic_timeout = 120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent2 = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 300
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack = 30
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close = 10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_max_retrans = 120
net.ipv4.netfilter.ip_conntrack_udp_timeout = 30
net.ipv4.netfilter.ip_conntrack_udp_timeout_stream = 180
net.ipv4.netfilter.ip_conntrack_icmp_timeout = 10
net.ipv4.ipfrag_time = 5
net.ipv4.tcp_timestamps = 1
net.ipv4.ipfrag_time = 1
vm.swappiness=20
vm.vfs_cache_pressure=500
Больше подошел бы stream_copy_to_stream, но в нем сложно копировать произвольную часть файла.
И этот stream_copy_to_stream в указанной статье дал примерно тот-же memory_get_peak_usage что и получилось у меня с passthru('/bin/dd ....').
Но у меня еще в скрипте дополнительно куча логики, которая ест память.
Так что не то. Функционала мало.
Все постить много…
По факту в выходные было 850 Mb. На используемых дисках await выше 10 ms не поднимается. Обычно 2 — 5.
Склеивать у меня не выход. Надо уметь отдавать произвольную часть файла. проблема именно в этом. И в том, что практически все запросы такие.
Нафиг-нафиг, ночью бежать до серверной чтобы ребутнуть сервер.
Отдавать как есть.
Канал 10 Gb.
Сейчас имеется много контента, который этими модулями не поддерживаются.
hls тоже не в тему — клиенты не поддерживают. И изменить что-то у клиента невозможно.
Проблема у меня возникла именно с блокирующим чтением диска при обработке range-bytes запросов. Если кто предложит способ обойти именно эту проблему — подсказывайте плиз.