Раньше, когда надо было распределить нагрузку на несколько серверов, мы прописывали несколько A-записей с одним именем в DNS-зоне, и все работало. Запросы клиентов распределялись примерно поровну. Особенно актуален такой способ балансировки был для раздачи статитического контента.
Недавно наш клиент обратился к нам с проблемой:
В ЧНН начинались проблемы с загрузкой различных флешек — файлы загружались по несколько минут.
Расследование выявило неравномерную загрузку одного из серверов раздачи статики — он отдавал в разы больше трафика в сеть, чем все остальные. Причем периодически нагрузка переходила от одного сервера к другому.
В DNS зоне было прописано что-то типа:
cdn.exampe.com IN A 192.168.10.1 cdn.exampe.com IN A 192.168.12.1 cdn.exampe.com IN A 192.168.15.1 cdn.exampe.com IN A 192.168.16.1 cdn.exampe.com IN A 192.168.11.1 cdn.exampe.com IN A 192.168.19.1
Раньше клиенты получали ответы от DNS-серверов по алгоритму round-robin, но поиск проблемы привел к совершенно неожиданному результату!
Запросы к DNS серверу по адресу 8.8.8.8 неизменно возвращали один и тот же адрес.
Никакого round-robin. Возвращаемый адрес мог смениться, если заканчивался TTL, а мог и не измениться.
Техподдержка корпорации добра ответила в стиле «мы лучше вас знаем, что именно вам надо».
DNS Round Robin has never been an effective means of load-balancing, and is less so today, as applications switch from gethostbyname to getaddrinfo for IPv6 support:
homepage.ntlworld.com/jonathan.deboynepollard/FGA/dns-round-robin-is-useless.html
www.tenereillo.com/GSLBPageOfShame.htm
daniel.haxx.se/blog/2012/01/03/getaddrinfo-with-round-robin-dns-and-happy-eyeballs
RRDNS никогда хорошо не работало, а дальше будет еще хуже. И когда наступит IPv6, станет совсем плохо…
Вот такое мнение у корпорации добра, и никакие графики нагрузки переубедить ее не смогли.
Дальнейшее расследование проблемы показало, что проблема не только в Google, но и в Hetzner, в котором хостится зона.
Проблема номер раз:
Каждый из гугло-серверов передает ответы точно такими же, какими получил от DNS-серверов, обслуживающих зону, ничего не изменяя в них. Если каждый из серверов получает свой вариант последовательности, то при последовательных запросах складывается впечатление, что Google отдает адреса в случайном порядке, хотя на самом деле это ответы отдаются со случайно выбранного сервера.
Проблема номер два:
Хетцнер, в котором хостится проблемная DNS-зона, начал отдавать список адресов для хоста неизменным.
И в итоге на всех гугло-серверах оказалась одинаковая последовательность адресов.
Ответ от ТП Hetzner также не порадовал:
This function is not enabled on our DNS-resolvers. If you want to use that kind of loadbalancing, you have to setup and use your own servers.
Конечно, можно обратиться к платным поставщикам услуг CDN или сказать программистам, чтобы они генерировали ссылки на контент, которые указывают на конкретные сервера (естественно, для каждого запроса сервер в ссылке берется случайным образом, чтобы распределить нагрузку).
Но с админов обычно требуют решить проблему быстро, и чтоб работало сейчас.
А уже потом можно будет поискать решение получше.
Возвращаем редирект на конкретный сервер средствами nginx:
Воспользуемся директивой split_clients, распределим проценты согласно мощности наших серверов и пропишем на каждом из них вот такой конфиг.
Естественно, в строке hostname cdn1.example.com; указываем свое уникальное имя для каждого из серверов.
http {
split_clients "${remote_addr}AAA" $variant {
15% 1;
15% 2;
15% 3;
15% 4;
15% 5;
15% 6;
* 7;
}
server {
listen 80;
server_name cdn.example.com;
return 302 http://cdn$variant.example.com/$request_uri;
}
server {
listen 80;
server_name cdn1.example.com;
location / {
root /srv/www/cdn.example.com/htdocs;
}
}
В итоге nginx возвращает пользователю редиректы на сервер, который определяется на основании хеша ip адреса клиента.
Вот такое вот распределение нагрузки.
PS: Перевели зону с Хетцнера в Яндекс