作者简介:玉修,携程技能专家,专注于电话音视频通讯、智能客服机器人等范畴

一、前语

携程拥有庞大的呼叫中心,触及上万客服人员,掩盖机票、酒店、火车票、度假等产线的售前售后事务,每天的电话事务量超百万通。近年来,通讯技能、人工智能技能和智能终端等都在不断革新,咱们也一直在考虑怎么去做更智能化、主动化的呼叫中心,为未来海量的客户需求供给安稳和优质的服务。

携程呼叫中心的智能化包含多个方面:

  • 用户侧:智能在线聊天机器人(IM)、智能语音导航/智能语音客服机器人/智能邀评插件(电话)

  • 客服侧:智能工单和排班体系、智能质检体系、智能客户资源处理体系、服务渠道智能化

  • 体系基建:渠道布置智能化、事务监控智能化

本文旨在讨论携程完成呼叫中心电话智能语音客服机器人的基建服务——语音识别服务(即ASR)的负责均衡的演进进程,以及最佳实践。

二、布景

跟着人工智能技能的开展,在呼叫中心事务中,传统的 IVR(交互式语音应答)按键导航模式逐渐向IVR智能客服机器人改变(客户与IVR机器人进行语音对话的方法来处理事务)。携程呼叫中心体系下的IVR事务也在不断地向电话智能语音机器人改变,目前携程酒店、机票、火车票的国内IVR呼入事务,以及IBU国际英语机票的IVR呼入事务,现已悉数由电话智能语音机器人来为客户供给自助服务。

下图是国内酒店事务场景中,客户拨打携程服务热线后,客户与电话机器人经过语音交流的记载。能够看出,客户顺利完结了“取消订单”的事务处理。

干货 | 携程客服机器人ASR引擎的负载均衡实践

智能客服机器人要想完成上图的交互作用,离不开ASR服务的运用,以及功用完善且安稳的呼叫中心体系的支撑。携程呼叫中心的整个渠道依靠了众多组件,底层包括CC-Gateway(语音网关)、SBC(会话边际操控服务)、REG(分机注册服务)、SM(会话处理服务)、RS(呼叫路由服务)、CM(呼叫处理服务,依据FreeSWITCH)、ASR(语音识别服务)等系列服务。

下图是携程呼叫中心,客户呼入到智能客服机器人场景,进行语音自助事务处理时所触及的部分中心组件架构图。

干货 | 携程客服机器人ASR引擎的负载均衡实践

从上图能够看出,携程呼叫中心体系底层(如FreeSWITCH)调用实时ASR完结语音识别是依据MRCP协议来完成的。咱们将上图中触及ASR运用部分的组件交互进行简化,得出其包含下面3种组件:

  • MRCP客户端:发送RTP和SIP/MRCP的主张者,如FreeSWITCH(下文简称FS

  • MRCP服务端:处理MRCP/SIP信令,接纳并转发RTP

  • ASR引擎 :解析RTP,将语音转化成文本,并回来给MRCP Server

干货 | 携程客服机器人ASR引擎的负载均衡实践

能够发现,对于呼叫中心ASR调用者而言,只需求关心怎样对接MRCP Server即可,无需关注ASR Engine部分。在实践运用过程中,假如你收购第三方ASR体系进行私有化布置的话(比方科大讯飞ASR、百度ASR),一般MRCP Server和ASR Engine是打包在一起,并布置在同一机器上。

但无论你收购哪家的ASR产品进行集群化布置,厂商都没有供给ASR的负载均衡处理计划,需求客户自行处理。携程为了让ASR引擎具备更高的可用性,采用了多集群、多IDC、多供货商的ASR产品(如携程自研、百度、阿里、微软等)来供给服务。针对这么多的集群和ASR产品,规划出一个调度战略和负载均衡计划来合理有效地运用ASR资源就变得极为重要了

三、计划探究

目标现已理清,接下来深入剖析调用ASR触及的技能点,看看怎么完成目标。

调用MRCP Server包含SIP(UDP/TCP)、MRCP(TCP)、RTP(UDP)三部分,MRCP和RTP的服务端地址是由SIP INVITE的响应 200 OK中SDP指定(如下图),所以只需完结对SIP的负载均衡就能处理别的两个,要给MRCP Server做负载均衡就变成了给 SIP(UDP/TCP)做负载均衡。

咱们期望负载均衡的作用是:只需MRCP-Server服务端集群下有多台机器,即使客户端只要一个,负载均衡设备也能将恳求均匀分发给服务端的每一个成员。

干货 | 携程客服机器人ASR引擎的负载均衡实践

常规的负载均衡计划,无外乎依据硬件负载均衡设备完成,如A10(即AX)、F5、NetScaler等;或者依据软负载完成,如LVS、Nginx等。但这些常规方法,都无法实在做到给MRCP Server完成负载均衡。

携程的基建服务中,刚好有AX、Netscaler、TDLB相关负载均衡服务,所以咱们依据这几种基建服务都进行过验证性测验,惋惜终究作用都不尽人意。

以FS作为MRCP Client,AX作为负载均衡设备为例。假如只要1台FS设备,1台AX设备,4台MRCP-Server设备。从FS顺次主张4次恳求,或者同时主张4次恳求,终究使ASR驻留并发达到4个。

干货 | 携程客服机器人ASR引擎的负载均衡实践

上图是左侧“卖家秀”是咱们想要达到的预期作用,右侧“买家秀”是咱们实验所得的实践作用,一切的恳求都被分配到了同一台MRCP-Server机器上,没能均匀的分配给集群下的各成员。理想很丰满,但现实太骨感。

那么,AX设备没能做到均匀分配的原因是什么呢?FS依据AX来给MRCP做负载又存在什么坏处呢?

首先,对于FS和AX设备相对固定的情况下,SIP恳求的IP四元组(Source IP、Source port、Destination IP、Destination port)不会发生变化,由于FS对接MRCP Server时,会在MRCP装备文件中指定客户端和服务端的IP/Port,所以AX每次分配给FS的MRCP Server都是同一台,这明显不符合负载均衡的预期。

其次,电话场景,在收到200 OK后,或许长达半小时不会再有SIP交互,期间的MRCP和RTP都是MRCP-Client和MRCP-Server之间进行直连交互,底子不经过AX设备,而AX设备默认的会话坚持时长为120秒,超越这个时刻,SIP通道会被AX封闭,这会导致后续的SIP无法送达。

既然此路不通,咱们要考虑其他处理计划,经过深入研究和各种尝试,以为下面这两种处理计划比较合适,但各有优缺陷:

  • 计划A:经过FreeSWITCH的distributor模块完成

  • 计划B:经过OpenSIPs完成


长处

缺陷

计划A

1、无需依靠第三方负载均衡组件

1、装备繁琐杂乱

2、MRCP Server节点增删,都需求调整FS装备文件,并且得在无ASR事务时,才能加载收效

3、端口数量耗费大(每个MRCP Server都需求单独分配端口段)

4、负载均衡战略相对单一,只支撑按份额分配。并且单机所占有的最小份额不能小于0

计划B

1、装备简略

2、MRCP Server节点增删,只需调整OpenSIPs的DB即可,有ASR调用时,也可更改,实时收效

3、端口数量耗费小(只需求装备一个MRCP Profile文件,多个MRCP Server共用端口段)

4、负载均衡计划多种多样,支撑按份额、轮询等多种方法

1、需求依靠第三方负载均衡组件OpenSIPs

咱们终究将两个计划结合,来完成负载均衡,FS上运用distributor模块来完成对 OpenSIPs做负载均衡,OpenSIPs上再对MRCP-Server做负载均衡,作用如下:

1)FS、OpenSIPs、MRCP-Server三个组件之间完成了IDC优先就近拜访(如上所述,FS未能做到100%的就近拜访)。

2)当相同IDC下的下流服务悉数不行用时,则主动将流量分配到其他IDC下,如下图,IDC-A 下 FS的ASR恳求,优先恳求到 IDC-A 的OpenSIPs,然后IDC-A的OpenSIPs再依据分配战略,将恳求优先分配给 IDC-A下的MRCP-Server,假如IDC-A下的MRCP-Server全宕机了,会主动分配给IDC-B下的MRCP-Server。

3)负载均衡服务可主动检测下流集群各成员的状况,当某成员服务不行用时主动拉出,服务状况康复后,再主动拉入。FS和OpenSIPs都是经过发送SIP OPTION 来主动勘探下流服务的状况。

干货 | 携程客服机器人ASR引擎的负载均衡实践

四、计划实践

接下来,咱们详细看看每种计划的详细完成方法。以下计划运行环境为:CentOS 7.6、FreeSWITCH 1.6.20、OpenSIPs 2.4.2。

本篇文章中,咱们不详细解说每种方法的完成原理,只介绍处理方法,有爱好的同学能够自行学习FS和OpenSIPs的相关功用点,这儿给出几个链接:

假设咱们只要一台FS作为MRCP 客户端,并且MRCP Server 集群中有两台服务器,分别是 mrcp1 和 mrcp2,期望FS针对每一通电话履行ASR指令时,恳求可均匀分配给两个MRCP Server。

4.1 依据FS的distributor模块完成MRCP Server的LB

该计划的中心思路如下:

1)FS直接与MRCP Server对接,为MRCP Server集群下每一个成员装备一个profile

2)将MRCP Server集群下的一切成员装备成 FS 的网关,并敞开网关的SIP OPTION勘探功用,同时保证gateway的name要与mrcp_profile文件中profile的name共同

3)经过FS的distributor 模块为这些MRCP网关装备负载均衡战略

4)最终,实践履行ASR指令时,先经过 expand eval {distributor mrcp {sofia profile external gwlist down}} 负载均衡分配得到一个可用的 MRCP Server Profile的称号,然后用该MRCP Profile的称号作为FS play_and_detect_speech ASR指令的参数即可。

详细的装备过程如下所示:

榜首步:FS与MRCP Server对接

<span>在 /usr/local/freeswitch/conf/mrcp_profiles/下装备FS对接MRCP Server的文件</span>

下面只给出mrcp1.xml的部分中心装备,只需求保证mrcp1.xml和mrcp2.xml里client-port、rtp-port-min、rtp-port-max装备不同即可。

这儿能够看到,假如MRCP Server集群有很多机器,那么这儿的RTP端口段或许不够用,一通电话进行ASR解析需求2个端口,一个用来传输RTP、一个传RTCP。

<span>&lt;include&gt;</span>

第二步:装备FS网关

<span>在 /usr/local/freeswitch/conf/sip_profiles/external/下装备网关对接文件</span>

mrcp1.xml 的详细装备如下:

<span>&lt;gateway name="mrcp1"&gt;  【gateway的name要与mrcp_profile文件中profile的name共同,或能够依照某种规矩转化】</span>

第三步:装备FS的distributor模块

<span>vim /usr/local/freeswitch/conf/autoload_configs/distributor.conf.xml</span>

最终,来看看运用作用。依照上述装备,将mrcp2服务宕机后,履行负载均衡的作用如下:

<span>freeswitch@LPT0596&gt; sofia profile external gwlist down   【获取宕机的网关】</span>

其他FS相关指令:

  • reload mod_unimrcp : 修正FS与MRCP server对接的文件后,重新加载收效【只要当时没有正在履行的ASR操作时,才能重加载】

  • sofia profile external rescan : 重新加载FS的网关装备

4.2 依据OpenSIPs完成MRCP Server的LB

4.2.1 中心思路

FS不直接与MRCP Server对接,而是与OpenSIPs进行对接。对接方法是把OpenSIPs装备成一个MRCP profile,文件中的server-ip 和 server-port 地址装备成OpenSIPS 的服务地址即可。

FS履行ASR指令时,先将SIP恳求发送给OpenSIPs,再由OpenSIPs负载均衡到MRCP Server集群中的成员,交互的时序图如下:

干货 | 携程客服机器人ASR引擎的负载均衡实践

4.2.2 计划剖析

经过OpenSIPs来完成对MRCP的负载均衡需求处理下面几个问题:

问题1、怎么判别收到的INVITE恳求是要履行ASR指令,仍是一般呼叫指令?

问题2、知道是履行ASR指令后,怎么挑选MRCP Server,进行分配?

问题3、假如有多套MRCP Server集群,比方一套百度MRCP,一套阿里MRCP,客户端期望能指定引擎运用,该怎么处理?

既然现已明确了问题点,那咱就各个击破即可,下面是各问题点的处理方法:

  • 问题1的处理方法

咱们来看一条FS发送给OpenSIPs,恳求履行MRCP负载均衡的SIP INVITE信息,其中 192.168.1.99是FS,192.168.1.18是OpenSIPs。

<section><code><span>INVITE sip:192.168.1.18:5070 SIP/2.0</span></code><code><span>Via:  SIP/2.0/UDP 192.168.1.99:5102;rport;branch=z9hG4bKQ21yZS46ytrgF</span></code><code><span>Max-Forwards:  70</span></code><code><span>From:  &lt;sip:192.168.1.99:5102&gt;;tag=4B8SvQe66FNvc</span></code><code><span>To:  &lt;sip:192.168.1.18:5070&gt;</span></code><code><span>Call-ID: ed9f5f6b-0673-123b-199a-fa163e72d95e</span></code><code><span>CSeq:  47770741 INVITE</span></code><code><span>Contact:  &lt;sip:192.168.1.99:5102&gt;</span></code><code><span>User-Agent:  FreeSWITCH</span></code><code><span>Allow:  INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE</span></code><code><span>Supported:  timer, 100rel</span></code><code><span>Content-Type:  application/sdp</span></code><code><span>Content-Disposition:  session</span></code><code><span>Content-Length:  306</span></code><code><span><br></span></code><code><span>v=0</span></code><code><span>o=FreeSWITCH 2480643166757753319 6144298267054033408 IN IP4 192.168.1.99</span></code><code><span>s=-</span></code><code><span>c=IN IP4 192.168.1.99</span></code><code><span>t=0 0</span></code><code><span>m=application 9 TCP/MRCPv2 1</span></code><code><span>a=setup:active</span></code><code><span>a=connection:existing</span></code><code><span>a=resource:speechrecog</span></code><code><span>a=cmid:1</span></code><code><span>m=audio 31799 RTP/AVP 0 8</span></code><code><span>a=rtpmap:0 PCMU/8000</span></code><code><span>a=rtpmap:8 PCMA/8000</span></code><code><span>a=sendonly</span></code><code><span>a=mid:1</span></code></section>

从上面信令能够看到,FS主张的INVITE中,没有主被叫号码信息,只要FS和OpenSIPs的IP和端口信息。假如咱们的OpenSIPs只用来给MRCP Server做负载均衡,那么就很简略,收到INVITE恳求,都以为是恳求履行ASR指令,分配给MRCP Server即可。可是,OpenSIPs只给MRCP Server做负载岂不是大材小用了!

所以,实践咱们不会这样运用,OpenSIPs一般还会给其他呼叫中心组件做负载均衡,比方给FreeSWITCH、语音网关、分机注册服务等做LB。这样OpenSIPs就会收到来自各种组件的SIP INVITE恳求。那么该怎么判别收到的 INVITE 是要履行ASR指令,仍是要做其他事务呢?

常规思路,自然是OpenSIPs剖析INVITE的SIP音讯头,从中进行判别。可是由于FS的mod_unimrcp模块的限制,FS履行ASR指令时,发送的SIP INVITE里不支撑增加自定义SIP音讯头,所以只能从标准 SIP 音讯头中进行发掘。

  • 依据INVITE恳求的源IP:不行行,由于同一个源IP或许主张多种恳求的INVITE,比方FS或许是恳求履行ASR,也或许是恳求呼叫手机;此外,即使可行,源IP也不便利维护。

  • 依据INVITE恳求的意图IP:不行行,一切INVITE恳求的该值都相同

  • 依据INVITE恳求的User-Agent头:可行,OpenSIPs经过$ua就能获取该值。虽然不能针对每次INVITE自定义不同的UA头,但FS对接MRCP Server的Profile中能够指定一个统一的User-Agent头,默认是FreeSWITCH。

  • 依据INVITE恳求SDP信息中的‘m’头:可行,OpenSIPs经过$(rb{sdp.line,m})就能获取该值。如 上面报文中“m=application 9 TCP/MRCPv2 1” 里边有MRCPv2,可依据这个判别是履行ASR。

主张运用User-Agent头进行区别,取值便利,效率高。所以,FS对接OpenSIPs时,装备的MRCP Profile时,指定一个特别的User-Agent,比方叫ASR_MRCP_CLIENT_FS,OpenSIPs收到INVITE恳求,优先判别UA信息,假如是ASR_MRCP_CLIENT_FS,那么就是要履行ASR指令。

  • 问题2的处理方法

能够运用OpenSIPS的load_balancer 或 dispatcher 模块来完成对 MRCP Server 服务端的负载均衡,两种方法的特点如下:

假如MRCP-Server集群下的成员可支撑的并发数不相同,想做到哪台机器剩余的可用资源最多,就优先分配给谁,当各成员可用资源数相同时,在轮训分配,那么能够运用 load_balancer 模块来完成负载均衡;

假如MRCP-Server集群下的成员可支撑的并发数彻底相同,无差别,那么主张运用dispatcher模块来试想负载均衡,能够做到均匀的将恳求分配给每一台服务器。


长处

缺陷

load_balancer

可操控每个MRCP Server的最大并发量

支撑监控分配给每个MRCP Server的实时并发量

分配战略单一:只支撑空闲优先战略分配和按份额分配两种战略,无法支撑回忆轮训,这就导致但MRCP Server集群新增成员时,会将流量悉数分配给新增的机器,这种情况,新机器的突增压力或许较大

dispatcher

分配战略多种多样:如支撑回忆轮训、Hash分配等

不能操控每个MRCP Server的最大并发量,话务量暴涨时,存在雪崩危险

不能监控分配给每个MRCP Server的实时并发量(但能够自行经过OpenSIPs其他模块完成)

  • 问题3的处理方法

在FS上为每一套MRCP Server集群,装备一个MRCP Profile并且都指向OpenSIPs,但User-Agent的值装备成不相同,OpenSIPs依据UA的不同,来挑选该给哪个集群做LB。

<span>baidu_mrcp_lb.xml  下面只给出特有装备,其他装备被省掉了</span>

OpenSIPs给MRCP Server做负载均衡的处理流程图如下:依靠dialplan模块进行挑选详细经过哪个模块来履行LB。

干货 | 携程客服机器人ASR引擎的负载均衡实践

4.2.3 详细完成

假如OpenSIPs自身也是集群化布置,那么能够经过本文3.1章节的方法完成对OpenSIPs的负载均衡。

下面代码触及OpenSIPs对dialplan、dispatcher、load_balancer几个模块的运用,本文不解说这部分的运用方法。

  • 数据库初始化

说明:

1)下方装备了百度、阿里两个MRCP Server集群,并且每个集群都布置在了两个IDC(IDC_A和IDC_B)

2)OpenSIPs依据dialplan拨号计划来为阿里和百度挑选负载均衡的方法,dialplan表中字段“attrs”装备逻辑是:[MRCP集群榜首路由的集群ID:负载均衡完成方法:集群称号],如“90:DS:ASR_MRCP_SERVER_CTRIP_ALI”代表,阿里MRCP榜首路由的集群ID是90,采用dispacher模块完成LB;”90:DS:ASR_MRCP_SERVER_CTRIP_ALI”代表,百度MRCP榜首路由的集群ID是91,采用load_balancer模块完成LB

3)无论是dispacher,仍是load_balancer,都装备了单IDC下负载均衡的基础上,增加了逃生路由的功用。集群ID为 90/91代表榜首路由,10090/10091代表第二路由

<span>dialplan的attrs字段被赋予了特别用途</span>

装备好后,可检查集群内MRCP成员的状况:

<span>sudo /usr/local/opensips/sbin/opensipsctl fifo lb_list</span>
  • OpenSIPs代码完成
<span>route{</span>

假如依照上面脚本履行了 ru=”sip:” ru = “sip:” rU “@” (duuri.host) “:” (du{uri.host}) “:” dp;,可是rU==null并且不设置rU== null 并且不设置 rU=”Null2SM”或者其他非空值,会报如下过错:

<span>Feb 12 22:27:35 fat5410 /usr/local/opensips/sbin/opensips[3710]: ERROR:core:parse_uri: bad char '@' in state 0 parsed: &lt;sip:&gt; (4) / &lt;sip:@192.168.1.190:8060&gt; (20)</span>

处理办法:

1)设置$rU 为一个非空值

2)直接不修正$ru 的值

3)修正 ru=”sip:” ru = “sip:” (du{uri.host}) “:” $dp;

4.2.4 信令记载:

  • FS 发送INVITE给 OpenSIPs
<span>2022-02-13 13:50:53  0800 : 192.168.1.99:5221 -&gt; 192.168.1.18:5070</span>
  • OpenSIPS 转发INVITE给 MRCP server
<span>2022-02-13 13:50:53  0800 : 192.168.1.18:5070 -&gt; 192.168.1.190:8060</span>
  • MRCP Server 回复200 OK,回来后续接纳RTP的实在地址
<span>2022-02-13 13:50:53  0800 : 192.168.1.190:8060 -&gt; 192.168.1.18:5070</span>
  • FS发送ACK给OpenSIPs
<span>2022-02-13 13:50:53  0800 : 192.168.1.99:5221 -&gt; 192.168.1.18:5070</span>
  • 最终,OpenSIPs将ACK转发给MRCP Server

五、结语

从上文中提到的携程呼叫中心客户呼入到智能客服机器人场景的中心组件架构图能够看出,ASR引擎的负载均衡只是携程呼叫中心渠道各组件中很小的一个功用点,但也是不行或缺的一部分。

正由于有了这个技能计划的完成,使得多集群、多数据中心、多供货商的ASR产品得以很好地整合,为携程电话智能客服机器人事务的安稳运行供给了良好的技能保证,提高了携程客户的通话体会。

本文主要解说了对于ASR引擎做负载均衡的规划以及完成计划,期望能对从事智能呼叫中心范畴工作或研究的同学们供给一些帮助。

【推荐阅读】