By 紫韵: 最近对 IM 系统产生了兴趣,就看了些博客,现希望通过一个系列的文章对其稍作总结与记录,如有不对,还望指正。
IM 简介
IM:Instant Messaging,即时通讯,是一个允许两人或多人通过网络实时传输文字、语音、视频等的终端服务,如现在常用的 QQ、微信、百度 Hi 等。IM 完全基于 TCP/IP 网络协议族实现,而 TCP/IP 协议族则是整个互联网得以实现的技术基础。
通讯方式
典型的 IM 通讯方式有如下四种:
- 在线直连通讯:即 P2P(Peer To Peer)对等通讯方式,也就是通信双方直接建立通信连接进行点对点的通信;
- 在线中转通讯: 通信双方不是通过点对点直连方式进行通信,而是通过一个服务端作为代理来进行通信,即消息发送方将消息发送给服务器,然后服务器再将消息转发给消息接收方;
- 离线中转通讯:以上两种方式都是基于通信双方均在线的前提之下,但是有时消息接收方并不一定刚好在线。当消息接收方处于离线状态时,也需要采用服务端中转方式进行消息投递。消息发送方现将消息发送到服务端,然后服务端转储消息,待消息接收方上线时再将消息转发给接收方;
- 扩展通讯:扩展通讯即调用其他通讯方式来完成通讯过程,如通过短信、Email、传真等方式将消息从发送方投递到接收方。
P2P && 服务器中转
一般常用的 IM 通讯方式就是 P2P 和服务器中转这两种,下面简要对比分析这两者的区别。
P2P:
P2P 多见于局域网内聊天工具,典型的应用有:飞鸽传书、天网 Maze 等。这类软件在启动后一般做两件事情:
进行 UDP 广播:发送自己信息和接受同局域网内其他端信息;
开启 TCP 监听:等待其他端进行连接。
限制和不便:
只适合 ** 在线 ** 的 ** 点对点 ** 消息传输,对离线、群组等业务支持不够;
由于 NAT 的存在,使得不同局域网内机器互联难度大大上升,在某些网络类型(对称 NAT)下无法建立连接。
** 服务器中转 **
几乎所有互联网 IM 产品都采用服务器中转这种方式进行消息传输,相比于 P2P 的方式,它的优劣如下:
优点:
能够支持更多P2P无法支持或支持不好的业务,如离线消息,群组,聊天室服务;
方便业务逻辑的拓展和新旧版本的兼容。缺点:服务器架构复杂,并发要求高。
工作方式
** 典型的 IM 工作方式如下:**
客户端登陆 IM 通讯中心(IM 通讯服务器),获取好友列表,获取离线消息,将自身标志为在线状态,与聊天对象建立聊天通道,进行文字、语音等通信。
- 用户 A 通过用户名和密码登录 IM 服务器,服务器通过读取数据库中用户信息进行校验,校验通过后,登记用户 A 的 ip 地址、IM 客户端版本号、使用的 TCP/UDP 端口号等并标记用户 A 的状态为在线,返回用户 A 登录成功标志;
- 用户 A 获取好有列表信息(包括:在线状态、IP 地址、TCP/UDP 端口号等)、离线消息;
- 服务器将用户 A 的在线相关信息通知到其在线好友 ,包括:在线状态、IP 地址、TCP/UDP 端口号等;
- 接下来用户 A 就可以通过直连/服务器中转方式与其它用户进行消息通信了。
IM 系统选型
一个典型的 IM 系统的选型过程大致包含如下几个部分:
- 服务方式:P2P or 服务器中转;
- 网络通讯协议:TCP or UDP;
- 数据通信协议:XMPP、SIP、MQTT、Protobuf、私有协议;
- 协议加密:加密流程的设计、加密算法的选择;
- 服务器:开源的 IM 服务器,如 OpenFire,Tigase,Prosody,Mosquitto,ejabberd等、自己的服务器。
** IM 系统架构分层:**
- ** 接入层(ENTRY):** 作为客户端和服务端的接口子系统,此层直接面对 PC 桌面客户端、WEB 网页客户端、移动 APPS 客户端的海量长连接请求,负责建立与客户端通信的加密通道,整合成内部少量有限的长连接,对通信数据进行压缩与解压,并将相应请求转发至逻辑层。除此之外,接入层实施初步的攻防策略,用来抵御非逻辑层面的攻击,监控某些数据(连接频率、发包频率、发包速率等),对 IP/UID 等指标实施封禁,IM 在某些紧急情况下,必须能够迅速实施封禁,所以需要实时授权 IP/UID 等黑白名单,使得白名单动态生效、黑名单自动解封。
- ** 逻辑层(LOGIC):** 逻辑子系统主要是负责整个 IM 系统的逻辑处理,包括用户相关(用户登录登出、用户信息设置查询)、好友相关(添加好友、获取好友、删除好友、修改好友信息等)、消息相关(收发好友消息、收发陌生人消息、消息确认、通用消息处理、离线消息等)等复杂逻辑处理。
- ** 路由层(ROUTER):** 路由子系统主要处理和用户一次登录 session 相关的数据(比如:用户在线状态[在线、离开、隐身],登录IP等),这部分涉及的数据变化非常快,没必要固化,直接存储在内存中。并记录用户登录接入层的路由信息,支持向指定 UIDS 通信的功能。
- ** 数据层(DATA ACCESS):** 统一数据访问子系统屏蔽了底层的存储引擎,上层无需关心实际的存储是 RDBMS 或者 NoSQL 或者其他的 KV 存储引擎,对上层提供友好、统一的访问接口,封装原子逻辑。并通过 CURD 接口的抽象封装,增加新的数据操作只需要增加配置,不用变动数据层代码,较容易完成关键数据的存储。
- ** 数据存储层(DATA STORAGE):** 数据存储层是 IM 的固化存储系统,根据业务数据特点决定使用何种持久化存储方式(RDBMS(MySQL)、NoSQL(MongoDB)等),并通过分布式缓存(Memcached、Redis等)加速查询。
一个典型的 IM 系统可能由如下及部分组成:
- 客户端:用于让用户接入系统;
- 注册服务器:用户接入系统时使用,提供鉴权等相应处理;
- 连接服务器:用于保持与所有用户的连接,状态消息的通知以及客户会话请求时通信服务器相关信息的返回;
- 通信服务器:用于通信渠道的建立以及离线信息的保存。包括离线文件传输。根据实际情况可以考虑增加一台文件服务器,供通信服务器使用;
- 数据库服务器:提供对于数据库所有的操作接口。所有关于数据库的操作均归必须通过该台位;
- 鉴权服务器:可有可无,供注册服务器使用,主要用于鉴权。
IM 系统功能点/技术点分析
*** 功能点分析:***
- 注册登录:注册方式(手机、邮箱、昵称)、登录验证(注册信息、三方、手机动态验证登录)等;
- 聊天:文字、语音、图片、视频、表情;单聊、群聊;
- 传输服务:文本传输、文件传输;
- 好友 / 群组管理:添加、删除、查找好友 / 群;
- 多端服务:PC 端、Android 端、IOS 端等;
- 用户信息管理。
*** 技术点分析:***
-
登录优化:
- 登录方式:注册信息、三方、手机验证码动态登录、无需登录等;
- LBS 请求:异步化,不在登录时进行 LBS 请求,而是在网络空闲和发生变化时进行请求并缓存,每次登录则直接从本地缓存获取连接地址,以加快登录速度;
- DNS 优化:移动端 DNS 解析时间长、准确率较低、容易被劫持,特别需要优化;优化策略:
- 使用 HTTP DNS,如开源的 HttpDNSLib;
- 尽可能避免 DNS 解析请求:如 LBS 直接返回待连接的服务器的 IP 地址而非域名;本地缓存 LBS IP 地址备用,请求 LBS 时优先使用 IP 而非域名;
- 登录认证请求的优化;
- 数据同步策略优化:用户登录 IM 系统后,需要在主界面呈现用户的好友列表、群组列表等信息,主要包括:好友列表、好友详情信息、群组列表、群组详情信息、群成员列表、群成员详情信息等。如果所有信息均在登录过程中进行同步的话,登录过程会耗时很长,并且流量消耗很大,从而导致用户体验很差,大致可以从如下几个方面进行优化:
- 按时间戳同步:客户端只同步比本地缓存新的数据;
- 延迟加载和按需更新:初始页面并不需要将所有信息均提供给用户,而是只需要保证映入用户眼帘的页面信息完全即可,这些信息主要有:好友列表、群组列表、离线消息记录;而好友详情信息、群组详情信息、群成员列表和群成员详情信息等均可以在用户进入相应的页面再按需更新或等到网络空闲时再加载即可;
服务器负载优化:多服务器专职化,各司其职(专门用于登录、鉴权、状态管理的服务器;专门用于消息通信的服务器等);服务器集群;分流(如可考虑消息直连通信 P2P);
消息同步机制
消息可靠性保证
消息时序性和一致性
消息推送机制
心跳保活机制
移动端 IM 技术难点
** 移动端 IM 客户端难点 **
- ** 流量:**移动端流量费较贵,所以省流量是移动端产品特别需要注意的性能指标。可以从网络通信协议、数据通讯协议、图片压缩技术、附件压缩技术等方面着手减少流量消耗;
- ** 耗电量 :**移动端的电量比较少,充电比较麻烦,需要注意电量消耗。一般来说,流量越小,耗电量越少;心跳次数越少,耗电量越少,不过这需要结合具体的业务场景来制定恰当的心跳策略;
- ** 心跳时长:**WIFI、2G、3G、4G、移动、电信、联通等不同网络、不同运行商下 NAT 失效时间是不一样的,因此心跳的时间也应当区别对待;
- ** 掉线重连机制** ;
- ** 网络不稳定:**移动端最大的特点就是网络切换频繁,从而导致网络不稳定,并且不同的网络环境下需要进行不同的处理(如 WIFI 网络和移动网络需要区别对待)。在不稳定的网络状态下,如何保证消息的到达率?如何保证消息以最快的速度到达?如何避免重联风暴?这些既需要从整体架构考虑,也需要在移动端采取巧妙的策略加以避免;
- ** 文件上传优化 **。
** 移动端架构设计的难点 **
- ** 连接器的设计:**连接器主要用来管理客户端的长连接;
- ** 中间件的设计:**是否采用通讯中间件?各种通讯中间件的优劣分析与选择?如果不采用中间件,如何管理连接器和逻辑服务器的连接关系?
- ** 逻辑服务器:**逻辑服务器通常简单一点,主要是根据业务逻辑进行最小粒度的划分即可;
- ** 状态服务器:**状态服务器主要管理用户在线、离线的相关状态。状态同步机制如何实现?状态存储机制,如何进行读写操作从而最大限度地提高状态服务器的处理能力和响应速度;
- ** 数据库的设计:**数据库设计相对来说比较难,当业务增长时容易成为性能瓶颈。因为无论是 SQL 关系型数据库,还是 NOSQL 非关系型数据库均有读写处理上限。
- ** 其他:**如推送机制、消息的可靠投递、消息同步机制、消息的时序性和一致性如何保证、在线消息和离线消息的区别对待等。这些都是必备而又非常复杂的功能技术点,都需要采取正确的架构和策略才能实现。