OpenSips + FreeSwitch负载均衡


1. 基本配置

  这个Demo简单一点(参考) 负载均衡可用的函数

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

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

  FreeSwitch的三种媒体处理方式:参考 

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

  vim /usr/local/freeswitch/conf/dialplan/public.xml

    <extension name="fs2os">
      <condition field="destination_number" expression="^(2(.*))$">
        <!--action application="bridge" data="sofia/external/2001@192.168.2.160;fs_path=sip:192.168.2.160:5060"/-->
        <action application="set" data="RECORD_STEREO=true"/>
        <action application="record_session" data="/tmp/record.wav"/>
        <action application="bridge" data="sofia/external/$1@192.168.2.160"/>
      </condition>
    </extension>

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

    vim /usr/local/freeswitch/conf/autoload_configs/acl.conf.xml

    

  脚本主要修改的地方:

# 注销掉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 <team@opensips-solutions.com>
#
# 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:
#      https://opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#


####### Global Parameters #########

log_level=3
log_stderror=no
log_facility=LOG_LOCAL0

children=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=no


listen=udp:192.168.2.160:5060   # CUSTOMIZE ME



####### Modules Section ########

#set module path
mpath="/usr/local//lib64/opensips/modules/"

db_default_url="mysql://opensips:opensipsrw@192.168.2.160:3306/opensips"
#loadmodule "proto_udp.so"
loadmodule "db_mysql.so"

loadmodule "auth.so"
loadmodule "auth_db.so"

modparam("auth_db", "calculate_ha1", 1)
modparam("auth_db", "use_domain", 1)
modparam("auth_db", "password_column", "password")

#### SIGNALING module
loadmodule "signaling.so"

#### StateLess module
loadmodule "sl.so"

#### Transaction Module
loadmodule "tm.so"
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 Module
loadmodule "rr.so"
/* do not append from tag to the RR (no need for this script) */
modparam("rr", "append_fromtag", 0)

#### MAX ForWarD module
loadmodule "maxfwd.so"

#### SIP MSG OPerationS module
loadmodule "sipmsgops.so"

#### FIFO Management Interface
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)

#### URI module
loadmodule "uri.so"
modparam("uri", "use_uri_table", 0)

#### USeR LOCation module
loadmodule "usrloc.so"
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 module
loadmodule "registrar.so"
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 module
loadmodule "acc.so"
/* 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 module
loadmodule "dialog.so"
modparam("dialog", "dlg_match_mode", 1)
modparam("dialog", "default_timeout", 21600)  # 6 hours timeout
modparam("dialog", "db_mode", 2)
modparam("dialog", "db_url",
    "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME

loadmodule "proto_udp.so"

### load balance
loadmodule "load_balancer.so"
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 logic

route
{

    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 or e.g. 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 dialog\n");
        ## 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 $rU\n");
}


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) = $ct.fields(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,使其支持无限回放,即一条腿的情况。

  

  

 

 

 

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM