Занимаясь тестированием нашего вновь разрабатываемого облачного хранилища, мы столкнулись со следующей проблемой. Перед инфраструктурой облачного хранилища стоит прокси сервер. До недавнего времени в качестве прокси мы использовали nginx. При загрузке в облако относительно больших файлов (от нескольких сотен мегабайт и более), мы обратили внимание, что сама загрузка (передача данных по сети от клиента до nginx) занимает примерно 50% времени обработки запроса. После окончания передачи данных nginx еще “думает” примерно столько же времени, сколько занимался приемом данных от нас, и только потом сообщает об успешной обработке запроса.
Nginx собирает входящий запрос в буфер целиком, прежде чем передавать его в upstream
Действительно, в официальной документации nginx сказано:
- Note that when using the HTTP Proxy Module (or even when using FastCGI), the entire client request will be buffered in nginx before being passed on to the backend proxied servers.
Другими словами, если вы загружаете на сервер большой файл, скажем, видео размером несколько Гб, nginx сначала целиком закачает ваше видео во временный файл, и только когда передача данных закончится, начнет передавать ваш запрос проксируемому серверу.
Вот как это выглядело в нашем случае. Первый этап: мы делаем upload файла и nginx его принимает от нас:
$ s3cmd put The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 s3://mybucket/
The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 ->
s3://mybucket/The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 [1 of 1]
1331526908 of 1331526908 100% in 144s 8.80 MB/s
остановившись на этих цифрах, s3cmd
“замирает” еще на 138 секунд, после чего финальные результаты получаются такие:
1331526908 of 1331526908 100% in 282s 4.50 MB/s done
Done. Uploaded 1331526908 bytes in 282.6 seconds, 4.49 MB/s
Как видите, скорость упала в 2 раза, а время выполнения запроса увеличилось в 2 раза. Лишние 138 секунд были потрачены на то, что уже принятый от нас файл nginx передавал по сети из своего буфера на диске в наше облако.
Значит, если найти директиву, которая управляет отключением опции буферизации запроса перед передачей его кешируемому серверу, можно увеличить скорость приема файлов хранилищем практически в 2 раза! Но оригинальный nginx этого не умеет. Как же быть? Поиск ответа на этот вопрос привел нас на страницу проекта tengine.
Tengine - форк nginx от taobao
Tengine является форком nginx, разрабатываемым и поддерживаемым крупнейшими китайскими сайтами: taobao.com и tmall.com и, разумеется, применяется на серверах этих сайтов в production. Полный список имеющихся на сегодня в tengine фич можно найти на странице http://tengine.taobao.org, но конкретно нас интересовало вот что:
- Sends unbuffered upload directly to HTTP and FastCGI backend servers, which saves disk I/Os.
В сервере tengine введено две новых директивы: proxy_request_buffering
и fastcgi_request_buffering
, входящие
соответственно в состав модифицированного модуля ngx_http_core_module
(см.
http://tengine.taobao.org/document/http_core.html).
Вот как выглядит загрузка того же самого файла в наше хранилище в случае, если вместо nginx в качестве прокси
используется tengine с отключенной опцией буферизации входящий запросов (proxy_request_buffering off;
):
$ s3cmd put The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 s3://mybucket/
The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 ->
s3://mybucket/The.Walking.Dead.S04E09.720p.WEB.rus.LostFilm.TV.mp4 [1 of 1]
1331526908 of 1331526908 100% in 150s 8.42 MB/s done
Done. Uploaded 1331526908 bytes in 150.8 seconds, 8.42 MB/s
Разница в скорости работы очевидна. Остается надеяться, что когда-нибудь Игорь Сысоев с командой включат патч, реализующий эту функцию из tengine, в основную ветку nginx.
Как собрать tengine в пакет для Debian Wheezy
Мы пошли наиболее простым путем и нашли дерево исходников tengine, уже подготовленное для сборки пакета в debian: https://github.com/whiteley/tengine. На это дерево можно накатить текущую версию tengine.