Pull to refresh

Балансировка нагрузки Asterisk + PHP = 100% загрузка процессора

Здравствуйте, уважаемые хабровчане.

Итак, хотелось бы поделится опытом реализации распределения нагрузки звонков на Астериск. Собственно задача стояла банальная — между 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%.

Вот собственно и все, чем хотел поделиться. Возможно данный пост станет кому-то полезным в решении подобного рода задач, или, возможно фундаментом для чего-то более грандиозного.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.