作者简介
玉修,携程技术专家,专注于电话音视频通信、智能客服机器人等领域。
一、前言
携程拥有庞大的呼叫中心,涉及上万客服人员,覆盖机票、酒店、火车票、度假等产线的售前售后业务,每天的电话业务量超百万通。近年来,通信技术、人工智能技术和智能终端等都在不断革新,我们也一直在思考如何去做更智能化、自动化的呼叫中心,为未来海量的客户需求提供稳定和优质的服务。
携程呼叫中心的智能化包含多个方面:
- 用户侧:智能在线聊天机器人(IM)、智能语音导航/智能语音客服机器人/智能邀评插件(电话)
- 客服侧:智能工单和排班系统、智能质检系统、智能客户资源管理系统、服务渠道智能化
- 系统基建:平台部署智能化、业务监控智能化
本文旨在探讨携程实现呼叫中心电话智能语音客服机器人的基建服务——语音识别服务(即ASR)的负责均衡的演进历程,以及最佳实践。
二、背景
随着人工智能技术的发展,在呼叫中心业务中,传统的 IVR(交互式语音应答)按键导航模式逐步向IVR智能客服机器人转变(客户与IVR机器人进行语音对话的方式来办理业务)。携程呼叫中心系统下的IVR业务也在不断地向电话智能语音机器人转变,目前携程酒店、机票、火车票的国内IVR呼入业务,以及IBU国际英语机票的IVR呼入业务,已经全部由电话智能语音机器人来为客户提供自助服务。
下图是国内酒店业务场景中,客户拨打携程服务热线后,客户与电话机器人通过语音沟通的记录。可以看出,客户顺利完成了“取消订单”的业务办理。
智能客服机器人要想实现上图的交互效果,离不开ASR服务的使用,以及功能完善且稳定的呼叫中心系统的支撑。携程呼叫中心的整个平台依赖了众多组件,底层包括CC-Gateway(语音网关)、SBC(会话边际控制服务)、REG(分机注册服务)、SM(会话管理服务)、RS(呼叫路由服务)、CM(呼叫管理服务,基于FreeSWITCH)、ASR(语音识别服务)等系列服务。
下图是携程呼叫中心,客户呼入到智能客服机器人场景,进行语音自助业务办理时所涉及的部分核心组件架构图。
从上图可以看出,携程呼叫中心系统底层(如FreeSWITCH)调用实时ASR完成语音识别是基于MRCP协议来实现的。我们将上图中涉及ASR使用部分的组件交互进行简化,得出其包含下面3种组件:
- MRCP客户端:发送RTP和SIP/MRCP的发起者,如FreeSWITCH(下文简称FS
- MRCP服务端:处理MRCP/SIP信令,接收并转发RTP
- ASR引擎 :解析RTP,将语音转换成文本,并返回给MRCP Server
可以发现,对于呼叫中心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服务端集群下有多台机器,即使客户端只有一个,负载均衡设备也能将请求均匀分发给服务端的每一个成员。
常规的负载均衡方案,无外乎基于硬件负载均衡设备实现,如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个。
上图是左侧“卖家秀”是我们想要达到的预期效果,右侧“买家秀”是我们实验所得的实际效果,所有的请求都被分配到了同一台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 来自动探测下游服务的状态。
四、方案实践
接下来,我们详细看看每种方案的具体实现方式。以下方案运行环境为:CentOS 7.6、FreeSWITCH 1.6.20、OpenSIPs 2.4.2。
本篇文章中,我们不详细讲解每种方式的实现原理,只介绍解决方法,有兴趣的同学可以自行学习FS和OpenSIPs的相关功能点,这里给出几个链接:
- mod_unimrcp
- mod_distributor
- mod_dptools: play_and_detect_speech
- Load Balancer Module
- Dispatcher Module
- Dialplan Module
假设我们只有一台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对接
在 /usr/local/freeswitch/conf/mrcp_profiles/下配置FS对接MRCP Server的文件
tree /usr/local/freeswitch/conf/mrcp_profiles
├── mrcp1.xml
└── mrcp2.xml
分享说明:转发分享请注明出处。