Qunar 由于业务上对 IM 系统的需求,以及对 IM 需要支持的功能和扩展,结合市面上已有的 IM 的实现,实现了自己的一套完善的办公 IM 和客服 IM 系统。具备了以下几个重要特点:实时性,可靠性,一致性,安全性,扩展性,高并发。
Startalk是去哪儿开源的一款通用的,高性能的企业级im套件。Startalk 前身是去哪儿的Qtalk。其内核也在去哪儿旅行和去哪儿网站上扮演着着客服服务工具的角色。也就是说,一套内核同时为去哪儿网提供了内部企业办公和商家tob业务的支撑。
XMPP 协议
XMPP 是一个开放式的 XML 协议,设计用于准实时消息和出席信息以及请求-响应服务。
XMPP 协议单元包括三个大类:
优点:XMPP 有大量的优秀实现,且社区环境良好,功能和扩展能力丰富。
缺点:报文较大,耗费网络流量和电量。
MQTT 协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的”轻量级”通讯协议,该协议构建于 TCP/IP 协议上,由 IBM 在 1999 年发布。MQTT 最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
MQTT 是一个基于客户端-服务器的消息发布/订阅传输协议。 MQTT 协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。正是由于它的简单,也带来了他的缺点:需要自己去实现聊天,好友等 IM 的逻辑。
基于上面调研的常用 IM 协议,我们最终选择了 XMPP 协议最为最开始的实现协议:
基于:
团队最终选择使用 ejabberd 开源实现来快速实现自己的 IM 功能。
消息流转过程为:
这样,一条消息就完整的从用户 A 传输到了用户 B,实现消息的即时沟通。
在上一节 ejabberd 架构图中,我们可以在每个步骤中添加 hook 函数,添加自己的扩展功能。我们添加的扩展功能有:
使用 protocolbuffer 协议
由于 XMPP 协议具有:XML 报文流量大、耗电高等缺点,我们通过使用 protocolbuffer 替换掉 xml 报文,实现客户端到服务器之间的流量传输,减少报文流量和降低手机端的耗电量。在服务端将 protocolbuffer 再转换成 ejabberd 服务器使用的 xml 格式,减少服务端 im 逻辑的修改。
消息可靠性
通过以下渠道来确保 IM 消息的可靠性:
消息确认回执
我们在 ejabberd_c2s进程收到消息的时候,添加一个 hook 函数,用来作为服务器对收到消息的确认,同时将时间戳也返回给客户端,作为该消息的时间戳。
消息确认回执,主要解决的是问题是:保证消息至少一次发送成功,只有客户端收到了服务器的确认回执,才会认为消息到达了服务器,得到了响应的处理;否则客户端就会认为消息没有到达服务器,发送失败了。
消息同步
当我们同一个账号同时登录多个设备的时候,需要感知到在其他设备收发的消息,并同步展示给用户。所以我们在收发消息时,需要做必要的处理,以实现多设备同步的功能。
同步发送消息给其他设备:
发布消息到消息队列
为了扩展 IM 功能,我们需要把所有的 IM 的消息和时间发布到消息队列,供其他系统订阅消费,实现消息的统计、分析和存储。所以我们将时间和消息分类放入到 kafka,实现消息的异步处理。
目前发送发送的包括:消息、上下线事件、驼圈事件以及 @事件等
发送消息的 http 接口
为了给其他系统提供发送消息的服务,我们通过提供 http 接口的方式,来模拟来自用户的消息,实现该功能。
下发 IM 认证凭证
我们可以在 IM 里嵌入其它系统,来扩展 IM 的能力,包括但不限于移动 OA 、运维报警等系统。IM 客户端可以在跳转到其它系统的时候,带上 IM 的认证凭证,由其它系统来调用 IM 接口来认证身份。如果认证通过则表明是通过正在登录的 IM 客户端访问的,否则不允许访问该系统。这样就避免了让用户重复的认证身份,提高办公效率和用户体验。
IM 认证凭证的流程是:
增量拉取
在一些客户端和服务器之间需要同步的数据拉取上,我们采用增量更新的逻辑,减少每次服务器的响应数据集,加快客户端的登录和同步流程。
实现方式上,IM 采用以更新时间作为查询的 key ,服务器在每次更新数据的时候,都要更新 updatetime 字段。在客户端再次登录的时候,使用本地最新的更新时间去拉取数据,服务器如果存在比客户端更新的数据,则将增量的数据返回给客户端。
应用的场景有:
机器人实现
由于我们需要通过 IM 实现一些自助服务或者智能回复,我们需要在 IM 的扩展上实现该功能。
首先我们已经有了所有消息的队列服务功能,然后我们基于消息队列,订阅所有的消息,然后根据系统配置,将发送给特定机器人的消息,转发给对应的机器人服务。机器人服务收到发给自己的消息时,通过自己的系统配置或者自主学习的问题库,进行对应的操作,并调用 IM 的发消息接口,返回给咨询用户特定的消息。我们可以通过该方式,实现各种自助和智能化的服务。节省人力成本和提高办公效率。
客服系统实现
对于客服系统,和普通 IM 有一些不同之处。在用户看来,他是在和一个店铺或者一个官方客服在聊天。实际上,后面可能是多个不同的客服,可能还会用到排队、会话超时等逻辑,所以要在常用的 IM 功能上来做扩展。
客服系统订阅所有的 IM 消息,当用户发送消息给客服的时候,客服系统需要对咨询做排队,客服分配,会话建立,然后将用户发给客服的消息转换成发给具体某一个客服的消息,然后发送给客服。
用户-------------> 店铺 转换成 店铺-----------> 客服 客服-------------> 店铺 转换成 店铺-----------> 用户
对于 IM 主要的指标,我们主要关注的有:
下面是对应指标的实际数值
通过实现基本的 IM 功能,以及各种扩展功能,我们总结出一些 IM 核心功能:
相关链接:
参考链接: