Рубрики
Kamailio

Kamailio часть 8. Балансировка в SIP протоколе через dispatcher модуль Kamailio с детальным разбором примеров

В этой статье мы рассмотрим модуль dipatcher, с помощью которого осуществляется балансировка нагрузки в Kamailio

Kamailio dispatcher модуль обеспечивающий балансировку

Возьмем схему из вводной части (Архитектура VoIP сервиса с использованием Kamailio):

kamailio load balance scheme

По схеме видно, что у нас есть множество Media серверов (это может быть Asterisk или FreeSWITCH, или любой другой media сервер). И нам через Kamailio необходимо выполнять балансировку на медиа сервера. Как это можно сделать?

  1. Вручную через конфигурационный файл прописывать маршруты
  2. Использовать готовый модуль с удобным API

Как вы понимаете, второй способ предпочтительнее. Давайте более подробно разберемся с подключением dispatcher модуля, с указанием необходимых параметров модуля и реализуем это на практике.

Алгоритмы балансировки в dispatcher модуле Kamailio

В версии Kamailio 5.4 (на которой я показываю все примеры), существует 13 алгоритмов балансировки, очень кратко приведу их:

  • 0, балансировка на основе поля callid, hash callid
  • 1, балансировка на основе поля From, hash over From URI
  • 2, балансировка на основе поля To, hash over To URI
  • 3, балансировка на основе Request-URI, hash over Request-URI
  • 4, балансировка с помощью алгоритма Round-Robing
  • 5, балансировка на основе авторизационных данных (Proxy-Authorization), если поле в SIP сообщении не найдено, используется Round-Robin
  • 6, случайный выбор (random)
  • 7, балансировка на основе hash псевдопеременных, hash over pv
  • 8, Балансировка на основе приоритета
  • 9, балансировка на основе веса (weight)
  • 10, балансировка на основе загрузки. Выбирается хост с наименьшей нагрузкой
  • 11, балансировка на основе относительного веса. Отличие от алгоритма №9 — пересчет вероятности при включении/выключении нового хоста
  • 12, отправка на все доступные хосты одновременно, serial forking

В сегодняшней статье мы будем использовать алгоритм №4 Round-Robin, но в будущем для конференций будет использоваться алгоритм №7.

Принцип работы dispatcher модуля в Kamailio

Давайте предположим, что у нас два media сервера (asterisk/freeswitch/etc…) и один(пока) балансировщик Kamailio. Во-первых нам необходимо добавить media сервера в dispatcher список. Это может быть как физический файл в файловой системе сервера который задается следующим параметром:

modparam("dispatcher", "list_file", "/var/run/kamailio/dispatcher.list")

Где /var/run/kamailio/dispatcher.list — абсолютный путь в файловой системе сервера.

Или же список может быть задан через базу данных (mysql, postgres):

modparam("dispatcher", "db_url", "mysql://user:passwb@localhost/database")

В цикле статей при возможности использования БД, мы этой возможностью всегда пользуемся. Использование БД позволяет хранить все необходимые данные в одном месте с возможностью их использования на множестве серверов. Как создавать и подключать базу данных рассматривалось в первой части (Подключение базы данных в Kamailio) цикла статей.

После добавления хостов в dispatcher список (в файл или в БД) необходимо выбрать какой алгоритм балансировки использовать для входящих запросов INVITE. В нашем случае мы будем использовать алгоритм №4 Round-Robin, т.е последовательно отправлять вызовы на следующий хост из dispatcher списка.

Например, на Kamailio пришло 4 запроса INVITE от 4-х разных абонентов. Всего в dispatcher списке два SIP сервера FreeSWITCH (один на порту 5090, другой на порту 5095). При балансировке через Round-Robin первый запрос INVITE отправится на первый FreeSWITCH (на порт 5090), второй запрос INVITE от второго абонента, отправится на второй FreeSWITCH (на порт 5095), третий запрос INVITE от третьего абонента отправится на первый FreeSWITCH (на порт 5090), четвертый запрос INVITE от четвертого абонента отправится на второй FreeSWITCH (на порт 5095).

Т.е для каждого INVITE запроса мы будем использовать следующий по списку FreeSWITCH.

Т.к мы выполняем балансировку только абонентских вызовов (INVITE запросов) нам нет надобности изменять остальной конфиг, все остальные SIP запросы (ACK, CANCEL, BYE) будут обрабатываться как и раньше.

Но давайте представим, что у нас один из серверов FreeSWITCH стал недоступен (не важно по какой причине), как изменится алгоритм работы Kamailio? Для этого в модуле dispatcher есть возможность проверки (healthcheck) SIP сервера из dispatcher списка. Kamailio по умолчанию будет отправлять запросы OPTIONS (можно изменить) на сервера из dispatcher списка с определенными промежутками. Давайте посмотрим как это делается:

modparam("dispatcher", "ds_ping_interval", 30)

Т.е указывая параметр ds_ping_interval — мы задаем периодичность отправки healtcheck.

С помощью параметра ds_probing_threshold (по умолчанию количество попыток = 1) задается необходимое количество неудачных попыток, прежде чем хост из dispatcher списка станет недоступным («inactive»)

modparam("dispatcher", "ds_probing_threshold", 2)

В приведенном выше примере, прежде чем SIP сервер (хост) из dispatcher списка станет недоступным, необходимо отправить два неудачных запроса.

Но как убедится, что SIP сервер из dispatcher списка вновь стал доступен и готов принимать вызовы? Это указывается с помощью параметра ds_inactive_threshold (по умолчанию кол-во попыток прежде чем хост станет доступен = 1):

modparam("dispatcher", "ds_inactive_threshold", 5)

Комбинируя три вышеперечисленных параметра мы можем очень гибко настраивать балансировку нагрузки на media сервера в зависимости от доступности media серверов. Сейчас мы задали такие правила:

  1. Период отправки healthcheck — 30 секунд
  2. Счетчик, при котором media сервер становится недоступен — 2, т.е через 60 секунд (2 проверки) сервер будет помечен как неактивный
  3. Количество успешных ответов на healthcheck для восстановления media сервера — 5, т.е когда media сервер ответит 5 раз подряд успешно на healthcheck, он снова сможет принимать вызовы.

Практическое руководство по применению dispatcher модуля в Kamailio

Подготовительная часть (установка и конфигурирование dispatcher модуля)

Давайте рассмотрим на практике, как обеспечить балансировку и отказоустойчивость в Kamailio через модуль dispatcher.

Для начала добавим выполним инициализацию модуля dispatcher в kamailio.cfg:

loadmodule "dispatcher.so"

После чего добавим строку подключения к базе данных к остальным параметрам модулей:

modparam("dispatcher", "db_url", DBURL)

Где DBURL — переменная, созданная в первой части(SIP регистрация в Kamailio) цикла статей.

Далее, добавим параметры для добавления/отключения media серверов в зависимости от их доступности. Для начала добавим период между проверкой доступности (healthcheck через SIP OPTIONS), например каждые 20 секунд:

modparam("dispatcher", "ds_ping_interval", 10)

Количество неудачных попыток проверки доступности, после которой media сервер будет помечен как недоступный — 4:

modparam("dispatcher", "ds_probing_threshold", 4)

Количество успешных ответов, после которого media сервер снова становится активным (доступным) — 4

modparam("dispatcher", "ds_inactive_threshold", 4)

На этом подготовительная часть закончена, перечитываем конфигурационный файл kamailio.cfg, например перезагрузив Kamailio:

systemctl restart kamailio

Я также создам дополнительный SIP профиль FreeSWITCH (FusionPBX) и назначу, чтобы он слушал порт 5095. Этим я сымитирую второй media сервер FreeSWITCH. Как это делается подробно рассматривалось в предыдущей статье (Интеграция между Kamailio и FreeSWITCH)

Маршрутизация с помощью dispatcher модуля в Kamailio

Теперь перейдем непосредственно к маршрутизации.

Для начала внесем наши media сервера в dispatcher список, в БД. Для этого выполним следующие SQL запросы:

psql -h localhost -U kamailio -W kamailio -c "INSERT INTO dispatcher (setid, destination, description) values ('1', 'sip:172.19.0.2:5090', 'media server 1');"

psql -h localhost -U kamailio -W kamailio -c "insert into dispatcher (setid, destination, description) values ('1', 'sip:172.19.0.2:5095', 'media server 2');"

psql — команда для работы с БД postgres, подключаемся к localhost, через пользователя Kamailio, к БД kamailio и с помощью флага ‘-c’ указываем сам SQL запрос (IP адреса необходимо заменить на ваши). После выполнения приведенных команд, у нас необходимо выполнить reload, чтобы Kamailio перечитал таблицу. Это делается с помощью команды:

kamcmd dispatcher.reload

Проверяем какой сейчас у нас dispatcher список, выполняем команду:

kamcmd dispatcher.list

В результате исполнения команды, вывод будет таким:

kamcmd dispatcher list kamailio

Как еще можно проверить, что media сервера (в нашем случае FreeSWITCH) доступны? Можно снять трассировку с помощью sngrep и увидеть, как Kamailio отправляет SIP healthcheck запрос OPTIONS (помните подготовительную часть?)

Изменение kamailio.cfg для обработки INVITE

Далее, нам необходимо поправить основной конфиг файл kamailio.cfg. Первым делом необходимо поправить маршрут DIALOG. Сейчас он выглядит так (приведен только отрывок, который нас интересует):

route[DIALOG] {
        if (!src_ip == '172.19.0.2') {
                setflag(tswitch);
                if (is_method("INVITE")) {
                        route(AUTH);
                        handle_ruri_alias();
                        record_route();
                        route(RELAY);
                }
        } else {
...
}

У нас сейчас захардкожена проверка на IP адрес источника, соответственно нам необходимо это изменить, чтобы проверялся не только IP 172.19.0.2, но и все остальные, которые находятся в dispatcher списке. Для этого мы будет проверять входит ли IP источника в dispatcher список или нет. Воспользуемся функцией модуля dispatcher — ds_is_from_list. Функция принимает в себя следующие значения:

  • groupid — ID группы, в нашем случае мы добавляли media сервера в группу 1
  • mode — указывается, что будет проверятся. Цифра 0 означает, что проверяется совпадения IP, порта и протокола. Цифра 2 означает, что проверяется мы не проверяем порт (эту проверку скипаем). Цифра 2 означает, что мы пропускаем проверку протокола
  • uri — пока не будем использовать, но можно указать статически или динамически SIP URI который будет проверятся в dispatcher списке

Изменим наш маршрут DIALOG следующим образом:

route[DIALOG] {
        if (!ds_is_from_list("1", "2")) {
                setflag(tswitch);
                if (is_method("INVITE")) {
                        route(AUTH);
                        handle_ruri_alias();
                        record_route();
                        route(RELAY);
                }
        } else {
...
}

И также поменяем хардкод в маршруте RELAY. Сейчас проверка флага tswitch выглядит следующим образом:

if (isflagset(tswitch)) {
                rewritehostport("172.19.0.2:5090");
                t_relay();
        }

Соответственно, здесь необходимо указать алгоритм балансировки с помощью функции ds_select_dst которая принимает в себя следующие значения:

  • set — указывается ID группы в dispatcher списке
  • alg — указывается номер алгоритма (все алгоритмы рассматривались в первой части статьи)
  • limit — использовать пока не будем, но указывается максимальное кол-во элементов для failover

Соответственно, поменяем маршрут RELAY, где указывается обработка флага tswitch следующим образом:

if (isflagset(tswitch)) {
                if (is_method("INVITE")) {
                        ds_select_dst("1", "4");
                }
                t_relay();
        }

Добавляем проверку на INVITE, чтобы не сломать маршрутизацию остальных SIP сообщений (BYE, CANCEL и.т.д). Сама функция ds_select_dst у нас использует 1 группу и 4 алгоритм балансировки (round-robin).

Предлагаю посмотреть на это наглядно:

dispatcher round-robin in kamailio

И сами вызовы, чтобы посмотреть на какие media сервера были вызовы отправлены:

kamailio dispatcher round-robin alg
первый вызов отправлен на 172.19.0.2:5095
kamailio dispatcher round-robin alg
второй вызов отправлен на 172.19.0.2:5090
kamailio dispatcher round-robin alg
третий вызов отправлен на 172.19.0.2:5095

Как видно, алгоритм работает корректно и все вызовы успешно завершились.

Обработка NAT в Kamailio

Последнее место в текущем конфиге, где есть хардкод IP — это маршрут NAT, давайте посмотрим на него:

route[NAT] {
        if (nat_uac_test("19")) {
                if (is_method("REGISTER")) {
                        set_contact_alias();
                } else {
                        if(is_first_hop()) {
                                if (!src_ip == 172.19.0.2) {
                                        set_contact_alias();
                                }
                        }
                }
        }
        return;
}

Интересующая нас строка выделена красным цветом. Здесь ничего нового, изменяем хардкод проверку на динамическую через функцию ds_is_from_list (разбиралась ранее):

route[NAT] {
        if (nat_uac_test("19")) {
                if (is_method("REGISTER")) {
                        set_contact_alias();
                } else {
                        if(is_first_hop()) {
                                if (!ds_is_from_list("1", "2")) {
                                        set_contact_alias();
                                }
                        }
                }
        }
        return;
}

Заключение

Сегодня мы рассмотрели один из ключевых модулей Kamailio — dispatcher. Разобрались, какие алгоритмы балансировки сущесвуют, реализовали один из них и удалили весь хардкод из текущего конфига.

В следующей статье мы разберемся, что делать если media сервер станет недоступен, а Kamailio еще не выведен этот сервер в inactive (т.е не успеет пройти healthcheck). Для этого мы добавим обработку ошибок через failure_route, но это уже в следующей статье.

Если есть желание сделать пожертвование, то это можно сделать кликнув по ссылке или же нажав на кнопку. Спасибо за поддержку !)

Для зарубежных платежных систем/карт

10 ответов к “Kamailio часть 8. Балансировка в SIP протоколе через dispatcher модуль Kamailio с детальным разбором примеров”

Спасибо за труды, прочитал на одном дыхании. Камаилио казалось чем-то сложным, после статей все стало проще.

Доброго времени суток,
а для чего в итоговом конфиге на гит в руте DIALOG введена дополнительная проверка && allow_source_address(«100») ?

if ((is_method(«INVITE») && allow_source_address(«100»)) || is_method(«UPDATE»)) {

Добрый день!
allow_source_address(«100») использовал для взаимодействия с оператором. В рамках этой статьи эта проверка не обязательна, можно удалить.

Добрый день,
я косвенно понял, что это связано с оператором и здесь это не описано, а жаль, тема очень актуальная и интересная. Хотелось бы понять как разделить два потока входящих вызовов. Т.е. первый поток это условно наши какие то удаленные пользователи которые должны пройти через регистрацию и аутентификацию и второй поток это внешние абоненты которых надо просто дальше прокинуть на астериск/фрисвитч без какой либо обработки.

От себя так же хочу присоединится к благодарностям за этот блок статей. Проделана огромная работа. Я пытался пройти обучение по kamailio в одном учебном центре, в итоге жалко потраченных личных денег и времени. В голове просто каша. У вас многие вещи описаны намного понятнее и логичнее. Если бы эта статья раньше мне попалась на глаза, то я лучше бы с вами договорился об уроках в частно порядке ))

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

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