Многие провайдеры на постсоветском пространстве самых разных масштабов предоставляют услуги Интернет по VPN туннелю, будь то PPPoE или PPTP/L2TP. О плюсах и минусах такого доступа я не буду рассказывать, т. к. данная тема смело поместиться в отдельную статью. Как правило для такого туннелирования используются либо серьезные железки (Cisco, Juniper, etc), либо софт-роутеры на базе FreeBSD и MPD5. Так вот, в этой статье пойдет речь о балансировке нагрузки на MPD5 серверы. На хабре уже был подобный топик, но там рассматривалось PPPoE, сегодня же разберем ситуацию с PPTP/L2TP.
Теория
Самый простейший способ балансировки VPN серверов — это так называемый Round robin DNS. Выполнив команду nslookup vpn.iformula.ru, увидим следующее:
nslookup vpn.iformula.ru Server: 193.93.236.2 Address: 193.93.236.2#53 Name: vpn.iformula.ru Address: 10.168.1.103 Name: vpn.iformula.ru Address: 10.168.1.101 Name: vpn.iformula.ru Address: 10.168.1.102
(можете попробовать nslookup yandex.ru — так же используется Round robin DNS)
Т.е. Клиент, посылая запрос к DNS серверу получает в ответ первый адресс из списка, запрос второго — следующий адресс и так далее по кругу. В принципе такой балансировки было бы достаточно, если бы не несколько обстоятельств:
- Не все серверы обладают одинаковой конфигурацией и производительностью
- При кратковременно падении одного из серверов, все его клиенты подключаться на оставшиеся сервера
Создается дисбаланс, который естественным путем может сглаживаться достаточно долго.
Выход из этих ситуаций прост: нужно мониторить количество одновременных сессий пользователей и при достижении максимальной нагрузки на сервер или его аварийном отключении, перестать анонсировать в DNS его ip-адресс. Разумеется, мы автоматизируем это с помощью shell скрипта.
Практика
1. Нам нужно получить информацию о количестве текущих сессий и максимально-допустимом количестве сессий. В MPD5 есть управление через telnet и webcmd. Я выбрал webcmd, так как в этом случае мне нужно просто получить html страницу и распарсить ее, нежели писать обработчик для telnet CLI на Expect. Включить web управление:
set user $ROOT $PASSWORD admin
set web self 0.0.0.0 5006
После перезапуска mpd по адресу 0.0.0.0:5006 будет доступна различная информация. Получить информацию о сессиях можно так: http://$login:$password@0.0.0.0:5006/cmd?show%20ippool
[] show ippool
Available IP pools:
pool1: used 1293 of 2047
2. Настроим DNS сервер. Я использую BIND9, который является стандартным в FreeBSD. Я предполагаю, что у вас уже есть настроенный DNS сервер с обслуживаемой зоной. Все что нам нужно, это добавить в эту зону $INCLUDE на автоматически генерируемый файл с списком VPN серверов:
$INCLUDE /var/named/etc/namedb/vpn ;
;host names
iformula.ru. IN A 193.93.236.126
3. Добавляем скрипт автоматизации в планировщик cron на выполнение каждые 30 минут. Разумеется, запускать скрипт нужно на сервере, где работает DNS демон.
echo "*/30 * * * root /usr/local/bin/mpd_balancer" >> /etc/crontab
echo "" >> /etc/crontab
Разберем скрипт
Параметры:
login="foo"
# имя пользователя
password="bar"
# и пароль для доступа к Webcmd MPD5
prcload="90"
# максимально допустимое количество одновременных сессий на одном сервере в процентах
name="vpn.example.com."
# имя службы VPN, точка в конце обязательна
srvlist="/root/srv"
# Пукть к файлу со списком vpn серверов
conf="/var/named/etc/namedb/vpn"
# путь к генерируемому $INCLUDE со списком vpn серверов, доступных клиентам
workdir="/tmp"
# директория для временных файлов
Получим HTML страницу с информацией о сессиях:
fetch -o $workdir/$ipsrv -q "http://$login:$password@$ipsrv:5006/cmd?show%20ippool" > /dev/null 2>&1
Распарсим количество активных и максимальных сессий для сервера:
mpdsrv="`cat "$workdir/$ipsrv" | grep used | awk '{print ($3)}' `"
maxloadsrv="`cat "$workdir/$ipsrv" | grep used | awk '{print ($5)}' | tr -d "1532" `"
Используя консольный калькулятор bc, посчитаем текущую загрузку сервера в процентах (проценты округляются до целых):
loadsrv="`echo "$mpdsrv/($maxloadsrv/100)" | bc`"
Если загрузка не превышает заданный процент, добавляем адресс сервера в список доступных, нагруженные и недоступные сервера просто комментируем:
if [ "$loadsrv" -lt "$prcload" ]
then
echo "$name IN A $ipsrv" >> $conf
else
echo ";$name IN A $ipsrv" >> $conf
fi
Так же, если просто запустить скрипт из консоли, получим вот такие данные:
#######################################################################
10.168.1.100 hosts 739 sessions and this is 49% of maximum load
10.168.1.101 hosts 1192 sessions and this is 70% of maximum load
10.168.1.102 hosts 1304 sessions and this is 65% of maximum load
10.168.1.103 hosts 138 sessions and this is 27% of maximum load
10.168.1.104 hosts 24 sessions and this is 24% of maximum load
#######################################################################
На основании этих данных можно рисовать красивые графики:
В скрипте используются утилиты bc, fetch и rndc — все это есть в стандартной поставке FreeBSD. Скрипт протестирован на FreeBSD 8.3, для Linux придется заменить fetch на wget. Поддерживает любое количество mpd5 серверов.
Скрипт:
Документация по MPD5
Документация по BIND9
Справочник по sh
Блог автора
Комментарии, предложения, вопросы и замечания приветствуются. Спасибо за внимание.
Автор: Ne_Palimsa