Здравствуйте, уважаемые хабровчане.
Итак, хотелось бы поделится опытом реализации распределения нагрузки звонков на Астериск. Собственно задача стояла банальная — между N+1 пирами сделать равномерное распределение звонков. Кажется — ничего сложного, есть системы, которые это уже делают, НО, не хотелось в голо поставленный Астериск (без ВЕБ-морд и пр.) добавлять что-то непонятно как работающее. Соответственно — решил все-таки изобрести велосипед, потому как готового решения через конфиги так и не нашел.
Немного поразмыслив и вспомнив азы высшей математики хотел наваять формулы и пр. Но, в процессе поисков попался мне вот такой незатейливый скрипт:
<?php
$Expos['peer1']='peer1';
$Expos['peer2']='peer2';
$Expos['peer3']='peer3';
$Expos['peer4']='peer4';
$Expos['peer5']='peer5';
$Expos['peer6']='peer6';
function array_multi_rand($Zoo){
$Boo=array_rand($Zoo);
if(is_array($Zoo[$Boo])){
return array_multi_rand($Zoo[$Boo]);
}else{
return $Zoo[$Boo];
}
}
echo(array_multi_rand($Expos));
на данный момент я не являюсь программистом и имею скудные познания в PHP, поэтому прокомментировать могу только одно — данный скрипт из перечня моих пиров произвольным образом выбирает название пира. Что в принципе является довольно хорошим подспорьем в решении поставленной задачи. После этого я вставил вызов данного скрипта с выводом результата в файл и потом чтение этого файла в переменную диалплана Астериска. Вот как стало это выглядеть:
exten = 12345,1,Noop()
same = n,Noop(${STRFTIME(${EPOCH},,%d-%m-%Y_%H:%M:%S)}))
same = n,Set(i=0)
same = n(loop),Set(i=$[${i}+1])
same = n,Noop(${i})
same = n,System(php /home/test.php > /home/file.txt)
same = n,Set(peer=${FILE(/home/file.txt)})
same = n,Noop(${peer})
same = n,Dial(SIP/${EXTEN}@${peer},60,r)
same = n,Gotoif($["${DIALSTATUS}"=«CONGESTION»]?step:check)
same = n(check),Gotoif($["${DIALSTATUS}"=«CHANUNAVAIL»]?step:hang)
same = n(step),GotoIf($[$i=5]?hang:loop)
same = n(hang),Hangup
несколько комментариев по диалплану на случай, если возникли вопросы. Сначала я просто вывожу в консоль дату и время, далее присваиваю переменной i значение 0 и начинаю создание цикла, после этого функцией System вызываю скрипт PHP, приведенный выше с перенаправлением отработки скрипта в file.txt. Следующим шагом я читаю содержимое этого файла и вывожу значение в консоль Астериска. Следом набираю номер 12345 в тот пир который у меня выбрался и если получаю либо отбой по недоступности свободных каналов, либо по недоступности пира делаю еще одну попытку, на случай что вдруг получится прозвонится через другой peer и так 5 раз (ну вдруг повезет и следующий peer будет доступен). Если не повезло 5 раз — кладу трубку.
Казалось бы — УРА! — задача решена. Но как всегда — не тут-то было. Пока нагрузка была в 3-4 одновременных звонка — все было хорошо и спокойно. Но вот когда поднялась до 30-ти. Вот тогда-то и началось. нагрузка на процессор колебалась в районе 96-133% хотя платформа на которой стоит Астериск — Intel® Xeon® CPU X3440 @ 2.53GHz (8 ядер). Что в принципе казалось — НОНСЕНСОМ. Но все-таки было грустной реальностью.
В расстроенных чувствах я полез бороздить просторы Интернета в поисках ответа на вопрос, который не могу сформулировать. И в одном из примеров нашел, что надо вызывать PHP с ключом -q (-q Quiet-mode. Suppress HTTP header output (CGI only)). Исправив строку диалплана на
same = n,System(/usr/bin/php -q /home/test.php > /home/file.txt)
я получил желаемый результат. Нагрузка снизилась до 15-30%.
Вот собственно и все, чем хотел поделиться. Возможно данный пост станет кому-то полезным в решении подобного рода задач, или, возможно фундаментом для чего-то более грандиозного.
Итак, хотелось бы поделится опытом реализации распределения нагрузки звонков на Астериск. Собственно задача стояла банальная — между N+1 пирами сделать равномерное распределение звонков. Кажется — ничего сложного, есть системы, которые это уже делают, НО, не хотелось в голо поставленный Астериск (без ВЕБ-морд и пр.) добавлять что-то непонятно как работающее. Соответственно — решил все-таки изобрести велосипед, потому как готового решения через конфиги так и не нашел.
Немного поразмыслив и вспомнив азы высшей математики хотел наваять формулы и пр. Но, в процессе поисков попался мне вот такой незатейливый скрипт:
<?php
$Expos['peer1']='peer1';
$Expos['peer2']='peer2';
$Expos['peer3']='peer3';
$Expos['peer4']='peer4';
$Expos['peer5']='peer5';
$Expos['peer6']='peer6';
function array_multi_rand($Zoo){
$Boo=array_rand($Zoo);
if(is_array($Zoo[$Boo])){
return array_multi_rand($Zoo[$Boo]);
}else{
return $Zoo[$Boo];
}
}
echo(array_multi_rand($Expos));
на данный момент я не являюсь программистом и имею скудные познания в PHP, поэтому прокомментировать могу только одно — данный скрипт из перечня моих пиров произвольным образом выбирает название пира. Что в принципе является довольно хорошим подспорьем в решении поставленной задачи. После этого я вставил вызов данного скрипта с выводом результата в файл и потом чтение этого файла в переменную диалплана Астериска. Вот как стало это выглядеть:
exten = 12345,1,Noop()
same = n,Noop(${STRFTIME(${EPOCH},,%d-%m-%Y_%H:%M:%S)}))
same = n,Set(i=0)
same = n(loop),Set(i=$[${i}+1])
same = n,Noop(${i})
same = n,System(php /home/test.php > /home/file.txt)
same = n,Set(peer=${FILE(/home/file.txt)})
same = n,Noop(${peer})
same = n,Dial(SIP/${EXTEN}@${peer},60,r)
same = n,Gotoif($["${DIALSTATUS}"=«CONGESTION»]?step:check)
same = n(check),Gotoif($["${DIALSTATUS}"=«CHANUNAVAIL»]?step:hang)
same = n(step),GotoIf($[$i=5]?hang:loop)
same = n(hang),Hangup
несколько комментариев по диалплану на случай, если возникли вопросы. Сначала я просто вывожу в консоль дату и время, далее присваиваю переменной i значение 0 и начинаю создание цикла, после этого функцией System вызываю скрипт PHP, приведенный выше с перенаправлением отработки скрипта в file.txt. Следующим шагом я читаю содержимое этого файла и вывожу значение в консоль Астериска. Следом набираю номер 12345 в тот пир который у меня выбрался и если получаю либо отбой по недоступности свободных каналов, либо по недоступности пира делаю еще одну попытку, на случай что вдруг получится прозвонится через другой peer и так 5 раз (ну вдруг повезет и следующий peer будет доступен). Если не повезло 5 раз — кладу трубку.
Казалось бы — УРА! — задача решена. Но как всегда — не тут-то было. Пока нагрузка была в 3-4 одновременных звонка — все было хорошо и спокойно. Но вот когда поднялась до 30-ти. Вот тогда-то и началось. нагрузка на процессор колебалась в районе 96-133% хотя платформа на которой стоит Астериск — Intel® Xeon® CPU X3440 @ 2.53GHz (8 ядер). Что в принципе казалось — НОНСЕНСОМ. Но все-таки было грустной реальностью.
В расстроенных чувствах я полез бороздить просторы Интернета в поисках ответа на вопрос, который не могу сформулировать. И в одном из примеров нашел, что надо вызывать PHP с ключом -q (-q Quiet-mode. Suppress HTTP header output (CGI only)). Исправив строку диалплана на
same = n,System(/usr/bin/php -q /home/test.php > /home/file.txt)
я получил желаемый результат. Нагрузка снизилась до 15-30%.
Вот собственно и все, чем хотел поделиться. Возможно данный пост станет кому-то полезным в решении подобного рода задач, или, возможно фундаментом для чего-то более грандиозного.