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.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

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

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