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

Лучшие времена наступили в конце декабря 2012 года. Приближалась новогодняя ночь с пиковой нагрузкой, которую хотелось пережить без падений. Опасаясь высокой нагрузки, я организовал вещание основных федеральных телеканалов с двух дополнительных серверов, поскольку только на них планировались какие-то масштабные новогодние передачи. На тот случай, если бы поведение зрителей оказалось отличным от предполагаемого, или если бы не хватило возможностей серверов — я приготовился к введению ограничений для внешних пользователей. Лишать их телевидение полностью — не хотелось, а вот ограничить количество каналов доступных к просмотру только федеральными (которые раздавались с трёх серверов с общим каналом в 3 Гбит\с) — почему бы и нет?

Так как вещание идет с одного порта, ограничить пользователей с помощью iptables так просто не получилось бы. Можно было бы завернуть трафик через nginx и ограничивать пользователей с его помощью, но ранее я этого не делал, а на эксперименты времени почти не оставалось. В итоге мне вспомнилась старая идея с персональными плейлистами, реализацией которой я и занялся путём наименьшего сопротивления.

У веб-сервера Nginx есть чудесный модуль — ngx_http_geo_module. С его помощью можно задать некую переменную, если IP-адрес клиента относится к определенной подсети. Конфигурация не сложная:

geo $locate {

default ext;

#Внутренние сети
192.168.1.0/24 int;
192.168.4.0/24 int;
192.168.8.0/24 int;
}

Добавив это в конфиг Nginx где-нибудь перед секцией server, мы получим переменную $locate, которая по-умолчанию имеет значение ext, но если IP-адрес клиента соответствует одной из перечисленных подсетей — принимает значение int.

Научившись понимать, какой клиент свой — int, а какой чужой — ext, остается просто отдать нужный плейлист. За это отвечает следующий location в конфигурации server’а:

location /playlist.m3u {

if ($locate = ext) {
return http://mywebserver.example/playlist/playlist_ext.m3u;
}

if ($locate = int) {
return http://mywebserver.example/playlist/playlist_int.m3u;
}

}

При запросе /playlist.m3u происходит проверка переменной $locate, если она равна ext — отдается один плейлист, если int — то другой. Остается только отредактировать плейлисты так, как хочется. Внутренний плейлист я не изменял, а во внешнем оставил те каналы, которые вещались с 3 серверов.

Разумеется, это не полноценное ограничение. Скорее это одна из частей комплексной системы управления доступом. Подобное решение бесполезно в том случае, если клиент использует сохраненный плейлист, а не обращается за ним на сервер каждый рза. Так же оно не защищает от тех клиентов, которые помнят адреса потоков. Но в моем случае этого было вполне достаточно.

P.S.

Всю новогоднюю ночь я внимательно следил за загрузкой каналов, готовясь задействовать эту систему. Но так и не пришлось — пользователи вели себя хорошо и по большей части смотрели именно те каналы, раздачу которых вели 3 сервера. При суммарном трафике около 1,8 Гбит\с всё было хорошо 🙂

 

Разные плейлисты для разных групп зрителей
Метки:    

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *