首先我们来看看怎样通过逻辑设计达到节约号码的目的,这涉及到话务平台两种绑定关系模式:固定关系模式和会话关系模式。
1、固定关系模式
话务平台最先支持的是固定关系模式。一个虚拟号,只分配给一个被叫真实号使用,不能同时分配给其他被叫真实号,这种绑定关系是独占式的。绑定之后,理论上任意主叫号码均能通过拨打这个虚拟号联系到背后的真实号。号码绑定关系可以被业务主动解绑,解绑后虚拟号回到号池,状态标记为“可用”状态,下一次分配号码时可以重复分配出去。号码绑定关系也可以由业务方指定有效期,例如可以指定为1天有效期,1天过后此关系自动过期解绑,业务方需要取虚拟号时再重新绑定。
2、会话关系模式
另一种会话关系就有很大不同了。会话关系是相对于独占的固定关系而言的,首先我们设计了一个共享号池,号池中储备有多个虚拟号。对于主叫A1,当其需要联系客户B1时,话务平台从共享号池中取出V分配给B1,A1通过拨打V联系到B1,A1-V-B1就是一个会话关系。此时另外一个主叫A2,他需要联系客户B2,话务平台从共享号池中分配号码给B2,分配的号码可以仍旧是V,A2通过拨打V可以联系到B2,关系为A2-V-B2。为什么A1和A2,都拨打虚号V,能联系到各自的客户B1和B2呢?因为主叫号码不同,话务平台根据主叫号码定位到不同的会话关系,并转接到不同的被叫真实号码!话关系比固定关系要节省号码,让我们更进一步,假设A1要联系10名被叫,那么需要10个虚拟号,每名被叫对应一个虚拟号。这个时候,如果A2要联系另外10名被叫,A2可以复用这10个虚拟号,不会出现拨虚拟号不能定位到被叫的问题,因为他们的主叫号码是不同的。
是不是很神奇?!会话关系也可以更复杂,除了给被叫分配虚号,也可以给主叫分配虚号,主叫的虚号就是被叫接到来电时的来电号显,这样两个真实号+两个虚拟号形成一组会话关系,当被叫回拨时,话务平台可以根据这个会话关系找到原始主叫真实号。
号池调度
通常,各个供应商、各个城市的接通率是不一样的,接通率是指拨通的次数占总呼叫次数的比例。为了优化接通率,在号码分配时有一些特别的设计。每家供应商都提供多批虚拟号,话务平台根据号码类型、适用地区、业务需求量等维度对其进行分片,划分成多个号码池。业务方一般配置为可以使用多个号池,以防某个号池号码耗尽,或者遇到供应商侧的故障,可以有备用号池保障号码分配能正常提供服务。当业务方申请分配虚拟号码时,会根据预先配置好的分配策略,确定使用哪些号池。分配策略规定了业务、城市、渠道与号池ID的对应关系。如果没有找到合适的号池,会选用默认的号池。为了优化号码分配,设计了一个号池评分模块。评分模块根据号池剩余号量、通话质量优劣(接通率)、以及人工干预等因素评分,确定优先级,优先级最高的号池被选中。号池选中之后,就可以从号池中取一个可用号码分配给业务使用,当号码关系解绑或者自然过期时,将号码回收到号码池,成为“可用”状态,如此号码可以循环利用。号池的设计,也是一种风险控制手段,如果号池消耗过快,来不及补充便耗尽,号池评分模块会根据剩余量自动降低这个号池的优先级;当某个供应商出现故障时,也可以通过接通率下降或者人工干预手段降低这个供应商的所有号池的优先级,从而让其他可用的号池来提供正常服务。
号码回收与复用,号码资源是有限的,在有限的资源和无限的需求之间如何平衡呢?我们设计了一些回收与复用的机制。在绑定号码时,明确指定了有效期属性,当有效期结束时,该号码会被回收至号池,下次分配可以重新使用。过期类型支持:不过期、绑定后指定时长后过期、首次通话后指定时长后过期、最后通话后指定时长后过期、定时过期。有些号码分配出去,可能并不会被拨打。话务平台设计了GC,会定期检查号码使用率情况,如果某个没有设置过期时间的虚拟号码,3天内没有被拨打,则可以认为是无效关系,GC会将其回收到号池。回收无人拨打的号码是安全的,因为使用方不缓存虚拟号码,而是展示时总是从话务平台实时获取,如果之前分配出去的号码已被回收,则会重新分配一个虚拟号给使用方。号码的复用,第一是体现在号码回收后可以重新分配给其他用户;第二是体现在会话关系中,一个虚拟号能复用给多个关系,能复用的关系数,取决于主叫能联系的被叫数量。
安全与认证,下面我们来探讨一下安全层面的考虑,安全是一个不容忽视的考虑因素。首先我们做了内外网隔离,面向业务的接口只能内网访问,面向供应商的接口能从内网和公网访问。其次,话务平台的接口采用https加密传输,防止中间人窃取、篡改数据。话务平台设计了业务方和供应商的身份标识体系,为每一个供应商和业务方都分配一个身份id,以及一个保密的随机字符串作为secret_key。每一次调用都需要调用者传递身份id用以声明自身身份。如何验证调用者是所声称的身份,不是冒充者?规定调用者需要传递参数签名,将所有HTTP的参数按照约定的顺序排序,拼接上secret_key,并做哈希计算,哈希值作为签名参数传过来。话务平台服务器收到http请求时,按照同样的规则重新计算签名,如果与传过来的签名值一致,则说明调用者是所声明的用户,验证通过;否则拒绝该次请求。参数签名能校验参数完整性,如果中间人篡改了参数值,会导致签名验证不通过。参数中还加入了时间戳,服务端验证时间戳是否有效,这可以一定程度上防止中间人截取到URL后重复调用,从而防止重放攻击。锁,并发分配号码,以上措施解决了一些冒充、拦截、篡改、重放等安全威胁,但是还有另一种数据安全问题,那就是并发安全。业务方请求分配虚拟号,存在共享资源的竞争,号池里的号码就是共享资源。这一过程,是先从号池里取出一个可用的号码,再创建绑定关系。对于两个并发请求,怎样防止取出同一个虚拟号分配出去呢。这种数据一致性的问题,可以用分布式锁来解决。锁是一个很大的话题,这里就不深入展开了。
总结下来,话务平台在设计时,重点考虑了以下平台化思路:提出供应商能力规范,统一了供应商提供的服务,以建立供应商能力抽象层,方便动态调度和切换。抽象出两种通用的通话模式,即固定关系模式和会话关系模式,提供抽象、收敛的接口,满足不同场景、灵活多变的业务需求。号池的设计,允许快速切换供应商,同时业务无感知,并且降低了单个供应商服务不可用的风险。号码的回收与复用,节省号码资源,节约成本。