5

微信客服项目简单介绍

 2 years ago
source link: https://hellolyfing.github.io/2018/08/13/%E5%BE%AE%E4%BF%A1%E5%AE%A2%E6%9C%8D%E9%A1%B9%E7%9B%AE%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近与同事协作完成微信客服项目的设计和开发工作。系统要完成的功能也很简单:打通微信与客服IM系统,让用户(像跟普通好友聊天一样)在自己微信上就可以实现与客服系统的直接对话。

对微信生态中好友、消息和群的第三方管理系统也有很多,不过为了稳定性和功能快速定制化,我们依然决定自研这套系统。现简单介绍一下这个系统。

系统功能介绍图

目前该系统在登录的时候仍然需要用手机扫码登录,不过一经登录基本不会掉线。

开发难点 / 技术点

在系统开发过程中遇到的一些难点和有意义的知识点,记录并分享下。

项目从单机到集群:可横向扩容的改造

微信消息轮询获取,目前只能支持单机模式。在较恶劣的情况下(单机偶现不可用、代码发布重启应用时)会出现微信登录状态丢失、微信服务不可用的情况。针对此问题,我们重构了消息轮询逻辑,将微信登录状态、微信接收的消息等内容持久化至Redis中,通过分布式轮询的方式保证微信客服的高可用,详见下方说明:

借助微信API实现的业务逻辑:

客服每登录一个微信号,都需要创建三个线程。其中线程A很快退出,线程B和线程C则持久运行。

线程B和线程C对绑定了微信Session信息的HttpClient重度依赖,微信消息队列也使用的应用共享内存,这导致: 1)应用无法做分布式和可高可用; 2)线程资源无法共享(缺少线程池的概念)

针对这种情况,微信客服项目准备做如下重构: 1)微信Session信息和微信消息,分别接入分布式存储和队列(实验性阶段,暂时用Redis实现) 2)创建线程池,分别执行线程B和线程C的原有业务内容

重构前流程图:

重构后流程图:

并发模式下,如何利用Mysql特性避免同一记录被重复插入

用户通过微信发送的消息到达我方的IM服务器后,需要自动为该用户分配一个会员UID,如果已有则会直接使用该UID。存储UID的表结构如下:

我们会根据表中的备注名生成会员邮箱,所以每次注册会员获取会员的UID时,会员服务化会保证返回的UID总是同一个,我们在获取到该UID后,会尝试将信息插入上图的wx_bb_uid_map表中。

但问题是,我们处理消息的方式是并发的,上面的步骤有可能被并发执行,但是我们的system_uid又没有设置唯一索引,所以在高并发下场景下我们发现有多条记录保存的是一模一样的值。

遇到这种问题,在插入前使用分布式锁也是可以的,不过能不能利用Mysql的特性去实现“已存在的记录不再插入”的目的呢?答案是:可以的。由于system_uid未使用唯一索引,所以无法利用:INSERT ON DUPLICATE KEY UPDATE 或者 INSERT IGNORE,但是利用INSERT INTO SELECT句式可以达到:如果system_uid已存在,则不插入记录的目的。

从SQL语句中可以看出,这是直接SELECT的值(而不是某表的字段)作为INSERT的入参,而且SELECT内容在WHERE判断记录已存在的情况下将会为空,即插入操作由于未发现值而被跳过。

INSERT INTO `wx_bb_uid_map` ( wxuin, nick_name, remark_name, system_uid, gmt_create, gmt_modified ) 
SELECT
    123,
    "wx小号",
    "姓名",
    1024,
    1531816594,
    1531816594 
FROM
    `wx_bb_uid_map` 
WHERE
    NOT EXISTS ( SELECT id FROM `wx_bb_uid_map` WHERE system_uid = 1024) 
    LIMIT 1

客服回复消息频率控制

由于我方的微信账号(个销号)是:给每个账号分配若干个人工客服进行消息收发,为防止由于消息发送频率过高导致的被风控,我们对人工客服对单个微信账号的回复频率做了频率限制。此处的频率限制使用了Redis做频率计数器,并以秒为单位过期计数器,达到控制发送速率的目的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK