整体架构解读
- 客服端和商城端都通过
websocket
连接到客服系统
, 并定期维持心跳 - 当客户接入客服系统时, 先根据策略选择在线客服, 然后再发送消息给客服
websocket实现
用netty
实现websocket
协议, 增加心跳处理的handler, 详见chat-server
模块
客服路由规则
暂时仅支持轮询的规则
优化: 比较好的方案是对客服接入的客户数进行分别统计, 选择客户数最小的, 当然如果统计的精细一点, 应该是统计客服在一段时间内收发消息的吞吐量
消息存储
bzmall
数据库的chat_messages
表, 用于存储全部的消息, 对于同一个会话的消息, 应该设置一个会话内的唯一id, 方便通过他来计算数量; 另外应该给from
和to
(即发送者和接收者)设置索引, 方便会话消息查询
消息拉取
当重新打开会话页面时, 应该拉取最新的消息, 实现起来也比较简单, 直接获取该会话的消息, 正序排列, 取最后面的n条即可;
消息的未读数
- 在会话页面时, 定期将消息进行批量确认, 比如当前页面展示的是id为1-5号的消息, 则在下一个批量确认时直接发送5即可, 这样服务端确认5号之前的消息设置为已读了; 另外需要创建一张消息offset表, 因为同一个会话的消息在
chat_messages
中只存了一份, 无法区分两端的不同情况; - 另外需要接入极光推送, 保证能及时收到消息提醒
优化: 可以让app在本地缓存消息的offset, 定期同步服务端, 未读数可以每次讲最大的id返回, 让app通过差值计算
消息同步
当通过websocket接收到消息后, app先将消息与本地的消息offset进行比较, 计算出未读数, 并进行渲染; 然后将消息内容在会话页面进行渲染
常见问题
用户分组
关于客户和客服都连接到websocket上了, 怎么进行区分并找到他们并路由过去呢, 现在的实现方式是每个接入websocket的客户端都提供了uid, 这个uid
的组成是类型_用户id
, 通过不同的类型前缀区分是客户还是客服
优化: 在服务端设置两个不同的存储用来接收客户和客服的连接, 这样清晰一点
多端同步
这个暂时应该涉及不到, 就按照单端处理吧先
多媒体消息类型
处理图片、音频、视频的这些, 还是先上传OSS, 然后将url传入后端即可