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

в 7:46, , рубрики: linux, балансировка нагрузки, балансировка трафика, Сетевые технологии, метки: , ,

Предистория

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

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

Автор: Redor

Источник

Поделиться

* - обязательные к заполнению поля