К сожалению для системных администраторов, Asterisk недалеко ушёл от корпоративных АТС в плане простоты настройки. Безусловно, Asterisk может, пожалуй, всё, что только возможно вообразить, но ценой этому является далеко не тривиальная настройка.
У меня за время работы с Asterisk накопилось множество различных примеров конфигурации. Полностью цифровые факсы с возможностью отправки из любого приложения в один клик, интеллектуальная запись звонков, всякие штуки с IVR и т.д. и т.п. Будет заинтересованность — со временем выложу.
В этом же посте хотелось бы поделиться системой простой балансировки исходящих соединений исходя из «веса» канала. Простейший пример, для чего это может понадобиться — звонки через обычные SIM нескольких операторов с безлимитными тарифами. У всех операторов есть некое максимальное значение минут, которые можно бесплатно проговорить в рамках тарифа в месяц. Поэтому хотелось бы распределить исходящие звонки по симкам в некой пропорции.
Предполагается, что вы умеет базово настраивать Asterisk, знаете, как пользоваться диалпланом и т.д. Писать очередную статью для новичков, а-ля как поставить Asterisk, было бы глупо.
С другой стороны, полноценное решение проблемы балансировки исходя из количества минут предполагает настройку БД с ведением статистики по длительности разговоров, AGI скрипты и прочие достаточно сложные и тяжёлые навароты. Я же опишу более простое, хоть и не до конца всеобъемлющее решение, которое, тем не менее, крайне хорошо себя зарекомендовало.
Итак: есть две SIP линии, каждая ведёт на свой GSM канал. Операторы Tele2 и Мегафон. На Tele2 у нас 300 минут, на мегафоне — всего 150. Соответственно нужно, чтобы на Tele2 поступало в два раза больше звонков. Кроме этого исходящий вызов должен идти через незанятую симку, а если оба канала заняты — то вызывающему абоненту об этом должна сообщать добрая тётенька, которая к тому же должна предложить подождать освобождения.
Итак, в sip.conf имеет примерно такое описание линий:
; ################################ ; GSM каналы ; ################################ [gsm-lines](!) deny=0.0.0.0/0 permit=10.42.42.42/32 type=friend secret=******* qualify=yes host=dynamic callcounter=yes ; активируем возможность использовать DEVICE_STATE call-limit=1 ; максимум 1 соединение на линию group = 1 context = from-gsm ; куда поступают входящие звонки insecure=invite canreinvite=no nat=no ; МегаФон [gsmline1](gsm-lines) ; Tele2 [gsmline2](gsm-lines)
Важными тут являются параметры callcounter, call-limit и context. Думаю, с ними всё понятно.
Собственно, в extensions.conf указанный контекст описан так:
; Звонки с GSM линий [from-gsm] ; МегаФон (первая линия) exten => +79310000000,1,Set(GROUP(gsm)=publick) ; Устанавливаем группу, дабы считать занятые каналы exten => +79310000000,n,Goto(to-internal,queue,1) ; Tele2 exten => +79520000000,1,Set(GROUP(gsm)=publick) ; Устанавливаем группу, дабы считать занятые каналы exten => +79520000000,n,Goto(to-internal,queue,1)
Безусловно, имена екстеншенов у вас будут другие (я использовал номера соответствующих телефонов, чтобы проще было). Они настраиваются на GSM шлюзе в настройках SIP подключения для каждого канала.
Тут нам важно, что для каждого входящего звонка устанавливается группа publick в категории gsm. Это нужно для подсчёта текущего количества занятых каналов.
Теперь самое интересное — исходящий контекст:
; Звонки на сотовые [to-gsm] ; Проверяем, есть ли свободные линии exten => _89XX.,1,GotoIf($["${GROUP_COUNT(publick@gsm)}" >= "2"]?noline) ; Вроде как есть свободные... exten => _89XX.,n,Set(GROUP(gsm)=publick) ; Устанавливаем группу, дабы считать занятые каналы ; Ok, проверяем - не мегафоновский ли номер вызываем? exten => _89XX.,n,Set(PR=${EXTEN:1:3}) exten => _89XX.,n,GotoIf($[$["${PR}"="921"] | $["${PR}"="931"] | $["${PR}"="929"]]?prefer-megafon) ; Распределяем нагрузку по симкам: ; На Tele2 у нас 300 бесплатных минут, на МегаФоне - 150. ; Берём рандом от суммы, и если он меньше 300 - значит отдаём предпочтение tele2, инчаче - мегафону exten => _89XX.,n,Set(BALANCE=${RAND(0,450)}) exten => _89XX.,n,GotoIf($[${BALANCE}<=300]?prefer-tele2:prefer-megafon) ; Предпочитаем Tele2 и проверяем, не занята ли его линия exten => _89XX.,n(prefer-tele2),GotoIf($["${DEVICE_STATE(SIP/gsmline2)}" = "NOT_INUSE"]?tele2:megafon) ; Или всё же мегафон... exten => _89XX.,n(prefer-megafon),GotoIf($["${DEVICE_STATE(SIP/gsmline1)}" = "NOT_INUSE"]?megafon:tele2) ; Соединяемся с возможностью перевода и продолжением выполнения диалплана. exten => _89XX.,n(tele2),Dial(SIP/gsmline2/${EXTEN},120,Tg) exten => _89XX.,n,Goto(after-dial,${EXTEN},1) ; Переходим к пост-обработке звонка exten => _89XX.,n(megafon),Dial(SIP/gsmline1/${EXTEN},120,Tg) exten => _89XX.,n,Goto(after-dial,${EXTEN},1) ; Переходим к пост-обработке звонка ; Если все каналы заняты exten => _89XX.,n(noline),Set(__CALLED_GSM_NUM=${EXTEN}) ; Запоминаем вызываемый номер exten => _89XX.,n,Goto(ivr-gsm,no-line,1) ; Если повесил трубку вызывающий абонент нам надо сделать постобработку exten => h,1,Goto(after-dial,h,1)
В целом, для всех операций присутствуют комментарии. За само распределение отвечает хитрый тюк с рандомом. Сразу скажу — на практике такое, весьма приближённое, решение для балансировки показало результаты не хуже, чем полноценная БД с подсчётом продолжительности каждого звонка. Вы ведь покупаете бесплатные минуты с запасом, я надеюсь? Т.е. вам всего лишь нужно примерно соблюдать баланс, что с успехом и делает предложенное решение.
Контекст after-dial нужен для пост-обработки звонка. Там могут быть всякие действия с записью, тем же подсчётом длительности и т.д. Для данной статьи это всё неактуально.
А вот ivr-gsm представляет некий интерес:
; IVR для GSM линий [ivr-gsm] ; Проигрываем предупреждение об отсутсвии свободных линий и ждём exten => no-line,1,Background(no-gsm-line,,custom) exten => no-line,n,Wait(10) ; Если есть запомненный номер - снова пытаемся его вызвать exten => no-line,n,GotoIf($["${CALLED_GSM_NUM}" != ""]?to-gsm,${CALLED_GSM_NUM},1) ; Нету - просто тихо выходим exten => no-line,n,Hangup()
В файлике no-gsm-line девушка должна говорить приятным голосом примерно следующее: Все исходящие линии заняты. Можете подождать или попробовать перезвонить позже.
В принципе, предложенный выше диалплан достаточно просто расширяется на большее количество линий. Просто после проверки DEVICE_STATE в случае занятости желаемой линии надо отправлять на некий экстеншн, который просто будет искать первую незанятую.
Если будет заинтересованность — могу продолжить серию и выложить, например, конфигурацию для цифрового факса.
ссылка на оригинал статьи http://habrahabr.ru/post/180445/
Добавить комментарий