现在的位置: 首页 > 综合 > 正文

分布式环境下基于redis解决在线客服坐席动态分配的问题

2018年03月30日 ⁄ 综合 ⁄ 共 1462字 ⁄ 字号 评论关闭

客服分配主要考虑效率与公平

客服平常的工作状态通常在两种模式下:

1. 顾客的人数 > 客服的接待能力

2. 顾客的人数 < 客服的接待能力

第一种情况,不存在客服的公平问题,只需考虑分配效率。

第二种情况,效率不成为问题,只需分配考虑公平,让顾客尽可能的平均分配到客服,既提升客服的并行接待能力,又保证了对客服的公平性。

当然还有第三种情况,就是相等,这犹如立起来的硬币是一个瞬时的小概率事件而非常态,可以不考虑。

在分布式环境下,基于 redis 提供的共享数据结构来实现客服的动态分配,先说明下关键数据结构:

根据客服的业务分组,同一分组的在线客服存储在 redis 的 SortedSet 结构中(图1)

SortedSet 顾名思义是一种排序集,这里根据客服最近一次接待的时间戳来排序,时间戳离现时越近则排在越末尾。

客服接待了一个顾客时,更新时间戳,redis 则会对 SortedSet 中的元素重新排序,刚接待过的客服会被排到末尾。

                                                                    图 1

每一个客服上线后在 redis 中存储一个 hash 结构来记录其动态属性,例如状态、正在接待人数、最大接待人数等(图2),同时将该客服加入其分组对应的 SortedSet 中。

重要的客服动态属性包括

     SN:                       正在接待人数/会话数(Session Number)

     CSU_x:               客服坐席单元(Customer Service Unit),x为编号,例如客服最大接待能力为8,则其属性包括了 CSU_1 ~ CSU_8 一共 8 个 CSU 单元

     MAX_CSU:        最大客服坐席单元

     STATUS:            客服状态(在线/离开/挂起等)

     ALLOT_FLAG:  分配标记  

                                                                图 2

客服分配过程如下(图3):

1. 获取对应业务分组的客服列表(从 SortedSet 中获取并保持该排序)。

2. 轮询客服列表,对每个客服进行分配逻辑检查和判断(检查客服状态、正在接待人数是否达到最大人数限制等)。

3. 轮询过程中获取到一个通过各种业务规则检查的可分配客服,设置正在分配标记(阻止分布式环境下其他程序同时对其进行分配),则尝试进行分配。

   3.1 尝试分配操作利用了 redis 的原子特性,模拟乐观锁机制。

   3.2 对客服的正在接待人数属性进行原子 +1。

   3.3 得到加1后的返回值和之前获取的正在接待人数做比较,例如检查时客服正在接待人数为 2,原子 +1 操作若没有并发冲突则会得到返回值 3,表明尝试分配成功,若返回值 > 3 说明产生了冲突,尝试分配失败。

       3.3.1 若尝试分配成功,更新该客服的 CSU_x 属性对应的状态和最近接待时间,将该客服移到对应客服分组的 SortedSet 的末尾

       3.3.2 若尝试分配失败,则回滚 +1 操作,进行 -1。

4. 由分配成功的程序取消该客服的正在分配标记,以确保该客服下次可以继续被分配。

5. 尝试分配失败的程序则继续尝试分配客服列表中剩下的客服

   5.1 尝试分配失败意味着产生了乐观分配冲突,为避免持续的冲突,需要对剩余的客服列表进行打乱(洗牌 shuffle)处理

   5.2 为了分配效率,在冲突的情况牺牲了公平性的考虑

   5.3 从另一方面来说,分配产生冲突也意味着很大的几率是在前面分析的第 1 中情况下,这时牺牲公平考虑效率是合理的,因为分配过程没有考虑公平,但最终结果是公平的(所有客服都会达到接待满员)。

                                           图 3

抱歉!评论已关闭.