分布式环境下基于redis解决在线客服坐席动态分配的问题
2012-12-24 11:06
555 查看
客服分配主要考虑效率与公平
客服平常的工作状态通常在两种模式下:
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
客服平常的工作状态通常在两种模式下:
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
相关文章推荐
- 分布式环境下基于redis解决在线客服坐席动态分配的问题
- 分布式环境下基于redis解决在线客服坐席动态分配的问题
- 分布式环境下基于redis解决在线客服坐席动态分配的问题
- 生产环境实战spark (10)分布式集群 5台设备 SPARK集群 HistoryServer WEBUI不能打开问题解决 File file:/tmp/spark-events does not
- 解决redis在centos自带ruby版本太低问题centos 6.5 ruby环境安装2.2+
- 使用Redis模拟简单分布式锁,解决单点故障的问题
- 王家林的“云计算分布式大数据Hadoop实战高手之路---从零开始”的第五讲Hadoop图文训练课程:解决典型Hadoop分布式集群环境搭建问题
- Redis在线用户设计(解决分页问题)
- 基于角色管理的权限分配(在线客服组方晓恩)
- 王家林的“云计算分布式大数据Hadoop实战高手之路---从零开始”的第五讲Hadoop图文训练课程:解决典型Hadoop分布式集群环境搭建问题
- 分布式环境下,事务在客户端远程调用中事务不能传播的问题的解决
- 王家林的“云计算分布式大数据Hadoop实战高手之路---从零开始”的第五讲Hadoop图文训练课程:解决典型Hadoop分布式集群环境搭建问题
- 基于redis(key分段,避免一个key过大) 和db实现的 布隆过滤器(解决hash碰撞问题)
- mysql及redis环境部署时遇到的问题解决
- 基于redis的分布式锁(不适合用于生产环境)
- 生产环境实战spark (8)分布式集群 Hadoop集群WEBUI打不开问题解决,关闭防火墙firewall
- 解决典型Hadoop分布式集群环境搭建问题
- 使用Redis模拟简单分布式锁,解决单点故障的问题
- 在分布式环境中如何解决session共享问题
- 【hadoop2.2(yarn)】基于yarn成功执行分布式map-reduce,记录问题解决过程。