IM技术调研
协议选型
选用什么网络传输协议(TCP/UDP/HTTP) ?
- udp协议虽然实时性更好,但是如何处理安全可靠的传输并且处理不同客户端之间的消息交互是个难题,实现起来过于复杂. 目前大部分IM架构都不采用UDP来实现。
- HTTP
http可以用来实现状态协议,离线消息用拉模式,避免 tcp 通道压力过大,影响即时消息下发效率。
IM进行图片聊天的时候: http能够很方便的处理 断点续传和分片上传等功能。 - TCP: 维护长连接,保证消息的实时性, 对应数据传输协议.目的: 及时收发消息。
综合考虑,使用http和tcp。
选用什么数据通信协议?
- IM协议选择原则一般是:易于拓展,方便覆盖各种业务逻辑,同时又比较节约流量。节约流量这一点的需求在移动端IM上尤其重要。
xmpp |
协议开源,可拓展性强,在各个端(包括服务器)有各种语言的实现,开发者接入方便。但是缺点也是不少:XML表现力弱,有太多冗余信息,流量大,实际使用时,有大量天坑。 |
MQTT |
协议简单,流量少,但是它设计之初并不是一个专门为IM设计的协议,多使用于物联网、推送。IM需要自己在业务上实现。(近几年有很多公司使用MQTT实现通用IM框架),服务端实现相比其他协议会复杂一些。 |
私有协议 |
自己实现协议,一个被良好设计的私有协议一般有如下优点:高效,节约流量(一般使用二进制协议),安全性高,难以**。 |
综合考虑,MQTT协议更适合我们。
MQTT协议概述
客户端
指使用MQTT的程序或设备。客户端总是去连接服务端。它可以:
- 发布其他客户端可能会感兴趣的应用消息
- 订阅自己感兴趣的的应用消息
- 退订应用消息
- 从服务端断开连接
服务端
扮演订阅或发布应用消息的客户端之间的中间人。一个服务端:
- 接受客户端的网络连接
- 接受客户端发布的应用消息
- 处理客户端订阅和退订的请求
- 转发匹配客户端订阅的应用消息
从以上协议定义中我们知道,MQTT将客户端和服务端限制了4种功能。假如我们要实现IM业务都需要按照它规定的要求来实现。
举例说明
场景:客户端A要给客户端B发送一条消息,按照MQTT协议是如何实现的。
最简单的流程,B向服务器订阅话题test,A向服务器test话题发布消息,B收到消息。
流程图如下:
MQTT协议比较特别的方式就是它的发布与订阅,相比传统的收发消息,它要多一步订阅,只有订阅了你才能收到消息,也只能通过订阅的方式来收消息没有别的途径。
技术实现方式
在说实现方式前,先说一下技术的难点。
难点1:客户端与服务器保持稳定的长连接,比如心跳策略,断线重连。
难点2:如何保证消息可达(不丢)/唯一(不重复)/保序(不乱序)。
难点3:维护mqtt协议要求的发布、订阅等协议逻辑。
实现方式一
自主开发,服务器通过netty与客户端保持长连接,netty基于java技术栈,网上还有erlang或nodejs的实现方式,但综合考虑还是建议使用netty。订阅发布可以使用kafka或rabbitmq等中间件来实现。
方案的优点:自己开发不受框架限制,可以实现各种业务,开发顺利上线后,运营成本低。
方案的缺点:开发成本高,稳定性相比其他方式较差,需要考虑的因素非常多,容易出问题。
实现方式二
基于ActiveMq
直接使用开源的activieMQ来实现客户和服务器端。
方案的优点:不用操心长连接稳定性问题,不用操心消息的送达率、顺序等问题。
方案的缺点:基于activeMq可能会受到一些业务限制。
实现方式三
使用第三方IM服务,比较出名的提供商:容联、网易云信,环信、融云等。
对比文章参考:
方案的优点:相比之下开发工作量最小,服务稳定。
方案的缺点:收费。
重点问题解答
MQTT协议在IM业务场景下是否实用?
答:实用。
推送怎么做?
答:如果自己开发,会先判断用户是否在线,假如在线会通过长链给用户发布消息,客户端回复收到推送消息确保推送成功。
假如用户不在线,会调用内部推送系统使用极光推送消息给用户。
Protobuf的实现
答:服务器引入google jar包即可编码和解码protobuf内容。Protobuf的内容定义参考MQTT协议规范。
即时通讯消息编号
答:服务器通过雪花算法来生成唯一且有序的唯一消息id。保证消息的有序唯一。