Пользователь
0,0
рейтинг
23 ноября 2009 в 14:49

Администрирование → nginx — строим свой letitbit

Появилось желание сделать сервис подобный letitbit.net в отдельно взятой стране на окраине Европы.
Требовалось:
  • позволять загружать/отдавать большие файлы;
  • не позволять перепубликовывать прямые ссылки на файлы;
  • ограничивать количество одновременно скачиваемых файлов.

Для реализации выбрали NGINX в связке с PHP через fastcgi.
В NGINX добавили:
  1. великолепный Nginx upload module, который позволяет избежать многократное копирование загруженного файла на пути NGINX-PHP. К тому же, при небольшой доработке, возможна загрузка сразу в нужную папку, что позволяет использовать простое переименование вместо копирования в PHP
  2. нужную заплатку к модулю secure_link, позволяющую делать безопасные ссылки действительными ограниченное время

PHP взяли самый обычный и запустили через spawn-fcgi.
Поставили сервачок, напихали туда штук 12 терабайтных дисков.
Программист написал PHP код, а Марис Рускулис придумал следующий трюк с rewrite для NGINX, позволяющий избежать обращение к PHP при скачивании файла.
В результате, конфигурация NGINX выглядела примерно так:
http {
limit_zone regular $zonekey 10m;
limit_zone premium $zonekey 10m;
server {
root /www/oursiteishere;
location / { try_files $uri @files; }
location ~ \.php$ { try_files $uri @files; fastcgi_stuff_here; }
location @files { rewrite ^(.*)$ /index.php?$1 last; }
location /storage/ { root /storages/; internal; }
# Location for regular users
location ~ /download/.+/(.+)/0/.+/.*/(.+)$ {
set $fname $2;
set $username $1;
set $zonekey "$binary_remote_addr $username";
limit_conn regular 1;
limit_rate '100k';
secure_link_secret megasecret;
secure_link_ttl on;
if ($secure_link = "") { return 403; }
add_header Content-Disposition "attachment; filename*=UTF-8''$fname";
rewrite ^/download/([a-f0-9]+)/([\.~0-9a-zA-Z_]+)/([01])/([0-9]+)/(.+)/.+$ /storage/$4/$5 break;
}
# Location for premium users
# Location for upload using upload module
}
}

Замечательной вещью в данном конфиге является тот факт, что при скачивании файла по сгенерированной защищённой от подмены временной ссылке (проверку осуществляет secure_link) не вызывается PHP с последующим X-Accel-Redirect.
Возможно, данное решение накладывает ограничение на присутствие логики перед непосредственной отдачей файла, но тем не менее, на мой взгляд, является довольно оригинальным трюком, позволяющим немного сэкономить на fastcgi.
Deniss @slimlv
карма
9,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (30)

  • 0
    Есть похожий проэкт, тоже с nginx, но логику на руби перекинули, и пока решили обойтись paperclip.
    • +3
      Проект. Grammar Nazi негодуют.
  • 0
    Делали нечто похожее только при отдаче X-Accel-Redirect :)
    а так почти все также NGINX в связке с PHP через fastcgi
    великолепный Nginx upload module

    без логики при отдаче ой как нелегко, особенно если есть превелигированные юзеры и обычные.
    а время ссылки можно ограничить и без вашего трюка ;)
    • 0
      Трюк в том чтобы обойтись без X-Accel-Redirect
      для привилегированных и обычных пользователей локейшены разные.
      • 0
        А каким образом синхронизируете информацию о качающих юзерах на серверах (файло-хранилищах)?
        • 0
          в данном варианте — никак.
          Лимиты per-server. Не даром letitbit указан.
          Хотя есть вариант с post_action поиграться
  • +1
    Трюк в том чтобы обойтись без X-Accel-Redirect
    для привилегированных и обычных пользователей локейшены разные.
  • +9
    У меня от слова «letitbit» одни негативные ассоциации :( Шарашкина контора у них…
    imho, лучше сравнить со SkyDrive-ом, Яндекс.Народ-ом, ну или RapidShare
    • –1
      А с депозитом?
      • +8
        депозит тоже говно.
  • 0
    Ну это весьма примитивно как для летитбита=) Чисто технически намного сложнее будет размазать нагрузки по куче серверов и винтов, желательно равномерно, контроли целостности, дубликатов итд.
    • 0
      этим занимаеться кодег раздающий ссылки. И не так всё и сложно если подумать ;)
      • 0
        Та я просто этим занимаюсь немного, то знаю, что это сложнее, чем кажется на первый взгляд. Одна копия файла все равно ненадежно и неэффективно, как правильно распределить так, чтобы при массовом скачивании на все винты в системе была примерно равная нагрузка это достаточно нетривиальная задача, особенно в условиях существенной нагрузки.

        А еще отслеживание и реакция на сбои оборудования, а подбор оптимального метода хранения для файлов, удаление неактуальных файлов (определение, какие именно файлы надо удалять), борьба с ботами, в общем на практике там много еще чего интересного.

        Антилич (по сути то, что у вас и есть), это очень простая часть системы на самом деле, даже без модулей к nginx делается достаточно тривиально.
        • 0
          MogileFS?
          • 0
            Оно как минимум не учитывает нагрузку на винты и популярность файла. Один файл можно хранить в 1-2 копиях, другой лучше на 10 винтов на разных серверах разбросать, потому что его очень много клиентов запрашивают.
            Ну и остальных проблема не решает (удаление неактуальных, метод хранения (рейды, не рейды), итд)
            • 0
              А все же как вы решаете проблему равномерного распределния нагрузки по винтам? В таких сервисах файлы быстро становятся популярными и быстро забываются… Пока соберешь статистику по популярности файла, и начнешь его по винатам двигать — его уже ни кто и не качает :)
              Кеш ОС, тоже не выход если файлы большие.
              • 0
                Там много параметров.
                Например зависит от количество копий файла. Как правило, если точные копии файла заливаются несколько раз, то файл популярный.
                Далее смотрится количество обращения в первые пару часов и если достаточно много, то делает еще одна копия, потом если все еще большая нагрузка на каждую копию, то еще одна итд
                Удаление файла тоже происходит с учетом того, что существуют копии. Для каждого винчестера создается список самых непопурярных хешей (каждый файл физически хранится под именем своего md5 хеша), дальше выбираются те, у которых есть еще копии или если копий нету, но хеш удовлетворяет определенным критериям (небыло обращения столько-то дней) и удаляются.

                Это в общих чертах, там чуть больше условий в алгоритмах, но примерно так работает.
                Балансировка нагрузки по винчестерам это тема статьи наверное, а не комментария.
              • 0
                Как вариант можно использовать кэш сервера для популярного контента
            • 0
              Ну да, могайл не идеален, но для относительно не больших проектов в качестве управлялки контентом его вполне хватает.
              Мы использовали его на видеохостинге. На типичном сторадже был самый простой проц и два винта в gmirror. До двухсот мегабит нода отдавала.
              К тому же балансировка в зависимости от загруженности нод там есть.
              Имхо, в деле доставки контента не стоит пытаться конструировать велосипеды.
              • 0
                Если речь об относительно небольшом (относительно чего?), то там может и просто на серверах надо хранить в виде одной копии и не переживать.

                Под нагрузкой когда все начинает методично ложиться, насчет велосипедов мнение резко меняется. В любом случае без велосипедов большие проекты не делаются, пусть из стандартных компонентов, но все равно конфигуации будут совсем не стандартные и много чего дописывать надо будет.
  • –3
    Спасибо авторам, недавно упустил хороший заказ из за незнания подхода к организации работы nginx, думаю теперь этого не повториться.
  • –2
    Вот изящное решение для IIS7 — www.codeplex.com/FileDenyModule
  • +3
    Раз как летитбит делали, трой не забыли положить? ;)
  • +1
    Да как-то банально это уже. Я про идею.
    Очередные фри и премиум-аккаунты, ограничения, реклама, «скачай бесплатный софт, отправив смску на короткий номер 777» и прочая дребедень.
  • +1
    делал подобный проект. админил с 10-ок серверов. часть из них находилось в москве. Конфа серверов была простой — простейший проц, минимум оперы, кучища винтов + по 2+ сетевые внешние. В ДЦ коннектил несколько внешних 100мегабитных портов на безлимите (кол-во портов==кол-во сетевых) и балансировал нагрузку операционкой (freebsd). Всё было построено на nginx+fast-cgi(php-fpm)+php. Php обрабатывал результат в любой логике, что я захочу. Было до 10 запросов в базу при коннекте к файлу в отдельных случаях, однако X-Accel-Redirect делал своё дело на ура. Даже при минимальных конфах проца и оперы (как на фронт-бэк серверах, так и на сервере-базе) алгоритм отрабатывал на ура, top говорил, что idle сервера 90% в пик.
    Отсюда напрашивается вопрос, зачем все эти шаманства с бубном возле конфига, если это дает минимум прироста производительности. Я бы сказал, это дает материальную точку.

    P.S. в портах фри уже давно лежит nginx не только с nginx_upload_module, но и с nginx_upload_progress_module, который тоже отлично справляется с желанием пользователя закрыть страницу и избавляет программеров от головной боли.
  • 0
    Посмотрите на переделанный модуль expirelink
    forum.nginx.org/read.php?21,17321
    Он позволяет делать ограничения как по времени на ссылку, так и по IP адресу, на конкретный файл, а не на «в общем»
  • 0
    я бы построил это на nginx — php-fpm
    закачка файла upload + upload_progress_module чтоб видеть прогресс закачки

    скачивание защищал бы через access_key_module
    не мудрил бы с реврайтами и конфиг сделал бы проще.
    а в остальном оценка статьи положительная.

  • 0
    Коллеги, извините за такой глупый и несколько не в тему вопрос, но как вы готовите spawn-fcgi?
    У меня он постоянно тихо умирает раз в пару дней безо всякой видимой причины.
    Причем — не на одном сервере…
    • 0
      Если умирает значит что-то криво собрано/настроенно. В крайнем случае daemontool/runit поможет
      • 0
        Собрано не мной:

        apt-get install spawn-fcgi,
        да и все.
        (Ubuntu-10.04 Server x64)

        А про настройки — его там особо и не понастраиваешь жеж — обычный инит-скрипт с
        DAEMON_OPTS="-f /usr/bin/php5-cgi -a 127.0.0.1 -p 9000 -u www-data -g www-data -P $PID"

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.