CDN на коленке: Часть 1. Geo DNS

Сеть доставки контента (Content Delivery Network) или CDN может быть крайне полезна при отдаче статического контента, такого как картинки, css и javascript. CDN позволяет сократить время загрузки страницы в браузере за счет нескольких моментов:

  1. контент размещен на сервере который располагается наиболее близко к пользователю, что существенно увеличивает скорость загрузки;
  2. распределение запросов по разным доменам, а все современные браузеры имеют лимит на количество одновременных подключений к одному домену.

Однако очень небольшое число сайтов в интернете использует cdn. Основная тому причина — тарифы на услуги CDN начинаются от нескольких тысяч рублей в месяц. Для тех кто платит за хостинг или VPS 200-500 рублей в месяц дороговато.

Я хочу рассказать о варианте создания своего CDN, причем его стоимость на порядок ниже тарифов таких компаний как CDNvideo, NGENIX или Akamai.

Начнем с первой части задачи, необходимо отдавать контент с сервера который находится наиболее близко к конечному пользователю. Наиболее эффективно, на мой взгляд, сделать это с помощью DNS. Есть несколько вариантов реализации такого сценария:

  1. GeoDNS BIND patch — патч в 40 строк добавляющий к функционалу views сервера BIND возможность взаимодействие с MaxMind’s GeoIP C API
  2. elegant Linux BASH script that can be used to help configure BIND to be geo-aware
  3. powerdns + geo backend

Я остановился на втором варианте, о нем речь далее и пойдет. Для примера настройки буду использовать домен cdn.rascal.su.

Итак, первое что нам понадобится это скрипт GeoIP.sh который мы берем отсюда.

Скрипт выполняет половину работы:

root@ns1:/etc/bind# mkdir geo
root@ns1:/etc/bind# cd geo
root@ns1:/etc/bind/geo# wget http://cdn.rascal.su/uploads/2012/12/GeoIP.sh_.gz
root@ns1:/etc/bind/geo# gunzip GeoIP.sh_.gz
root@ns1:/etc/bind/geo# bash GeoIP.sh_
--2012-12-15 16:58:40--  http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
Resolving geolite.maxmind.com (geolite.maxmind.com)... 174.36.207.186
Connecting to geolite.maxmind.com (geolite.maxmind.com)|174.36.207.186|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1574629 (1.5M) [application/zip]
Saving to: `GeoIPCountryCSV.zip'

100%[=========================================================>] 1,574,629    509K/s   in 3.0s

2012-12-15 16:58:44 (509 KB/s) - `GeoIPCountryCSV.zip' saved [1574629/1574629]

Creating CBE (Country,Begin,End) CSV file...DONE
Generating BIND GeoIP.acl file...DONE

На выходе работы скрипта получаем GeoIP.acl, который содержит соответствие ip-адреса и страны в формате BIND ACL. Пришла очередь настройки view в named.conf.

include "/etc/bind/geo/GeoIP.acl";

# CDN for SNG
view "russia" {
    match-clients { AM; AZ; BY; GE; KG; KZ; RU; TM; TJ; UA; UZ; };
    recursion no;

    zone "cdn.rascal.su" {
        type master;
        file "/etc/bind/master/ru.cdn.rascal.su";
    };
};

# CDN for Others
view "global" {
    match-clients { any; };
    recursion no;

    zone "cdn.rascal.su" {
        type master;
        file "/etc/bind/master/de.cdn.rascal.su";
    };

};

Файл зоны ru.cdn.rascal.su:

$ORIGIN .
$TTL 3600       ; 1 hour
cdn.rascal.su           IN SOA  ns1.rascal.su. hostmaster.rascal.su. (
                                2          ; serial
                                900        ; refresh (15 minutes)
                                600        ; retry (10 minutes)
                                86400      ; expire (1 day)
                                3600       ; minimum (1 hour)
                                )
$TTL 0  ; 0 seconds
                        NS      ns1.rascal.su.
                        NS      ns2.rascal.su.
$TTL 3600       ; 1 hour
                        A       62.76.187.192

Файл зоны de.cdn.rascal.su:

$ORIGIN .
$TTL 3600       ; 1 hour
cdn.rascal.su           IN SOA  ns1.rascal.su. hostmaster.rascal.su. (
                                2          ; serial
                                900        ; refresh (15 minutes)
                                600        ; retry (10 minutes)
                                86400      ; expire (1 day)
                                3600       ; minimum (1 hour)
                                )
$TTL 0  ; 0 seconds
                        NS      ns1.rascal.su.
                        NS      ns2.rascal.su.
$TTL 3600       ; 1 hour
                        A       78.47.49.45

На всех DNS-серверах должен использоватьcя тип master для зон, а их синхронизация должна выполняться внешними средствами.