极光推送技术原理:移动无线网络长连接

移动互联网应用现状

因为手机平台本身、电量、网络流量的限制,移动互联网应用在设计上跟传统 PC 上的应用很大不一样,需要根据手机本身的特点,尽量的节省电量和流量,同时又要尽可能的保证数据能及时到达客户端。

为了解决数据同步的问题,在手机平台上,常用的方法有2种。一种是定时去服务器上查询数据,也叫Polling,还有一种手机跟服务器之间维护一个 TCP 长连接,当服务器有数据时,实时推送到客户端,也就是我们说的 Push。

从耗费的电量、流量和数据送达的及时性来说,Push 都会有明显的优势,但 Push 的实现和维护成本相对较高。在移动无线网络下维护长连接,相对也有一些技术上的难度。本文试图给大家介绍一下我们极光推送在 Android 平台上是如何维护长连接。

移动无线网络的特点

因为 IP v4 的 IP 量有限,运营商分配给手机终端的 IP 是运营商内网的 IP,手机要连接 Internet,就需要通过运营商的网关做一个网络地址转换(Network Address Translation,NAT)。简单的说运营商的网关需要维护一个外网 IP、端口到内网 IP、端口的对应关系,以确保内网的手机可以跟 Internet 的服务器通讯。

http://www.cisco.com/en/US/i/100001-200000/110001-120000/119001-120000/119935.jpg

图片源自 cisco.com. 

NAT 功能由图中的 GGSN 模块实现。

大部分移动无线网络运营商都在链路一段时间没有数据通讯时,会淘汰 NAT 表中的对应项,造成链路中断。

Android 平台上长连接的实现

为了不让 NAT 表失效,我们需要定时的发心跳,以刷新 NAT 表项,避免被淘汰。

Android 上定时运行任务常用的方法有2种,一种方法用 Timer,另一种是AlarmManager。

Timer

Android 的 Timer 类可以用来计划需要循环执行的任务,Timer 的问题是它需要用 WakeLock 让 CPU 保持唤醒状态,这样会大量消耗手机电量,大大减短手机待机时间。这种方式不能满足我们的需求。

AlarmManager

AlarmManager 是 Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。

这意味着,如果我们用 AlarmManager 来定时执行任务,CPU 可以正常的休眠,只有在需要运行任务时醒来一段很短的时间。极光推送的 Android SDK 就是基于这种技术实现的。

服务器设计

当有大量的手机终端需要与服务器维持长连接时,对服务器的设计会是一个很大的挑战。

假设一台服务器维护10万个长连接,当有1000万用户量时,需要有多达100台的服务器来维护这些用户的长连接,这里还不算用于做备份的服务器,这将会是一个巨大的成本问题。那就需要我们尽可能提高单台服务器接入用户的量,也就是业界已经讨论很久了的 C10K 问题。

C2000K

针对这个问题,我们专门成立了一个项目,命名为C2000K,顾名思义,我们的目标是单机维持200万个长连接。最终我们采用了多消息循环、异步非阻塞的模型,在一台双核、24G内存的服务器上,实现峰值维持超过300万个长连接。

后记

稳定维护长连接是推送平台的一个基础,极光推送团队将会在这方面长期投入,以保证用户能有效的节省电量、流量,同时数据能实时送达。

极光推送技术原理:移动无线网络长连接》上有38条评论

  1. 土豆地瓜

    不管是不是长连接,系统一休眠,不是也收不到推送消息吗?除非能支持wireless/3G唤醒?

    1. javenjaven

      JPush 原理与苹果的 APNs 是类似的。手机状况正常的情况下休眠时也可以收到消息。你多测试下就可以体会到了。

      1. biliu

        android手机在休眠状态下,网络应该是断开的,你说的jpush在休眠状态下也能收到消息,是因为你们使用AlarmManager定时唤醒手机,在手机唤醒的时候主动去服务器pull吗?如果是这样是否会有延迟,如果不是,能否分享一下,我对这个挺感兴趣的?

        1. tiimfei

          我也有类似的疑问。 保持长连接是为了及时收到消息,但是安卓系统休眠时,即使收到消息,cpu也不会被唤醒。 除非是将AlarmManager的时间设定的较短,定时唤醒手机,看这个tcp链接上是否有消息收到。 不知道是否微信之类的实时消息应用都是这样实现的? 这样感觉会比较费电啊。特别是当手机上安装了多个有这种推送功能的应用之后。

  2. 梁良

    mqtt V3 协议心跳包的发送不受控制,客户端只能通过topic保持休眠期不掉线,个人觉得这样就失去了mqtt心跳包小的优势。

  3. 王帅

    我使用Android版本的时候注意到一个问题,如果我没有自定义receiver而点击通知的话,的确是回到主界面,但当我按了后退键时,发现其实是new了一个新的主界面activity在activity栈中,导致按一下后退不是退出程序而是回到上一个主界面activity,请问这样正常吗?

  4. vincentyong

    手机客户端都是TCP长连接,极光的推送平台,单机可承受200w的并发TCP连接,服务器的水平扩展是通过类似F5的负载均衡设备吗?若要达到几千万的并发,你们使用网络防火墙吗?

  5. bart

    有些手机闹钟服务被替换或者修改,导致不会按预设的时间间隔启动,那么使用闹钟发心跳会不会有问题?

  6. 杨继国

    想问问你们的心跳策略,2g 2.5g 3g wifi 是否策略不一样,重连的时候会重试几次,心跳一个月要消耗多少流量

    1. pengfei.x

      200w长连接 肯定不是200w并发 消息推送到全部的客户端的时间并没有说明 另外如果是富文本的消息 200w消息推下去 带宽得多少?

      希望可以多透露一些技术细节 🙂

      1. Admin 文章作者

        200W 长连接一直在那儿,消息可以并发。这只是一个节点。
        实际上,我们有 N 多接入服务器,消息并发下行远远不止 200W。

        富媒体内容本身并不走消息通道。

  7. walker

    比较关心心跳的间隔,如果AlarmManager的间隔时间短,后台又存在多个JPush Service的实例(如存在多个使用JPush做为推送实现的app),虽然说服务器端可以共享链接,但我个人的理解,这只是为了减轻服务器端的负载;客户端多个JPush Service实例使用的AlarmManager对CPU做唤醒如果不是同步的,Android很有可能永远不会进Deep Sleep,CPU会一直在跑,耗电也会增加很多。

    1. javenjaven

      你说的对:如果一个手机上有多个 JPush SDK,节省电量角度,就需要客户端做共享连接的动作。

  8. 周亮

    问下,在彻底关闭app的情况下,还能收到jpush推送过来的消息吗?即能不能像微信那样,app关闭了依然可以收到消息。

    1. javenjaven

      大多数情况下是可以的。 在某些手机环境下,如果限制了你的 App 在后台连网(微信一般不会被限制),则就无法 PushService 再运行起来。

  9. Charles

    我想问一下,如果APP进程被杀掉,TCP连接不就断了吗,这时候 Android SDK 难道会重连TCP,还是杀掉进程并不会杀掉该TCP连接,从而能收到推送。

    1. Javen FangJaven Fang

      杀掉进程后,SDK 会被一些系统广播触发再起来,比如:网络切换、屏幕点亮等。 另外,SDK 本身也定时心跳,这个定时也是一个系统广播。

      在某些特殊的 Android ROM 里因限制的确可能存在起不来的情况。详细情况请到极光社区里搜索:community.jiguang.cn

  10. littlefat

    我这边最近遇到一个问题,短消息推送在不同网络情况下的实时性
    通过对比在CDMA网络下比较稳定,而在WCDMA网络情况下,短消息推送则不及时,最长可达1分钟左右

    不知道你们有没有遇到过这种课题,使用我们的APP,微信,还有极光推送,都遇到这个问题了

    1. Javen FangJaven Fang

      中国运营商的网络很复杂,互通性不好,在不同网络条件下表现时好时坏,也算是正常的 :)

      1. littlefat

        测试到的情况并不是时好时坏,在一定条件下,W网会出现很稳定的延迟,最高约1分钟
        CDMA, WCDMA, LTE三者对比,WCDMA最差

        超出应用程序之外,很多东西,没有资源和专业支持,就只能在应用程序中折中了

        我们的APP为VOIP类型应用,要求实时性,针对这种情况,需要更改很多处理机制~

评论已关闭。