2023年12月6日发(作者:)

OpenSips+FreeSwitch负载均衡

1. 基本配置

  这个简单一点() 负载均衡可用的

opensipsctl fifo which

opensipsctl fifo lb_list # 查看负载均衡的配置是否生效

  Wireshark软件的Telephony菜单里有一个VoIP Call菜单项,可以自动发现sip呼叫,可以整理出呼叫过程中,所有消息的流程图。分析流程图可以找到问题所在,然后去搜索解决方案,就

比较容易了。

  FreeSwitch的三种媒体处理方式:

  录音这个顺序很重要,不能把顺序和bridge的弄反了,否则会录音不成功:

  vim /usr/local/freeswitch/conf/dialplan/

  acl配置,注意是cidr而不是domain:

    vim /usr/local/freeswitch/conf/autoload_configs/

    

  脚本主要修改的地方:

# 注销掉location的查找,就可以不验证,直接打电话了。查找location会改变du、ru变量。

route[relay]

{

# for INVITEs enable some additional helper routes

if (is_method("INVITE"))

{

# 如果 INVITE 是从 FS 传回来的,则将找到的分级 relay

if($si=~"192.168.2.57")

{

xlog("xxxxxxxxxxxxxxxxx [$ru] [$du]n");

if (lookup("location","m"))

{

xlog("yyyyyyyyyyyyyyyy [$ru] [$du]n");

#$ru="sip:2001@192.168.2.160:5060";

}

}

else

{

# 第一次收到的 INVITE 要转给 FS

t_on_branch("per_branch_ops");

t_on_reply("handle_reply");

t_on_failure("missed_call");

# relay to FS

xlog("Alex6 ...... [$ru] [$si]n");

rewritehostport("192.168.2.57:5080");

}

}

if (! t_relay())

{

send_reply("500","Internal Error");

}

exit;

}

  虽然依赖DAILOG模块,但是并没有太多的函数调用,只加了validate the sequential request against dialog 这个判断,应该也可以去掉,然后就是直接调用 if (! load_balance("1", "pstn"))

了,在数据库 load_balancer里面有配置。

#

# OpenSIPS residential configuration script

# by OpenSIPS Solutions

#

# This script was generated via "make menuconfig", from

# the "Residential" scenario.# You can enable / disable more features / functionalities by# re-generating the scenario with different options.### Please refer to the Core CookBook at:# /Resources/DocsCookbooks# for a explanation of possible statements, functions and parameters.######## Global Parameters #########log_level=3log_stderror=nolog_facility=LOG_LOCAL0children=4/* uncomment the following lines to enable debugging */#debug_mode=yes/* uncomment the next line to enable the auto temporary blacklisting of

not available destinations (default disabled) */#disable_dns_blacklist=no/* uncomment the next line to enable IPv6 lookup after IPv4 dns

lookup failures (default disabled) */#dns_try_ipv6=yes/* comment the next line to enable the auto discovery of local aliases based on reverse DNS on IPs */auto_aliases=nolisten=udp:192.168.2.160:5060 # CUSTOMIZE ME####### Modules Section #########set module pathmpath="/usr/local//lib64/opensips/modules/"db_default_url="mysql://opensips:opensipsrw@192.168.2.160:3306/opensips"#loadmodule "proto_"loadmodule "db_"loadmodule ""loadmodule "auth_"modparam("auth_db", "calculate_ha1", 1)modparam("auth_db", "use_domain", 1)modparam("auth_db", "password_column", "password")#### SIGNALING moduleloadmodule ""#### StateLess moduleloadmodule ""#### Transaction Moduleloadmodule ""modparam("tm", "fr_timeout", 5)modparam("tm", "fr_inv_timeout", 30)modparam("tm", "restart_fr_on_each_reply", 0)modparam("tm", "onreply_avp_mode", 1)#### Record Route Moduleloadmodule ""/* do not append from tag to the RR (no need for this script) */modparam("rr", "append_fromtag", 0)#### MAX ForWarD moduleloadmodule ""#### SIP MSG OPerationS moduleloadmodule ""#### FIFO Management Interfaceloadmodule "mi_"modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")modparam("mi_fifo", "fifo_mode", 0666)#### URI moduleloadmodule ""modparam("uri", "use_uri_table", 0)#### USeR LOCation moduleloadmodule ""modparam("usrloc", "db_mode", 1)modparam("usrloc", "nat_bflag", "NAT_BFLAG")modparam("usrloc", "use_domain", 1)modparam("usrloc", "hash_size", 16)#modparam("usrloc", "nat_bflag", "NAT")#modparam("usrloc", "working_mode_preset", "single-instance-no-db")#### REGISTRAR moduleloadmodule ""modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")modparam("registrar", "max_contacts", 1)modparam("registrar", "min_expires", 30)modparam("registrar", "max_expires", 300)modparam("registrar", "default_expires", 120)/* uncomment the next line not to allow more than 10 contacts per AOR */#modparam("registrar", "max_contacts", 10)#### ACCounting moduleloadmodule ""/* what special events should be accounted ? */modparam("acc", "early_media", 0)modparam("acc", "report_cancels", 0)/* by default we do not adjust the direct of the sequential requests. if you enable this parameter, be sure to enable "append_fromtag" in "rr" module */modparam("acc", "detect_direction", 0)#### DIALOG moduleloadmodule ""modparam("dialog", "dlg_match_mode", 1)modparam("dialog", "default_timeout", 21600) # 6 hours timeoutmodparam("dialog", "db_mode", 2)modparam("dialog", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE MEloadmodule "proto_"### load balanceloadmodule "load_"modparam("load_balancer", "db_url", "mysql://opensips:opensipsrw@192.168.2.160:3306/opensips")modparam("load_balancer", "probing_method", "OPTIONS")modparam("load_balancer", "probing_interval", 30)####### Routing Logic ######### main request routing logicroute{ if (! mf_process_maxfwd_header("10"))

{ send_reply("483","Too Many Hops"); exit; } if (is_method("OPTIONS")) { t_reply("200", "OK"); exit; }

$var(pTg) = has_totag(); xlog("method[$rm] has_totag = $var(pTg)"); if ($var(pTg) > 0)

{ if (loose_route())

{ xlog("loose_route ---> as receive message method[$rm]"); # route it out to whatever destination was set by loose_route() in $du (destination URI). route(relay); } else

{ if (is_method("ACK"))

{ if (t_check_trans()) { # non loose-route, but stateful ACK; must be an ACK after a 487 404 from upstream server xlog("receive message method[$rm] from [$ru] then do t_relay"); t_relay(); exit; } else { xlog("receive message method[$rm] no transaction , then exit"); exit; } } sl_send_reply("404","Not here"); } # validate the sequential request against dialog if ( $DLG_status!=NULL && !validate_dialog() ) { xlog("In-Dialog $rm from $si (callid=$ci) is not valid according to dialogn"); ## exit; } exit; } # CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()) t_relay(); exit; } # absorb retransmissions, but do not create transaction t_check_trans(); if (!is_method("REGISTER|MESSAGE")) { record_route(); } if (is_method("PUBLISH|SUBSCRIBE")) { t_reply("405", "Method Not Allowed "); exit; } if (is_method("REGISTER"))

{ xlog("Alex1--Do REGISTER AUTH : [$rm] ci[$ci] si[$si] sp[$sp] rd[$rd] rU[$rU] fU[$fU]");` route(AUTH); } if ($rU==NULL)

{ # request with no Username in RURI send_reply("484","Address Incomplete"); exit; } route(relay);}branch_route[per_branch_ops]

{ xlog("new branch at Alex2 $ru $rUn");}onreply_route[handle_reply]

{ xlog("incoming reply [$ci] [$si:$sp] [$rs]n");}failure_route[missed_call]

{ if (t_was_cancelled())

{ exit; }}route[relay]

{ # for INVITEs enable some additional helper routes if (is_method("INVITE"))

{ if ($si=~"192.168.2.57") { xlog("Alex111 [$ru] [$du]n"); if (lookup("location","m"))

{ xlog("yyyyyyyyyyyyyyyy [$ru] [$du]n"); #$ru="sip:2001@192.168.2.160:5060"; } } else if($si=~"192.168.2.176")

{ xlog("Alex222 [$ru] [$du]n"); if (lookup("location","m"))

{ xlog("yyyyyyyyyyyyyyyy [$ru] [$du]n"); #$ru="sip:2001@192.168.2.160:5060"; } } else { t_on_branch("per_branch_ops"); t_on_reply("handle_reply"); t_on_failure("missed_call"); # relay to FS # rewritehostport("192.168.2.57:5080"); if (! load_balance("1", "pstn")) { xlog("Alex333 [$ru] [$si]n");

sl_send_reply("500", "Service full.");

exit;

}

}

}

if (! t_relay())

{

send_reply("500","Internal Error");

}

exit;

}

route[AUTH]

{

# the same as --> www_authorize("", "subscriber");

$var(authRslt) = www_authorize("$td", "subscriber");

xlog("register auth result [$var(authRslt)] rd [$rd] user[$fU] source ip[$si] Alex1: $rp");

switch ($var(authRslt))

{

case -1:

send_reply("404", "Not Found");

exit;

case -2:

case -5:

send_reply("403", "Forbidden");

exit;

case -3:

case -4:

###www_challenge("$td","1");

www_challenge("$td","0");

exit;

}

$var(pA) = is_ip_registered("location", "$tu", "$si");

if ($var(pA) < 0)

{

xlog("====SIP contact ct:[$ct] [$fu] ci:[$ci] did not registe on, then check registe status for fU:[$fU].");

if (is_registered("location"))

{

xlog("L_WARN", "====Forbid $ct to registe on, cuase by : exist another $fU has registed");

send_reply("403", "Occupied");

exit;

}

}

if (! save("location", "f"))

{

sl_reply_error();

}

$var(expire) = "0";

if ($hdrcnt(Expires) == 0)

{

$var(expire) = $(expires);

xlog("no expire header ,contact expire is [$var(expire)]");

}

else

{

$var(expire) = $hdr(Expires);

xlog("expires header , expire [$var(expire)]");

}

exit;

}

View Code

  数据库的配置:

mysql> select * from load_balancer;

+----+----------+------------------------+-----------+------------+-------------+

| id | group_id | dst_uri | resources | probe_mode | description |

+----+----------+------------------------+-----------+------------+-------------+

| 1 | 1 | sip:192.168.2.57:5060 | pstn=500 | 1 | FS1 |

| 2 | 1 | sip:192.168.2.176:5060 | pstn=500 | 1 | FS2 |

+----+----------+------------------------+-----------+------------+-------------+

  配置命令:

INSERT INTO `opensips`.`load_balancer` (`id`, `group_id`, `dst_uri`, `resources`, `probe_mode`, `description`) VALUES ('1', '1', 'sip:192.168.2.57:5060', 'pstn=500', '1', 'FS1');

INSERT INTO `opensips`.`load_balancer` (`id`, `group_id`, `dst_uri`, `resources`, `probe_mode`, `description`) VALUES ('2', '1', 'sip:192.168.2.176:5060', 'pstn=500', '1', 'FS2');

UPDATE `load_balancer` SET description='FS2' WHERE id=2;

opensipsctl dispatcher addgw 1 sip:192.168.2.57 5060 0 50 'FS1' '节点1'

opensipsctl dispatcher addgw 1 sip:192.168.2.176 5060 0 50 'FS2' '节点2'

opensipsctl dispatcher show # 查看负载均衡配置

opensipsctl fifo lb_status 2 1 # 将目的地2配置为可用的状态

sofia profile internal siptrace on # 在fs中执行,查看信令流

注意是 insert into 不是 info

2. 语音流和信令

  补充小任务:配置FS,使其支持无限回放,即一条腿的情况。