IM实时通信系统

背景

IM实时通信是基于刚才提到的Websocekt实时消息推送系统的子系统,和消息推送系统的区别主要是业务上,实时通信是前后端交互推送消息,而并非消息推送只会从服务端进行push。

具体实现

当用户在平台点击咨询按钮时,会激活聊天窗口,此时消息体内由json数据构成,存储发送人uid(当前登录用户uid),和接收人的uid,后台通过onmessage方法获取到前端推送的websocket数据,从json中解析出接收人uid,随后通过接收人的uid在websocket链接容器散列表中进行寻址,获取接收人websocket链接对象,然后将消息推送到接收人的聊天窗口中。

时序算法

其实这里面有一个算法问题,就是客户发起在线咨询请求的时候,如何对应分配客服的问题,一般情况下,客服数量是有限的,怎么才能在有限的客服资源条件下,最大化的提高咨询效率?

我自己设计了一套基于时序的算法

首先声明一个全局时序变量,这个变量默认时序是0

随后定义一个基于散列表(哈希)的容器,key是就客服所在时序,假设我们有三个客服,每个客服最多同时和三个客户聊天,那么并发聊天的阈值就是9个客户,如此,我们的哈希时序就分为四个状态,分别是 0、1、2、3 分别代表同时在和几个客户聊天:

# 时序字典
s_dict = {0:[c],1:[a,b],2:[],3:[]}

客服分配

当客户发起咨询请求时,首先通过时序变量获取客服所在的线性结构容器,此时可以获取到当前的客服列表,随后采用hash取模算法,通过对客户uid进行哈希操作,并且对客服列表长度n取余操作,获取到分配客服的下标,接着通过下标累加操作,将该客服转移到下一个时序列表中,同时根据下标将当前分配后时序客服删除。

当然,这里可能会有一些问题

比如如果当前时序已经是3了,说明客服系统已经满载了,此时需要进行排队操作,客户uid会进入队列,遵循先进先出原则,当某一个客服被释放之后,再触发出队逻辑。

另外一个问题是,当前时序客服队列的长度如果是1的话,说明当前时序只剩下一个客服,那么客服增序操作后,当前时序变量也必须增序,因为当前时序已经不存在客服,时序变量不增量操作的话,就无法获取到客服列表了。

# 分配客服方法
def send_user(uid):

    global s

    if s == 3:

        print("客服正忙,请稍后")

        return

    if len(s_dict[s]) == 1:

        user = s_dict[s].pop()

        s_dict[s+1].append(user)

        s += 1

        return s_dict[s][0]

    else:

        user_index = hash(uid) % len(s_dict[s])

        user = s_dict[s].pop(user_index)

        s_dict[s+1].append(user)

        return user

客服释放

客服不仅仅有分配逻辑,当客户关闭聊天窗口后,会触发绑定事件,将该客服uid发送至后端,该客服会进行减序操作,即在时序散列表中进行寻址,找到客服uid所在的序列,然后将该客服序列做递减操作。

这里可能出现的问题是,时序变量的递减时机问题,只有在客服所在序列和当前时序吻合的情况,才会针对时序变量递减,否则时序变量不变,因为如果每一次都递减,就会出现时序错乱,无法获取到客服时序列表的问题。

举例子:时序1中两位客服,时序3中一位客服,时序3客服递减,总时序不应该递减

举例子:时序2中三位客服,其他时序没有客服,时序2中客服递减,总时序也应该递减


# 释放客服
def release_user(user):

    global s

    # 查找客服所在时序
    for key in s_dict.keys():

        if user in s_dict[key]:

            s_dict[key].remove(user)
            s_dict[key-1].append(user)
            print(len(s_dict[key-1]))
            if key == s:

                s = s - 1

            break

聊天记录存储

历史聊天记录我会保存在redis中,生命周期是一个月,使用hash进行存储,主要目的是为了量化客服的工作绩效,以及对聊天记录进行自然语言分析(nlp),这块聊天记录往往一式两份,但真实记录没必要存两份,所有通过客户uid和客服uid做正序排序操作后,组成唯一的聊天记录key,只存储一份聊天记录,节约系统内存资源。

results matching ""

    No results matching ""