分布式环境下基于redis解决在线客服坐席动态分配的问题
客服分配主要考虑效率与公平
客服平常的工作状态通常在两种模式下:
1. 顾客的人数 > 客服的接待能力
2. 顾客的人数 < 客服的接待能力
第一种情况,不存在客服的公平问题,只需考虑分配效率。
第二种情况,效率不成为问题,只需分配考虑公平,让顾客尽可能的平均分配到客服,既提升客服的并行接待能力,又保证了对客服的公平性。
当然还有第三种情况,就是相等,这犹如立起来的硬币是一个瞬时的小概率事件而非常态,可以不考虑。
【分布式环境下基于redis解决在线客服坐席动态分配的问题】在分布式环境下,基于 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
转载于:https://www.cnblogs.com/hehe520/archive/2012/12/24/6147643.html
推荐阅读
- 开学第一天(下)
- 【故障公告】周五下午的一次突发故障
- 人生感悟记#环境仪器宋庆国成长记#072
- 生活随笔|好天气下的意外之喜
- MongoDB,Wondows下免安装版|MongoDB,Wondows下免安装版 (简化版操作)
- 汇讲-勇于突破
- Android中的AES加密-下
- 说的真好
- 六步搭建ES6语法环境
- 放下心中的偶像包袱吧