专业IM即时通讯软件开发,值得信赖!

IM 即时通讯技术在多应用场景下的技术实现,以及性能调优

即时通讯软件开发 云聊IM 186℃

本文中所涉及到的所有 iOS 端相关代码,均已100%开源(不存在 framework ),便于学习参考。

本文侧重移动端的设计与实现,会展开讲,服务端仅仅属于概述,不展开。

为大家在设计或改造优化 IM 模块时,提供一些参考。

我现在任职于 LeanCloud(原名 AVOS ) 。LeanCloud 是国内较早提供 IM 服务的 Paas 厂商,提供 IM 相关的 SDK 供开发者使用,现在采纳我们 IM 方案的 APP 有:知乎Live、掌上链家、懂球帝等等,在 IM 方面也积累了一些经验,这次就在这篇博文分享下。

作者:iOS程序犭袁

大规模即时通讯技术上的难点

思考几个问题:

  1. 如何在移动网络环境下优化电量,流量,及长连接的健壮性?现在移动网络有2G、3G、4G各种制式,并且随时可能切换和中断,移动网络优化可以说是面向移动服务的共同问题。
  2. 如何确保IM系统的整体安全?因为用户的消息是个人隐私,因此要从多个层面来保证IM系统的安全性。
  3. 如何降低开发者集成门槛?
  4. 如何应对新的iOS生态下的政策以及结合新技术:比如HTTP/2、IPv6、新的APNs协议等。

应用场景

一个 IM 服务最大的价值在于什么?

可复用的长连接。一切高实时性的场景,都适合使用IM来做。

比如:

  1. 视频会议、聊天、私信
  2. 弹幕、抽奖
  3. 互动游戏
  4. 协同编辑
  5. 股票基金实时报价、体育实况更新、
  6. 基于位置的应用:Uber、滴滴司机位置
  7. 在线教育
  8. 智能家居

下文会挑一些典型的场景进行介绍,并涉及到技术细节。

IM 发展史

基本的发展历程是:轮询、长轮询、长连接。

挑一些代表性的技术做下介绍:

一般的网络请求:一问一答

轮询:频繁的一问一答

长轮询:耐心地一问一答

一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。

短轮询很容易理解,那么什么叫长轮询?与短轮询有什么区别。

举个例子:

比如中秋节我们要做一个秒杀月饼的页面,要求我们要实时地展示剩余的月饼数量,也就是库存量。这时候如果要求你只能用短轮询或长轮询去做,怎么做呢?

长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管服务端有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止,这就是区别。

(实际开发中不会使用长短轮询来做这种需求,这里仅仅是为了说明两者区别而做的一个例子。)

长轮询曾被 Facebook 早起版本采纳,示意图如下:

HTML5 WebSocket: 双向

参考: What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?

我们可以看到,发展历史是这样:从长短轮询到长连接,使用 WebSocket 来替代 HTTP。

其中长短轮询与长短连接的区别主要有:

  1. 概念范畴不同:长短轮询是应用层概念、长短连接是传输层概念
  2. 协商方式不同:一个 TCP 连接是否为长连接,是通过设置 HTTP 的 Connection Header 来决定的,而且是需要两边都设置才有效。而一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
  3. 实现方式不同:连接的长短是通过协议来规定和实现的。而轮询的长短,是服务器通过编程的方式手动挂起请求来实现的。

在移动端上长连接是趋势。

其最大的特点是节省 Header。

轮询与 WebSocket 所花费的Header流量对比:

让我们来作一个测试:

假设 Header 是871字节,

我们以相同的频率 10W/s 去做网络请求, 对比下轮询与 WebSocket 所花费的 Header 流量:

Header 包括请求和响应头信息。

出于兼容性考虑,一般建立 WebSocket 连接也采用 HTTP 请求的方式,那么从这个角度讲:无论请求如何频繁,都只需要一个 Header。

并且 Websocket 的数据传输是 frame 形式传输的,帧传输更加高效,对比轮询的2个 Header,这里只有一个 Header 和一个 frame。

而 Websocket 的frame 仅仅用2个字节就代替了轮询的871字节!

相同的每秒客户端轮询的次数,当次数高达 10W/s 的高频率次数的时候,Polling 轮询需要消耗665Mbps,而 WebSocket 仅仅只花费了1.526Mbps,将近435倍!!

数据参考:

  1. HTML5 WebSocket: A Quantum Leap in Scalability for the Web
  2. 《微信,QQ这类IM app怎么做——谈谈Websocket》

下面探讨下长连接实现方式里的协议选择:

大家都在使用什么技术

最近做了两个 IM 相关的问卷,累计产生了900多条的投票数据:

  1. 《你项目中使用什么协议实现了 IM 即时通讯》
  2. 《IM 即时通讯中你会选用什么数据传输格式?》

注:本次投票是发布在微博@iOS程序犭袁 ,鉴于微博关注机制,本数据只能反映出 IM 技术在 iOS 领域的使用情况,并不能反映出整个IT行业的情况。

下文会对这个投票结果进行下分析。

协议如何选择?

IM 协议选择原则一般是:易于拓展,方便覆盖各种业务逻辑,同时又比较节约流量。后一点的需求在移动端 IM 上尤其重要。常见的协议有:XMPP、SIP、MQTT、私有协议。

我们这里只关注前三名,

一个好的协议需要满足如下条件:高效,简洁,可读性好,节约流量,易于拓展,同时又能够匹配当前团队的技术堆栈。基于如上原则,我们可以得出: 如果团队小,团队技术在 IM 上积累不够可以考虑使用 XMPP 或者 MQTT+HTTP 短连接的实现。反之可以考虑自己设计和实现私有协议,这里建议团队有计划地迁移到私有协议上。

这里特别提一下排名第二的 WebSocket ,区别于上面的聊天协议,这是一个传输通讯协议,那为什么会有这么多人在即时通讯领域运用了这一协议?除了上文说的长连接特性外,这个协议 web 原生支持,有很多第三方语言实现,可以搭配 XMPP、MQTT 等多种聊天协议进行使用,被广泛地应用于即时通讯领。

社交场景

最大的特点在于:模式成熟,界面类似。

我们专门为社交场景开发的开源组件:ChatKit-OC,star数,1000+。

ChatKit-OC 在协议选择上使用的是 WebSocket 搭配私有聊天协议的方式,在数据传输上选择的是 Protobuf 搭配 JSON 的方式。

项目地址:ChatKit-OC

下文会专门介绍下技术实现细节。

直播场景

一个演示如何为直播集成 IM 的开源直播 Demo:

项目地址:LiveKit-iOS

(这个库,我最近也在优化,打算做成 Lib,支持下 CocoaPods 。希望能帮助大家快速集成直播模块。有兴趣的也欢迎参与进来提 PR)

LiveKit 相较社交场景的特点:

  1. 无人数限制的聊天室
  2. 自定义消息
  3. 打赏机制的服务端配合

有人可能有这样的疑问:

(叫我Elon(读:一龙)就好了)

那么可以看下 Demo 的实现:我们可以看到里面的弹幕、礼物、点赞出心这些都是 IM 系统里的自定义消息。

数据自动更新场景

  1. 打车应用场景(Uber、滴滴等 APP 首页的移动小车)
  2. 朋友圈状态的实施更新,朋友圈自己发送的消息无需刷新,自动更新

这些场景比聊天要简单许多,仅仅涉及到监听对象的订阅、取消订阅。
正如上文所提到的,使用 MQTT 实现最为经济。用社交类、直播类的思路来做,也可以实现,但略显冗余。

电梯场景(假在线状态处理)

iOS端的假在线的状态,有两种方案:

  1. 双向ping pong机制
  2. iOS端只走APNs

双向 ping-pong 机制:

Message 在发送后,在服务端维护一个表,一段时间内,比如15秒内没有收到 ack,就认为应用处于离线状态,先将用户踢下线,然后转而进行推送。这里如果出现,重复推送,客户端要负责去重。将 Message 消息相当于服务端发送的 Ping 消息,APP 的 ack 作为 pong。

使用 APNs 来作聊天

优缺点:

优点:

解决了,iOS端假在线的问题。

缺点:(APNs的缺点)

  1. 无法保证消息的及时性。
  2. 让服务端负载过重

APNs不保证消息的到达率,消息会被折叠:

你可能见过这种推送消息:

这中间发生了什么?

当 APNs 向你发送了4条推送,但是你的设备网络状况不好,在 APNs 那里下线了,这时 APNs 到你的手机的链路上有4条任务堆积,APNs 的处理方式是,只保留最后一条消息推送给你,然后告知你推送数。那么其他三条消息呢?会被APNs丢弃。

有一些 App 的 IM 功能没有维持长连接,是完全通过推送来实现的,通常情况下,这些 App 也已经考虑到了这种丢推送的情况,这些 App 的做法都是,每次收到推送之后,然后向自己的服务器查询当前用户的未读消息。但是 APNs 也同样无法保证这四条推送能至少有一条到达你的 App。

为什么这么设计?APNs的存储-转发能力太弱,大量的消息存储和转发将消耗 Apple 服务器的资源,可能是出于存储成本考虑,也可能是因为 Apple 转发能力太弱。总之结果就是 APNs 从来不保证消息的达到率。并且设备上线之后也不会向服务器上传信息。

现在我们可以保证消息一定能推送到 APNs 那里,但是 APNs 不保证帮我们把消息投递给用户。

即使搭配了这样的策略:每次收到推送就拉历史记录的消息,一旦消息被 APNs 丢弃,这条消息可能会在几天之后受到了新推送后才被查询到。

让服务端负载过重:

APNs 的实现原理决定了:必须每次收到消息后,拉取历史消息。这意味着你无法控制 APP 请求服务端的频率,同一时间十万、百万的请求量都是可能的,这带来的负载以及风险,有时甚至会比轮询还要大。

参考:《基于HTTP2的全新APNs协议》

结论:如果面向的目标用户对消息的及时性并不敏感,可以采用这种方案。比如社交场景。(对消息较为敏感的APP则并不适合,比如:专门为情侣间使用的APP。。。)

技术实现细节

基于 WebSocket 的 IM 系统

WebSocket简介

WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。 WebSocket 通信协定于2011年被 IETF 定为标准 RFC 6455,WebSocket API 被 W3C 定为标准。

在 WebSocket API 中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

只从 RFC 发布的时间看来,WebSocket要晚很多,HTTP 1.1是1999年,WebSocket 则是12年之后了。WebSocket 协议的开篇就说,本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮训的问题而创建的。可以达到支持 iOS,Android,Web 三端同步的特性。

喜欢 (0)
聊天软件开发
点击这里给我发消息