Pull to refresh

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

Reading time 3 min
Views 42K

Предистория



Рано или поздно системный администратор сталкивается с необходимостью распределить трафик по нескольким каналам, при этом естественно желание чтобы каждый канал использовался по максимуму. Столкнувшись с подобной необходимостью, и решив не изобретать велосипед, обратился к помощи поисковиков. Так как сервер у меня на 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 абонентами. Кроме балансировки используется динамический шейпинг, но это уже тема для другой статьи.

Всем баланса во всем.
Tags:
Hubs:
+50
Comments 24
Comments Comments 24

Articles