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.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 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"

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