请选择 进入手机版 | 继续访问电脑版

默认
打赏 发表评论 2
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
实践分享:如何构建一套高可用的移动端消息推送系统?
微信扫一扫关注!

内容概述


消息推送作为移动端 APP 运营中的一项关键技术,已经被越来越广泛的运用。

本文追溯了推送技术的发展历史,剖析了其核心原理,并对推送服务的关键技术进行深入剖析,围绕消息推送时产生的服务不稳定性,消息丢失、延迟,接入复杂性,统计缺失等问题,提供了一整套平台级的高可用消息推送解决方案。实践中,借助于该平台,不仅能提能显著提高消息到达率,还能提高研发效率,并道出了移动开发基础设施的平台化架构思路。

另外,《深入的聊聊Android消息推送这件小事》这篇文章也可以重点看看。

参考资料


[1] 有关推送技术的综合文章:
iOS的推送服务APNs详解:设计思路、技术原理及缺陷等
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
扫盲贴:认识MQTT通信协议
一个基于MQTT通信协议的完整Android推送Demo
IBM技术经理访谈:MQTT协议的制定历程、发展现状等
求教android消息推送:GCM、XMPP、MQTT三种方案的优劣
移动端实时消息推送技术浅析
扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别
绝对干货:基于Netty实现海量接入的推送服务技术要点
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
为何微信、QQ这样的IM工具不使用GCM服务推送消息?
极光推送系统大规模高并发架构的技术实践分享
从HTTP到MQTT:一个基于位置服务的APP数据通信实践概述
魅族2500万长连接的实时消息推送架构的技术实践分享
专访魅族架构师:海量长连接的实时消息推送系统的心得体会
深入的聊聊Android消息推送这件小事
基于WebSocket实现Hybrid移动应用的消息推送实践(含代码示例)
一个基于长连接的安全可扩展的订阅/推送服务实现思路
>> 更多同类文章 ……

[2] 有关IM/推送的通信格式、协议的选择:
为什么QQ用的是UDP协议而不是TCP协议?
移动端即时通讯协议选择:UDP还是TCP?
如何选择即时通讯应用的数据传输格式
强列建议将Protobuf作为你的即时通讯应用数据传输格式
全方位评测:Protobuf性能到底有没有比JSON快5倍?
移动端IM开发需要面对的技术问题(含通信协议选择)
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
理论联系实际:一套典型的IM通信协议设计详解
58到家实时消息系统的协议设计等技术实践分享
>> 更多同类文章 ……

[3] 有关IM/推送的心跳保活处理:
Android进程保活详解:一篇文章解决你的所有疑问
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
深入的聊聊Android消息推送这件小事
为何基于TCP协议的移动端IM仍然需要心跳保活机制?
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
>> 更多同类文章 ……

消息推送基础知识


移动互联网蓬勃发展的今天,大部分手机 APP 都提供了消息推送功能,如新闻客户端的热点新闻推荐,IM 工具的聊天消息提醒,电商产品促销信息,企业应用的通知和审批流程等等。推送对于提高产品活跃度、提高功能模块使用率、提升用户粘性、提升用户留存率起到了重要作用,作为 APP 运营中一个关键的免费渠道,对消息推送的合理运用能有效促进目标的实现。

推送最早诞生于 Email 中,用于提醒新的消息,而移动互联网时代则更多的运用在了移动客户端程序。要获取服务器的数据,通常有两种方式:第一种是客户端 PULL(拉)方式,即每隔一段时间去服务器获取是否有数据;第二种是服务端 PUSH(推)方式,服务器在有数据的时候主动发给客户端。

很显然,PULL 方案优点是简单但是实时性较差,我们也可以通过提高查询频率来提高实时性,但这又会造电量、流量的消耗过高,反之 PUSH 方案基于 TCP 长连接方式实现,消息实时性好,但是由于要保持 APP 客户端和服务端的长连接心跳,也会带来额外的电量和流量消耗。因此在整体架构设计中需要折中平衡,目前主流的推送实现方式都是基于 PUSH 的方案。

移动端消息推送的三种典型实现方式


目前移动推送技术实现方式主要有以下三种:

  • 轮询方式(PULL):
    客户端和服务器定期的建立连接,通过消息队列等方式来查询是否有新的消息,需要控制连接和查询的频率,频率不能过慢或过快,过慢会导致部分消息更新不及时,过快会消耗更多的资源(流量、电量等),对用户体验有较大伤害。
  • 短信推送方式(SMS PUSH):
    通过短信发送推送消息,并在客户端植入短信拦截模块(主要针对 Android 平台),可以实现对短信进行拦截并提取其中的内容转发给 App 应用处理,这个方案借助于运营商的短消息,能够保证最好的实时性和到达率,但此方案对于成本要求较高,开发者需要为每一条 SMS 支付费用。
  • 长连接方式(PUSH):
    移动 Push 推送基于 TCP 长连接实现, 客户端主动和服务器建立 TCP 长连接之后, 客户端定期向服务器发送心跳包用于保持连接, 有消息的时候, 服务器直接通过这个已经建立好的 TCP 连接通知客户端。尽管长连接也会造成一定的开销,对于轮询和 SMS 方案的硬伤来说,目前已经是最优的方式,而且通过良好的设计,可以将损耗降至最低。不过,随着客户端数量和消息并发量的上升,对于消息服务器的性能和稳定性要求提出了非常大的考验。因此,就难度而言,此方式代价最高。

移动端消息推送的解决方案列举


基于 TCP 长连接的方式是主流的推送方式,基于该推送方式逐步发展出系统级、应用级一系列的推送解决方案。

1系统级方案


iOS 平台(APNs):
iOS 在系统层面与苹果 APNs(Apple Push Notification service)服务器建立连接,应用通过观察者模式向 ioS 系统注册关注的消息,系统收到 APNs Server 消息后转发到相应的应用程序,整个过程很清晰,并且所有 APP 都共用同一个系统级的连接,减少了系统开销,虽然 APNs 能无障碍的访问,但实际使用过程中,发现延时和丢消息的情况偶有发生。

Android 平台(C2DM):
Android 的 C2DM(Android Cloud to Device Messaging)采取与 iOS 类似的机制,都是由系统层面来支持消息推送,但是由于 Google 的服务在国内不能稳定的访问,此方案对于中国用户来说基本是无法使用的。

除了 Google 官方提供的方案,中国众多的手机厂商在其定制的系统中也内置了推送功能,如小米、华为等。

即时通讯网注:自2012年起,Android官方已经废弃了C2DM,取而代之的是GCM,有关GCM的详细资料请参见:《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》、《为何微信、QQ这样的IM工具不使用GCM服务推送消息?》、《求教android消息推送:GCM、XMPP、MQTT三种方案的优劣》这几篇文章。

2应用级方案


第三方推送服务:

鉴于 Android 平台 C2DM 推送的不可用性,国内涌现出大量的第三方推送服务提供商,采用第三方推送服务的系统流程如下图:

1.jpeg

目前应用最为广泛的第三方推送服务提供商包括个推、极光、友盟、小米、华为、BAT 等,绝大部分 APP 都会优先考虑采用第三方推送服务。

自建推送服务:

第三方服务在开发成本和消息到达率上表现都不错,但所有信息会经过第三方服务器,对于信息敏感类 APP 而言,有必要考虑自建一套消息推送服务,能最大化保证安全,但对于自建推送服务,如果从零开始来做需要解决几个难点:

  • 第一:移动推送服务器对 App 客户端海量长连接的维护管理;
  • 第二:App 客户端如何保证 Push Service 常驻,对于 Android 我们可以通过发现 push service 不存在可以定时拉起的方式;
  • 第三:通信协议的制定,我们可以采用开源的 XMPP 方式实现,也可以自定义协议,不管哪种方式我们都要保证消息传送的到达率的准确性;
  • 第四:在移动互联网网络环境下,经常出现弱网环境,特别是 2G、3G 等网络不稳定的情况下,如果保证消息在弱网环境下不重、不丢也是一个挑战。

要构建真正可用的移动端推送系统还存在的问题


无论是第三方推送服务,还是自建推送服务,在实际的使用过程中,发现都存在以下问题:

  • 应用服务端与推送服务强耦合。当推送服务不可用时,造成整个业务系统无法推送,甚无法正常工作。
  • 缺乏 ACK 机制。推送的过程是异步的,从应用服务端发送到推送服务时,可以得知发送是否成功,但是从第三方推送服务下发到 APP 时,无法得知客户端是否接收到。iOS 平台中,从推送服务发送到苹果 APNs 服务时,同样无法确定 APNs 是否收到。同时,第三方推送服务通常使用共享的推送通道,受其他推送方的影响,可能造成消息的延迟和丢失。
  • 服务会被杀死。尤其在 Android 平台上,后台推送 service 会被各种主动或者被动原因 kill 掉,导致消息丢失。
  • 缺乏消息的持久化。对于推送服务而言,消息推送是来一条推一条,无法追溯历史消息和消息状态。
  • 缺乏重传机制。整个推送过程涉及多个环节,当其中某个环节出现问题,造成客户端接收不到推送的消息时,就导致消息丢失,再无法接收到。
  • 客户端接入逻辑复杂。每接入一个新的 APP,都要进行重复的接入工作,接入逻辑完全一致,代码无法复用,需要在不同项目中拷贝。
  • 客户端与推送服务的 SDK 强耦合。客户端使用推送服务的接口,而各推送服务提供的接口不统一,如果需要替换推送服务,那么接入部分代码需完全重写。
  • 缺乏数据监控和统计。每个应用每天推送了多少消息,成功到达 app 多少,失败多少,目前均没有统计。

本文总结的解决之道


为了解决以上问题,我们考虑基于第三方消息推送服务构建一套移动消息推送中间件平台,该消息平台采用了低耦合的分层架构设计(如图 2 所示),分为三层:接入层、传输层和应用层。其中接入层是业务方调用的入口,我们采用异步消息队列的方式提供了较高的业务系统发送消息的速度,并且具备了消息缓冲功能,即使高峰期的海量消息推送对整个平台冲击较少,保护了推送系统。

传输层会从接入层接收消息并进行解析,对推送消息进行合法性检查校验,如果消息不合法直接丢弃,同时将合法的消息进行协议转换并发送到对应的第三方推送平台;应用层主要是提供统一的 SDK 供业务使用,封装适配第三方推送平台的 SDK 接口到统一的接口 SDK 中,这样业务 APP 使用方只关注统一封装的 SDK 即可实现业务消息的操作,而不需要考虑各种滤重、校验等通用操作。主要功能包括:

  • 屏蔽推送接口,实现业务与推送服务解耦,提供一套通用的客户端 SDK,简化客户端接入。
  • 实现多点接入,可同时接入多套推送服务,根据历史推送成功率动态选择最优推送路径,当一条路径失效可选择备用路径进行推送,保证消息推送万无一失。
  • 引入消息持久化机制,方便追溯和统计。
  • 引入消息的 ACK 机制和重传机制,提高消息的到达率。
  • 实现数据监控和统计机制,提供相关数据的统计分析,和报警预警功能。
  • 提供 web