Системный архитектор
10,6
рейтинг
16 августа 2014 в 02:40

Администрирование → Дисковая балансировка в Nginx


В этой статье я опишу интересное решение на базе Nginx для случая, когда дисковая система становится узким местом при раздаче контента (например, видео).

Постановка задачи


Имеем задачу: необходимо отправлять клиентам статические файлы (видео) с суммарной полосой раздачи в десятки гигабит в секунду.

Такую полосу по очевидным причинам нельзя раздавать прямо из хранилища, необходимо применить кэширование. Объём контента, составляющий большую часть производимого трафика, на несколько порядков больше объёма оперативной памяти одного сервера, поэтому кэширование в ОЗУ невозможно, хранить кэш придётся на дисках.

Сетевые каналы достаточной ёмкости имеются a priori, иначе задача была бы нерешаема.

Выбор пути решения


В этой ситуации проблемным местом становятся диски: чтобы сервер произвёл 20 гигабит трафика в секунду (два оптоволокна в агрегате), он должен прочитать с дисков ~2400 мегабайт в секунду полезных данных. Вдобавок к этому диски ещё и могут быть заняты записью в кэш.
Для масштабирования производительности дисковой системы применяют RAID-массивы с чередованием блоков. Ставка делается на то, что при чтении файла его блоки окажутся на разных дисках и скорость последовательного чтения файла будет в среднем равна скорости самого медленного диска, умноженного на число чередующихся дисков.
Проблема такого подхода в том, что он работает эффективно только для идеального случая, когда читают достаточно длинный файл (размер файла много больше размера блока чередования), который расположен внутри файловой системы без фрагментирования. Для параллельного чтения многих мелких и/или фрагментированных файлов такой подход не позволяет даже приблизиться к суммарной скорости всех дисков. К примеру, RAID0 из шести ssd дисков при 100% загруженности очереди ввода-вывода давал скорость как у двух дисков.
Практика показала, что выгоднее поделить файлы между дисками целиком, используя раздельные файловые системы. Это гарантирует утилизацию каждого диска, потому что они независимы.

Реализация


Как упомянуто выше, кэшировать будем nginx-ом. Идея в том, чтобы поделить раздаваемые файлы между дисками поровну. Для этого в простейшем случае достаточно хэшированием отобразить множество URL-ов во множество дисков. Примерно так мы и сделаем, но обо всём по порядку.
Определим зоны кэширования по числу дисков. В моём примере их 10.
В секции http:
    proxy_cache_path  /var/www/cache1  levels=1:2  keys_zone=cache1:100m inactive=365d max_size=200g;
    proxy_cache_path  /var/www/cache2  levels=1:2  keys_zone=cache2:100m inactive=365d max_size=200g;
    ...
    proxy_cache_path  /var/www/cache10 levels=1:2  keys_zone=cache10:100m inactive=365d max_size=200g;

В директорию каждой зоны кэширования примонтирован отдельный диск.

Источниками контента будут три апстрима, по два сервера в каждой группе:
upstream src1 {
        server 192.168.1.10;
        server 192.168.1.11;
}
upstream src2 {
        server 192.168.1.12;
        server 192.168.1.13;
}
upstream src3 {
        server 192.168.1.14;
        server 192.168.1.15;
}

Это непринципиальный момент, взято для правдоподобия.

Секция server:

server {
	listen   80 default;
	server_name  localhost.localdomain;
	access_log      /var/log/nginx/video.access.log combined buffer=128k;

	proxy_cache_key $uri;

	set_by_lua_file $cache_zone /etc/nginx/cache_director.lua 10 $uri_without_args;

	proxy_cache_min_uses 0;
	proxy_cache_valid  1y;
	proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404;

	location ~* ^/site1/.*$ {
		set $be "src1";
		include director;
	}
	location ~* ^/site2/.*$ {
		set $be "src2";
		include director;
	}
	location ~* ^/site3/.*$ {
		set $be "src3";
		include director;
	}

    location @cache1 {
            bytes on;
            proxy_temp_path /var/www/cache1/tmp 1 2;
            proxy_cache cache1;
            proxy_pass           http://$be;
    }
    location @cache2 {
            bytes on;
            proxy_temp_path /var/www/cache2/tmp 1 2;
            proxy_cache cache2;
            proxy_pass           http://$be;
    }
...
    location @cache10 {
            bytes on;
            proxy_temp_path /var/www/cache10/tmp 1 2;
            proxy_cache cache10;
            proxy_pass           http://$be;
    }
}

Директива set_by_lua_file выбирает подходящий диск для этого URL хэшированием. Для условного «сайта» выбирается и запоминается бэкэнд. Затем в файле director происходит перенаправление во внутренний локейшн, который обслуживает запрос из выбранного бэкэнда, сохраняя ответ в определённом для этого URL кэше.

А вот и director:
if ($cache_zone = 0) { return 481; }
if ($cache_zone = 1) { return 482; }
...
if ($cache_zone = 9) { return 490; }
error_page 481 = @cache1;
error_page 482 = @cache2;
...
error_page 490 = @cache10;

Выглядит ужасно, но это единственный способ.

Вся соль конфигурации в хэшировании URL->диск, cache_director.lua:
function shards_vector(base, seed)
    local result = {}
    local shards = {}
    for shard_n=0,base-1 do table.insert(shards, shard_n) end

    for b=base,1,-1 do
        choosen = math.fmod(seed, b)+1
        table.insert(result, shards[choosen])
        table.remove(shards, choosen)
        seed = math.floor(seed / b)
    end
    return result
end

function file_exists(filename)
  local file = io.open(filename)
  if file then
    io.close(file)
    return 1
  else
    return 0
  end
end

disks = ngx.arg[1]
url   = ngx.arg[2]
sum   = 0
for c in url:gmatch"." do
    sum = sum + string.byte(c)
end
sh_v = shards_vector(disks, sum)

for _, v in pairs(sh_v) do
    if file_exists("/var/www/cache" .. (tonumber(v)+1) .. "/ready") == 1 then
        return v
    end
end

В директиве set_by_lua_file, упомянутой выше, этот код получает количество дисков и URL. Идея напрямую отображать URL в диск хороша до тех пор, пока не выйдет из строя хотя бы один диск. Переадресацию URL-ов с проблемного диска на здоровый нужно нужно выполнять одинаково для конкретного URL-а (иначе не будет попаданий в кэш) и при этом же она должна быть разной для разных URL-ов, чтобы не возникало перекоса нагрузки. Оба этих свойства должны сохраняться, если замена замены (и т.д.) тоже выйдет из строя. Поэтому для системы из n дисков отображаю URL во множество всевозможных перестановок этих n дисков и затем по порядку следования этих дисков в расстановке пытаюсь воспользоваться соответствующими кэшами. Критерием активности диска (кэша) считается наличие файла-флага в его директории. Мне приходится chattr-ить эти файлы, чтобы nginx не удалял их.

Результаты


Такое размазывание контента по дискам действительно позволяет использовать всю скорость дисковых устройств. Сервер с 6 недорогими SSD-дисками при рабочей нагрузке смог развить отдачу порядка 1200 МБ/с, что соответствует суммарной скорости дисков. Скорость массива же колебалась в районе 400 МБ/c
@YourChief
карма
41,5
рейтинг 10,6
Системный архитектор
Реклама помогает поддерживать и развивать наши сервисы

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

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

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

  • –5
    Способ так себе, проксирование под серьезной нагрузкой работать скорее не будет. Лучше по крону заполнять сервер самыми актуальными данными (в том числе, дублировать совсем горячие на несколько дисков) в фоновом режиме. Потребуется отдельный баллансировщик, но он будет нужен в любом случае, когда вырастите за пределы доступного на кэше канала. А больше 60G вы даже через крутой сервер не прокачаете. Даже если проксирование будет делаться не на nginx а каким-то более оптимизированным для такой задачи софтом. + такой кэш сервер не должен падать, иначе это завалит весь CDN.
    • +1
      Способ так себе, проксирование под серьезной нагрузкой работать скорее не будет.

      Будет и работает.
      Потребуется отдельный баллансировщик, но он будет нужен в любом случае, когда вырастите за пределы доступного на кэше канала. А больше 60G вы даже через крутой сервер не прокачаете.
      Пропускать трафик через какую-то ноду — не единственный и не лучший способ менеджить трафик. Есть ещё энное количество способов способов.
      • +1
        Ну на какой-то небольшой нагрузке может и будет.

        Вот у вас есть CDN размером X TB и кэш размером X/20 ТБ. Как вы определяете, какие файлы создают самую большую нагрузку, чтобы их был смысл на кэш закидывать?
        • –2
          Такая задача принимать такое решение извне кэширующей системы возникает только в вашей схеме с внешним костылём, заливающим популярное содержимое. Ознакомьтесь с работой вебкэшей-обратных прокси.
          • +1
            Такая задача стоит всегда так, как места в кэше меньше, чем на хранилище. В вашем случае будет происходить следующее:

            nginx залил какие-то рандомные файлы в кэш (в которым первыми обратились), уперся в размеры кэша, удалил часть самых неактуальных и снова залил рандомные файлы. И так по кругу. Постоянно на сервере будут присутствовать непонятные файлы, постоянно будет идти перезапись. Если вы решите поставить 2 одинаковых кэша, то они будут дублировать друг друга и места в кэше это не добавит. Вы не сможете сами определить интервал, за которых считать популярность файлов, это будет решать nginx.
            (мы на своей системе определили оптимальный интервал — 3 часа. Т.е. считаем трафик, который создает файл за это время, имеем наименьшее количество перезаписи и наибольшее количество трафика с каждого гигабайта ssd. Но на разных системах это время разное и его надо подбирать)

            И т.д. не буду повторять то, что я уже описал ниже.
            • –1
              Если вы решите поставить 2 одинаковых кэша, то они будут дублировать друг друга и места в кэше это не добавит.

              Этот вывод вы сделали, опираясь на собственные домыслы о механизме деления нагрузки между кэшами, не так ли?

              (мы на своей системе определили оптимальный интервал — 3 часа. Т.е. считаем трафик, который создает файл за это время, имеем наименьшее количество перезаписи и наибольшее количество трафика с каждого гигабайта ssd. Но на разных системах это время разное и его надо подбирать)

              антинаучное шаманство. nginx имеет данные по популярности записей за весь свой аптайм и вытеснение происходит органически
            • 0
              > nginx залил какие-то рандомные файлы в кэш (в которым первыми обратились), уперся в размеры кэша, удалил часть самых неактуальных и снова залил рандомные файлы.

              В некоторых случаях (при большом кэш-хите) от постоянной перезаписи файлов в кэше помогает proxy_cache_min_uses.
              • 0
                Да, без него вообще беда.
    • 0
      Зря вы, решение хорошее. Во-первых, оно рабочее. Во вторых, простое. В третьих, насколько я могу судить исходя из своего знакомства с большими инсталляциями, а по прочтении статьи у меня сложилось ощущение что у автора не одна машинка, хорошо масштабируется.
      • +1
        И каким образом оно масштабируется? Ну за кэшем допустим может быть множество серверов. А как сделать несколько кэшей? Каким образом решать, что вообще должно быть сохранено в очень ограниченном хранилище кэша?
        • 0
          Кэши встречают все запросы и решают, какие ключи хранить, а какие пропускать бэкэндам. Если я вам сейчас вот прямо здесь начну рассказывать, как поделить однородную нагрузку между несколькими вебсерверами это будет:
          1. оффтопик
          2. разговор не на одном уровне

          Понимаете?
          • +4
            Я занимался построением CDN, которая в лучшие времена выдавала 250Гбит (летом несколько меньше выходит). С хороших кэшей выжимали 80G. Не в тестовом, а боевом режиме. Мы пробовали множество разных вариантов и я точно могу сказать, что ngx_http_proxy_module это не очень хорошее решение для больших объемов данных и трафика. Особенно, в таком варианте как у вас.

            Вам приходится пропускать весь трафик через кэш. И тут есть как минимум следующие проблемы:

            1. Кэшер, вместо того, чтобы отдавать только самые горячие данные, вынужден пропускать через себя и трафик остального CDN, что сильно снижает его производительность. Мы выжимали 20G при нескольких тысячах соединений с одного процессора E3-1270, с хорошим запасом. Вам понадобится минимум 2 таких процессора и при условии, что большой процент трафика попадает на файлы в кэше.

            2. Вы тратите впустую канал от хранилища до кэша. Хранилище могло мы неактуальные файлы раздавать самостоятельно, вместо этого, сначала надо их передать на кэшер и потом оттуда в мир.

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

            4. Если вы используете несколько серверов, то сильно ограничиваетесь в выборе алгоритма распределения файла по кэшерам. По сути, остается либо полное дублированные данных (если рандомно редиректиться запрос на кэш), либо делить контент по какому-то признаку и получать несколько расрозренных кэшей (которые опять-же прийдется дублировать).
            Тогда как оптимальнее всего, распределить равномерно по всем кэшерам топ файлов со всего CDN. Так, чтобы максимум трафика уходило именно с кэшей. (этот пункт могу раскрывать подробнее, не уверен что понятно написал).

            5. Кэши долго прогреваться, потому что надо сперва собрать статистику по нагрузке на каждый файл, для этого пропустив множество неэффективных запросов. И даже после прогрева, кэш будет работать не лучшим образом, nginx будет постоянно копировать туда случайные файлы, определять наименее актуальные, удалять, снова заполнять случайными. Тогда как если мы сразу заливаем топ файлов и периодически его обновляем, то практически все время кэширующий сервер работает с максимальной эффективностью, не занимаясь неактуальными файлами.

            6. Из-за постоянных копирований в кэш и удаления оттуда файлов, быстро умрут SSD. Тогда как на кэшере, куда заливаются только топ актуальных файлов, перезаписи в разы, а то и на порядки меньше.

            Правильно у вас то, что вы храните файлы на отдельных дисках. Но заполнять кэш намного лучше в фоне по крону, имея на руках полную таблицу по актуальности всех файлов на CDN.
            • +1
              Мы пробовали множество разных вариантов и я точно могу сказать, что ngx_http_proxy_module это не очень хорошее решение для больших объемов данных и трафика.

              Точно могу сказать на основании чего? Какая-то неустранимая проблема возникла?
              1. Кэшер, вместо того, чтобы отдавать только самые горячие данные, вынужден пропускать через себя и трафик остального CDN, что сильно снижает его производительность. Мы выжимали 20G при нескольких тысячах соединений с одного процессора E3-1270, с хорошим запасом. Вам понадобится минимум 2 таких процессора и при условии, что большой процент трафика попадает на файлы в кэше.

              Негорячие данные это 5% трафика. Закон Парето во всей красе.
              2. Вы тратите впустую канал от хранилища до кэша. Хранилище могло мы неактуальные файлы раздавать самостоятельно, вместо этого, сначала надо их передать на кэшер и потом оттуда в мир.

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

              Нет.
              4. Если вы используете несколько серверов…

              Региональные имеют полный набор, центральные — делят контент. Никаких проблем с этим я не вижу.
              5. Кэши долго прогреваться, потому что надо сперва собрать статистику по нагрузке на каждый файл

              Из конфига видно, что если есть место, файл попадает сразу в кэш. Такой проблемы нет.
              6. Из-за постоянных копирований в кэш и удаления оттуда файлов, быстро умрут SSD.

              Перезаписей у заполненного кэша мало, да и discard помогает.

              Проблем, о которых Вы говорите, просто нет. Такой кэш работает естественным путём, это крайне удобно. Может, конечно, всё хорошо в силу сравнительно небольшого разнообразия данных — даже в один отдельновзятый кэш влезает объём контента для 85% попаданий.

              Я занимался построением CDN, которая в лучшие времена выдавала 250Гбит (летом несколько меньше выходит). С хороших кэшей выжимали 80G

              Можно, конечно, апеллировать к опыту, но большие ошибки — большие и раскаяния, знаете ли.
              • +1
                > Негорячие данные это 5% трафика. Закон Парето во всей красе.

                Тут ваша ошибка.

                Мы продаем софт разным клиентам и профиль нагрузки у всех очень отличается.

                У некоторых горячая зона влезает в память. У некоторых RAM VFS кеш отключается сразу и приходится крутить настройки cache hit miss в нашем сервере, что бы горячая зона влезла в пачку SSD, а остальные 50% трафика просто брались с хардов.

                Т.е. ваше предположение о том, что негорячие данные — 5% трафика основаны на вашем очень частном случае. Я видел 50% трафика с хранилища и ничего с этим не сделать.
              • +2
                Я написал целых 6 неустранимых или сложноустранимых проблем. Они все разной степени критичности, но вместе получается существенное ухудшение эффективности кэширования.

                1. Закон Паретто сработает если у вас объем кэша равен объемы хранилища. А когда кэш в десятки раз меньше, то на него может прийтись и 50% трафика и 30% и 10. Заранее просчитать это нельзя, зависит от профиля использования CDN. и 10% для небольшого кэша (несколько 4-8 SSD, против 24-36 винта хранилища) гораздо вероятнее. Т.е. 90% процентов трафика кэшер будет просто гонять по сети, замедляя по дороге.

                Региональные имеют полный набор, центральные — делят контент. Никаких проблем с этим я не вижу.


                Региональные кэши пока вмешивать очень рано, центральные сначала заведите на полную мощность. Очень интересно, по какому признаку они будут делить контент.
                Самый оптимальный алгоритм, который удалось придумать нам при работе с файлами (а не блоками): составляется топ файлов в системе по соотношению трафика, сгенерированного им за учетный период, к объему этого файла. Далее из этого топа выбирается то количество, которое влезет на кэши и равномерно по ним распределяется так, чтобы на каждый гигабайт каждого ssd на кэшах пришлось примерно одинаковое количество трафика.
                Если сможете придумать более оптимальный способ заполнения кэша, с радостью выслушаю.

                В продакшене, разумеется, используется более сложная версия, с дублированием самого топа (30% объема) файлов так, чтобы каждый такой файл был на 2х серверах (и выключение одного кэша не приводило к резкому наплыву трафика на стореджи), но общий принцип такой: распределяем на основе соотношения трафика файла к его объему. У вас данных по этому соотношению нет, их хранит nginx (в лучшем случае) и стандартными средствами получить их нельзя. Т.е. эффективно распределить файлы по кэшам вы тоже не сможете.

                Можно, конечно, апеллировать к опыту, но большие ошибки — большие и раскаяния, знаете ли.
                Проблем, о которых Вы говорите, просто нет.


                Вы не в школе учитесь? Я привел проблемы, которые есть у вашей архитектуры. Мы ее тоже рассматривали, обнаружили их и пересмотрели постоение кэширования. Да, отдавать все только через несколько кэшей выглядит заманчиво. Но если сделать в лоб, как вы и стандартными средствами, работать будет в разы хуже, чем могло бы. Про разы это не преувеличение, см. пункт 1 выше.

                Как доказать вам ущербность вашей артитектуры не ткнув носом в плохо работающий продакшен, я не знаю. Аргументы вы воспринимаете как-то странно, считая себя априори умнее всех и считая чужой опыт бесполезным, даже не пробуете анализировать узкие места. Потому, спорить с вами не буду, смысла нет.

                Но для тех, кто соберется строить нагруженную CDN и наткнется на вашу статью, еще раз укажу на то, что ваш способ очень неоптимален и годится только для небольшой нагрузки. Дальше будет дорого, а еще дальше, в любом случае, плохо.

                Чтобы был повод подумать над архитектурой еще раз, оставлю ссылку на альтернативу, которая точно держит указанные выше нагрузки: ruhighload.com
                • +3
                  Мне кажется, у вас просто разный профиль нагрузки. Если 90% трафика падает на кэш, а 10 проксируется дальше, то вышеприведенная схема более чем рабочая. В вашем случае это, очевидно, не так. Поэтому и решение приходится использовать более сложное и интеллектуальное. А серебряных пуль, как известно, нет. Преимущество этого решения простота. Вашего — большие возможности и гибкость. За всё приходится платить )
                  • +1
                    90% нагрузки на кэш это редкий случай. Либо маленькое хранилище (или очень большой кэш, но сомнительно), либо какой-то особый профиль использования. Я писал, что схема будет неэффективной если большой процент нагрузки прийдется проксировать. Для каких-то ситуаций, разумеется, предлагаемая схема сработает. Она не годится именно для общего случая т.к. абсолютно негибкая.
                  • +1
                    90% трафика на кеш при видеостриминге бывает только если у вас сайт посвященный одному единственному сериалу, и этот сериал — Игра Престолов.

                    Тогда у вас горячая зона наверное будет влезать даже в память.

                    В других случаях нельзя априори судить о профиле нагрузки. Мы делали софт для анализа логов, что бы посчитать горячую зону. Без этого никак.
                    • +2
                      Другой вариант сходу — СМИ/журналы. 90% смотрят последние новости и статьи.
                      • +2
                        Да, тоже наверняка будет такой профиль, особенно при солидном возрасте. Ведь старое видео мало кого интересует.

                        Например, в телевидении через неделю как правило запись можно стирать.
                • –10
                  Господа модераторы, тут реклама в комментах — отреагируйте, пожалуйста
              • +3
                Я влезу немного с оффтопиком по поводу так называемого закона Парето. Во-первых, это не строгий закон, а эмпирическое правило которое часто, но далеко не всегда имеет место. Во-вторых, парето это 20/80, а не 5/95, ну а самое главное, что вы вывернули это правило наизнанку, т.к правило говорит о том, что как раз Малая часть дает БОльшую часть результатов. Т.е если бы в ваш кэш на примерно 20 процентов било примерно 80 % заапросов — то это было бы Парето.
                А у вас как раз показано, что оно НЕ работает :)
  • +4
    Для того, что бы раздавать 20 гигабит видео и при этом оказывать хороший сервис, надо отдавать не mp4, а HDS/HLS.

    Тогда кешировать надо будет маленькие сегментики.

    Один сервер на 20 HDD и 6 SSD справляется с 10-гигабитной загрузкой без особых проблем.

    esc прав: автоматическое кеширование на видео паршиво работает и приходится вручную подгадывать, что даст наибольший удар.
    • +1
      Почему не mp4?

      В общем случае, cdn файлы раздает, пользователи их могут скачивать хоть менеджром загрузки. Но если даже речь о хостинге онлайн-видео, чем так плох mp4? мы 200Гбит таких файлов раздаем. Случаются косяки, но они вызваны затыками в других местах, а не mp4.

      Интересно узнать, что не так с mp4 в данном случае. Особенно, если речь о flash плеере и веб. Хотя, я и на мобильных устройствах проблем не вижу. Перекос нагрузки теоретически возможен, но мы несколько раз перестраховались на этот случай. поделитесь опытом, чем HDS/HLS лучше для VoD?
      • 0
        mp4 плох для современного хостинга видео потому что:

        1) вы получаете до 30% перерасхода трафика на дозагрузках ненужного контента
        2) вы лишаетесь возможности вещать мультибитрейт/мультиязык
        3) вы лишаетесь возможности предоставлять качественный сервис ан iOS. Apple влегкую банит приложения, которые отдают не HLS

        • 0
          1. Возможно перерасход есть, но проблема решаемая. Даже стандартными средствами nginx можно ограничить скорость загрузки файла после подгрузки определенной порции. В связке с плеером, можно достичь еще лучших результатов. Конечно, оверхед останется, но большинству он не так уж и критичен. Многие банально не кодирую видео должным образом и получают существенно больший оверхед даже с hls и не заморачиваются.

          2. Решается модулем микширования. Помню мы с вами такое решение на базе erlyvideo сделать не смогли, но пересмотрев немного требования, со временем сделали очень эффективный модуль в виде модуля к nginx. На диске хранятся подготовленные видео и аудиодорожки, которые модуль умеет отдавать в любой комбинации и с поддержкой всей остальной функциональности, востребованной при раздаче mp4 (псевдостримминг, поддержка aio/sendfile в засимости от хранилица, докачку по http и.т.д). Оверхед получается на уровне 10-15% по сравнению с отдачей готовых файлов.

          3. Тут спорить не буду, вероятно так и есть. Хотя знаю как минимум 2 приложения, которые не заморачивались этим вопросом, написаны на phonegap и гоняют mp4 по обычному http протоколу. Но, конечно, это не значит что их завтра не забанят.
          • 0
            > Помню мы с вами такое решение на базе erlyvideo сделать не смогли

            Я не знаю кто вы такой, так что ничего прокомментировать не могу.

            HDS/HLS позволяет на лету достаточно неплохо подстраиваться под реальную скорость клиента. В Flussonic это реализовано очень эффективно.
            mp4 стриминг не позволяет сделать адаптивный битрейт.
            • 0
              Я когда-то заказывал у вас модуль для эрли, чтобы можно было из нескольких mp4 файлов брать дорожки и потом отдавать их в любой комбинации в виде нового mp4 файла на лету. К сожалению, сделать не получилось тогда и пришлось в итое изменить требования и делать на другой платформе.

              Адаптивный битрейт мы на mp4 тоже сделали в виде альфы, но потом забросили. Не такая и хорошая штука, как кажется. Оставили только в варианте, когда канал ну совсем не тянет выбранное качество (и переключение только вниз). А когда видео то нормальное, то все в квардратах и непонятно, что происходит, то видео хочется или выключить или зафиксировать какое-то качество и прокэшировать какое-то время.

              Хотя, кто-то может считать это хорошей штукой, разумеется. Но как по мне, оно нужно для трансляций в реальном времени, а не VoD.
              • 0
                В целом, неважно, кто я. Главное, что решение для преключения дорожек и качеств mp4 файлов есть и оно работает очень эффективно под большой нагрузкой. Т.е это не проблема. Но переключение качества должен поддерживать и плеер на своей стороне (это, возможно, отличает его от HLS).
      • 0
        В принципе… для DRM, защита от копирования и все такое.
        Ну, или видимость защиты от копирования.
        Иногда это бывает краеугольным требованием клиента/правообладателя.

        При проксировании mp4 с сохранением (proxy_store), веселье начинается, когда пользователь нажимает на середину фильма.
        Хотя как раз у вас это не используется, оставлю на заметку другим.
        • 0
          перемотка — это краеугольная проблема псевдостриминга.

          Автопереключение битрейта — это вторая проблема.
          • 0
            В чем конкретно проблема? С кэшированием, которое описывается в статье — да, это проблема. Но если использовать другие схемы, где сложность?
        • 0
          DRM схема которую знаю я реализовывается отдельно от CDN. Т.е. CDN отдает чанки (mp4 тут, пожалуй, уже неприменимо), которые зашифрованы предварительно. И никаких дополнительных сложностей в плане отдачи файлов тут нет. Напротив, чанки обычно практически одинакового размера и некоторые вещи упрощаются.

          А ключи для расшифровки отдаются отдельно с другого сервера, плеер их в кучу собирает.

          nging_proxy это решение для веб-страниц, css/js и мелких картинок. Конечно оно будет работать криво, если через его медафайлы гонять. По моим комментариям можно понять, что я категорически против такой схемы.
  • +3
    > К примеру, RAID0 из шести ssd дисков при 100% загруженности очереди ввода-вывода давал скорость как у двух дисков.

    Не потому ли, что в Линуксе (если речь о нём, конечно), подсистема ввода-вывода (за исключением последних двух релизов, но вряд ли в серьёзном продакшне всегда самое распоследнее ядро) однопоточна?
    • 0
      Возможно, у каждого устройства своя очередь. Соответственно несколько устройств параллелится, а вот с одним шустрым могут быть проблемы.
      • +2
        Не-а. До blk-mq в ядре была одна очередь на все устройства.

        kernel.dk/systor13-final18.pdf

        См. рис. 2.
        • 0
          Нда, всё было хуже, чем я думал. Тогда не вижу разницы особой между 1 шустрым устройством и много не очень шустрых с точки зрения ядра.
          • 0
            Ну пока одна очередь справляется, это не так. А когда не справляется — да, разницы нет.
        • 0
          Там довольно интересная ситуация — и после blk-mq в ядре одна очередь на все устройства, не использующие новый фреймворк. Пока переделали только пару драйверов для PCI-E SSD, которые не являются SCSI-устройствами. Поддержка SCSI ожидается в 3.17.
          • 0
            Да, так и есть. Более того, они ещё и планировщик ввода-вывода будут под это дело менять.
  • 0
    А что мешает масштабировать задачу горизонтально вместо извращений с вытягиванием максимума из одного сервера? Когда добавится третий канал — что будете делать?

    Принимаете соединения на балансировщик. Тот раскидывает запросы по nginx'ам. Если вы не можете позволить себе балансировщик, вытягивающий десятки гигабит — настройте DSR, и тогда пакеты от клиентов до сервиса будут идти через балансировщик, а обратно — в обход. Плюс варианты вроде «запросы к четным файлам кидаются на один сервер, к нечетным — на другой» (а вот тут уже можно существенно повысить процент попаданий в RAM кеш).
    • 0
      Ничего не мешает, и это не единственный канал.

      Как я уже упоминал выше, пропускать трафик через балансировщик — не единственный способ менеджить трафик.
      • 0
        Есть еще геобалансировка. Подход местами неизбежный, но тяжело управляемый и не избавляющий от необходимости в балансировке на каждой локации.
  • –2
    «Такую полосу по очевидным причинам нельзя раздавать прямо из хранилища, необходимо применить кэширование. » — эмм, кеширование тут каким местом то?

    И далее вода-вода-вода и «Как упомянуто выше, кэшировать будем nginx-ом.»

    «Практика показала, что выгоднее поделить файлы между дисками целиком, используя раздельные файловые системы. » Да об этом как-бэ и зравый смысл всегда намекал.

    Если честно, то после прочтения впечателние какой-то неполноты. Хотите матчасть — пишите же её, хотите кучу конфигов — кладите в публичный репозиторий(главное без lua в конце).
    А так очередной вброс непонятно чего без четкой идеи и реализации получился.
    • +2
      Да почему вброс то, автор описал работающее решение своей задачи. Единственное замечание к нему это то, что он не описал подробнее свой профиль нагрузки, из-за чего в ветке выше образовалось некоторое непонимание.

      Еще раз, задача описана. Решение приведено. Рассказано несколько сумбурно, но в комментариях автор указал, что в его случае попадания в кэш составляют 95%, что дает достаточно полное понимание задачи и подхода к ее решению. Где тут вброс?
  • 0
    Коллеги, которые занимались нагрузочными CDN'ами, объясните, чем плоха схема, когда у нас на серверах по 128/256 Гб оперативной памяти, которая работает как кэш (+ уникальная балансировка по таким серверам)? 5-10% от хранимого объема замечательно туда попадают, а больше, в принципе, и не требуется
    • 0
      В принципе, тут ответ уже есть
      ruhighload.com/post/%D0%A4%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2%D1%8B%D0%B9+%D1%85%D0%BE%D1%81%D1%82%D0%B8%D0%BD%D0%B3+%D0%BD%D0%B0+500%D0%A2%D0%B1
      Для раздачи используют ту систему кэширования, что работает на серверах хранения, но в другой конфигурации. Базовым хранилищем являются SSD диски, а быстрым кэшем — оперативная память, на которую приходится больше половины генерируемого трафика.

      Когда объем данных много больше оперативной памяти, то нужен промежуточный дисковый кэш (SSD), который составляет те самые 10-30%, а уже 10-30% от него кладется в оперативную память (т.е. в оперативной памяти 1-9% от общего объема, и это более-менее эффективно работает).
    • +1
      Эта схема плоха, когда ваших 256 Гб оперативной памяти не хватает на горячую зону и в итоге серия первого сезона доктора хауса выталкивает из кеша свежевышедшую игру престолов.

      Основная проблема — алгоритм заполнения кеша и выкидывания из него данных.
      • 0
        Можно монтировать память как виртуальный диск и копировать туда файлы точно так же, как и на ssd, используя свои алгоритмы. Но если кэша не хватает, то его не хватает, тут ничего не сделаешь.

        Мы вообще использовали тройную схему: сервер с 36 винтами, к нему цепляли 1 терабайтные SSD (напрямую в материнскую плату, мимо экспандеров), и ставили на этот сервер 256ГБ памяти. Если данные влазят на один-два таких сервера — отличное решение, позволяющее раздавать по 40-50Гбит с сервера и не гонять данные по сети. Но если серверов больше, то отдельные кэши уже работают эффективнее.
        • 0
          Да, PCI SSD хорошо.

          Потому что если втыкать их через обычный SATA, то они быстро захлебываются.
          • 0
            Это миф про SATA, серьезно. Мы выжимали 45Гбит с обычных SATA SSD, и это было очень близко к их теоретической производительности. Проблемы есть только если подключать через экспандер. Многие так и делают, отсюда и мысли про то, что sata тормозит. Правда, корпус, что позволяет подключать 24 диска без экспандеров, пришлось заказывать из Штатов и ждать месяц. Но решения на PCI-ex получаются существенно дороже (в разы, при сравнимой емкости) и толку в них не очень много. Для кэша в рейде, возможно, преимущества есть и для этого их и берут. Но не для раздачи.

            З.Ы. В 36дисоквый сервер все стало без костылей. Винты пошли через экспандеры, а SSD вставили в корзинку для системных дисков и подключили к SATA портам материнки. Именно такое «напрямую» я имел в виду.
            • 0
              Да, экспандер.

              А вы имеете ввиду именно материнску плату с 24 разъёмами SATA?
              • 0
                Нет, материнка обычная. Обычно, проблема в корпусе, винты подключаются безальтернативно в экпандер и все. Мы нашли корпус, который позволяет напрямую соединять 4 винта с контроллером через mini-SAS. В итоге, 3 контроллера LSI-9210 через 6 проводов присоединяют 24 винта. Порты у материнки спободные, можно под системный винт использовать или еще как-то. еще 4 порта занято сетевыми картами (intel x520-DA2).

                Такая конфигурация сама по себе выдает 45Гбит (диски intel 520 серии по 240ГБ). Добавив к этому 256 памяти (240 под хранилище) выжали 80.
                • 0
                  Ага, понял вас.

                  Большое спасибо за такие детали.
  • +2
    Позволю себе предложить маленькое улучшение.

    if ($cache_zone = 0) { return 481; }
    if ($cache_zone = 1) { return 482; }
    ...
    if ($cache_zone = 9) { return 490; }
    error_page 481 = @cache1;
    error_page 482 = @cache2;
    ...
    error_page 490 = @cache10;
    


    Можно заменить на:
    if ($cache_zone = 0) { error_page 418 = @cache1; return 418; }
    if ($cache_zone = 1) { error_page 418 = @cache2; return 418; }
    ...
    if ($cache_zone = 9) { error_page 418 = @cache10; return 418; }
    

    Шуточный 418 обычно используется для таких goto переходов.
    Мне кажется, логику можно реализовать и без lua, но пока не готов представить рабочую альтернативу.
    • +5
      Позволю себе улучшить это улучшение :)
      director может состоять из этого:
      error_page 418 = @cache$cache_zone;
      return 418;
      

      Т.е. можно обойтись и без include.
      При указании named location можно использовать переменные.
      Главное, чтобы такой location был (иначе будут возвращаться 500 ошибки could not find named location "@x").
      • 0
        Ооо, вот это шикарно, благодарю Вас!

        Без lua не реализовать логику деления и замен, как мне кажется.
  • 0
    Объясните, пожалуйста, за что отвечает «bytes on» в конфиге nginx.

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