Комбинированная балансировка нагрузки интернет-каналов

от автора

Предистория

Рано или поздно системный администратор сталкивается с необходимостью распределить трафик по нескольким каналам, при этом естественно желание чтобы каждый канал использовался по максимуму. Столкнувшись с подобной необходимостью, и решив не изобретать велосипед, обратился к помощи поисковиков. Так как сервер у меня на Ubuntu, то обратил свое внимание на статью http://help.ubuntu.ru/wiki/ip_balancing. Реализовал «Способ 1», но при тесте были замечены следующие критичные проблемы: при использовании ссылок на некоторых сайтах они не открывались (например при попытке включить музыку на ресурсе «ВКонтакте»). Причина очевидна — запрос шел через другой канал. Обдумав ситуацию, решил скомбинировать подход к балансировке. Логика проста — больше всего съедает трафика торренты и им подобные программы, поэтому разделяем трафик. В итоге трафик с портами до 11000 распределяем приблизительно равномерно по количеству абонентов — подсетями, трафиком с портами 11000-60000 выравниваем загрузку каналов.

Настройки

Предполагается что созданы таблицы маршрутизации для каждого из каналов, назовем их chan1, chan2, chan3 — три канала соответственно.
Где-нибудь, например в /etc/rc.local добавляем что-то вроде:

ip rule add prio 101 fwmark 1 table chan1 ip rule add prio 102 fwmark 2 table chan2 ip rule add prio 103 fwmark 4 table chan3 

Создаем скрипт /etc/rc.balance:

#!/bin/bash  lst='/etc/rc.balance.lst'  ########### Flushing ################## /sbin/iptables -t mangle -F PREROUTING /sbin/iptables -t mangle -F POSTROUTING /sbin/iptables -t mangle -F OUTPUT #######################################  /etc/rc.baltor  /sbin/iptables -t mangle -A PREROUTING -d 172.16.0.0/16 -j RETURN /sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/16 -m state --state INVALID -j DROP  while read net mark do     /sbin/iptables -t mangle -A PREROUTING -s $net -m state --state new,related -j CONNMARK --set-mark $mark done<$lst  /sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/16 -p udp --sport 11000:60000 --dport 11000:60000 -m state --state new,related -j BALANCE /sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/16 -p tcp --sport 11000:60000 --dport 11000:60000 -m state --state new,related -j BALANCE  /sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/16 -j CONNMARK --restore-mark  exit 0 

Создаем список распределения сеток по каналам (во второй колонке — марка):

172.16.0.0/22		1 172.16.4.0/22		2 172.16.8.0/22		4 

Скрипт /etc/rc.baltor — правила балансировки:

#!/bin/bash  /sbin/iptables -t mangle -F BALANCE  lst='/etc/rc.cnload.lst' mrk=1  while read kld do     /sbin/iptables -t mangle -A BALANCE -j CONNMARK --set-mark $mrk     /sbin/iptables -t mangle -A BALANCE -m statistic --mode random --probability 0.$kld -j RETURN     mrk=`expr $mrk \* 2` done < $lst  /sbin/iptables -t mangle -A BALANCE -j CONNMARK --set-mark $mrk  exit 0 

Скрипт /etc/rc.cnload — расчет вероятности в зависимости от загрузки канала:

#!/bin/bash  cn1=800000 # ширина первого канала в килобитах в секунду cn2=600000 # второго .. cn3=400000 # и третьего if1='eth1' # интерфейс первого канала if2='eth2' # второго if3='eth3' # третьего  lst='/etc/rc.cnload.lst'  a1=`ifconfig $if1 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'` a2=`ifconfig $if2 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'` a3=`ifconfig $if3 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'` sleep 20 b1=`ifconfig $if1 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'` b2=`ifconfig $if2 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'` b3=`ifconfig $if3 | grep "RX bytes" | awk '{print $2}' | awk -F: '{print $2}'`  c1=`expr \( $b1 - $a1 \) \* 8 / 20000` c2=`expr \( $b2 - $a2 \) \* 8 / 20000` c3=`expr \( $b3 - $a3 \) \* 8 / 20000`  d1=`expr \( $cn1 - $c1 \) \* 100 / $cn1` d2=`expr \( $cn2 - $c2 \) \* 100 / $cn2` d3=`expr \( $cn3 - $c3 \) \* 100 / $cn3`  # выполняем корректировку при загрузке одного из каналов более 60% if [ $d1 -lt "40" -o $d2 -lt "40" -o $d3 -lt "40" ] then     e1=`expr 100 \* $d1 / \( $d1 + $d2 + $d3 \)`     e2=`expr 100 \* $d2 / \( $d2 + $d3 \)`     f1=`head -n 1 $lst | tail -n 1`     f2=`head -n 2 $lst | tail -n 1`     # корректировка если коэффициенты изменились      if [ $e1 -ne $f1 -a $e2 -ne $f2 ]     then         echo $e1 > $lst         echo $e2 >> $lst         /etc/rc.baltor     fi fi  exit 0 

Добавляем в /etc/rc.local

/etc/rc.balance 

и в /etc/crontab

*/1 *	* * *	root    /etc/rc.cnload 

Важно, чтобы на момент старта уже существовал файл с коэффициентами /etc/rc.cnload.lst, его можно составить запуском скрипта /etc/rc.cnload.

Заключение

Данный метод упешно реализован в сети с 8000 абонентами. Кроме балансировки используется динамический шейпинг, но это уже тема для другой статьи.

Всем баланса во всем.

ссылка на оригинал статьи http://habrahabr.ru/post/157401/


Комментарии

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

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