写点什么

消息推送技术干货:美团实时消息推送服务的技术演进之路

用户头像
JackJiang
关注
发布于: 刚刚
消息推送技术干货:美团实时消息推送服务的技术演进之路

本文由美团技术团队分享,作者“健午、佳猛、陆凯、冯江”,原题“美团终端消息投递服务 Pike 的演进之路”,有修订。

1、引言

传统意义上来说,实时消息推送通常都是 IM 即时通讯这类应用的技术范畴,随着移动端互联网的普及,人人拥有手机、随时都是“在线”已属常态,于是消息的实时触达能力获得了广泛的需求,已经不再局限于 IM 即时通讯这类应用中。

对于美团这种移动端“入口”级应用来说,实时消息的推送能力已经深入整个 APP 的方方面面。目前美团应用中使用的推送技术,是一个被命名为 Pike 的一套易接入、高可靠、高性能的双向消息实时投递服务

本文将首先从 Pike 的系统架构升级、工作模式升级、长稳保活机制升级等方面介绍 2.0 版本的技术演进,随后介绍其在直播、游戏等新业务场景下的技术特性支持,并对整个系统升级过程中的技术实践进行了总结,希望本文能给消息实时推送服务感兴趣或从事相关工作的读者以帮助和启发。(本文同步发布于:http://www.52im.net/thread-3662-1-1.html

2、相关文章

实时消息推送技术文章参考:

  1. 魅族2500万长连接的实时消息推送架构的技术实践分享

  2. 专访魅族架构师:海量长连接的实时消息推送系统的心得体会

  3. 百万在线的美拍直播弹幕系统的实时推送技术实践之路

  4. 京东京麦商家开放平台的消息推送架构演进之路

  5. 解密“达达-京东到家”的订单即时派发技术原理和实践

  6. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

  7. 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

  8. 微信直播聊天室单房间1500万在线的消息架构演进之路

  9. 百度直播的海量用户实时消息系统架构演进实践

  10. 技术干货:从零开始,教你设计一个百万级的消息推送系统

美团技术团队分享的其它文章:

  1. 美团点评的移动端网络优化实践:大幅提升连接成功率、速度等

  2. 深度解密美团的分布式ID生成算法

3、v1.0 的前世今生

3.1 v1.0 的诞生背景

2015 年,美团诞生了 Shark 终端网络通道,为公司移动端提供长连代理加速服务。Shark 通过网络接入点的全球多地部署和保持长连来提升网络请求的端到端成功率,降低端到端延时,从而提升用户体验。

Pike 1.0 是基于 Shark 长连通道实现的应用内推送服务。由于底层传输基于 Shark 长连通道,使得 Pike 1.0 天生便具有了低延时、高可靠、防 DNS 劫持等优秀基因。目前 Pike 1.0 在美团内部的即时通讯聊天、营销推送、状态下发、配置同步等业务场景都有广泛使用。

3.2 v1.0 的工作流程

Pike 1.0 移动端 SDK 会在每次长连接创建成功后:

  • 1)使用 APPID、设备唯一标识 UnionID(美团唯一标识、点评唯一标识等)向服务器发起注册;

  • 2)在注册成功之后业务服务端就可以通过 Pike 1.0 服务端 SDK 提供的接口,主动向设备的 App 推送消息;

  • 3)服务端推送的消息通过长连接通道抵达客户端,最后通过注册的回调接口投递给业务方。

整体工作流程参见下图:

3.3 v1.0 的优势

Pike 1.0 底层传输基于 Shark 长连通道。

所以 Pike 1.0 在以下几个方面有不错的表现:

  • 1)防劫持:底层通道直接使用 IP 直连,省去 DNS 解析耗时的同时也避免了被 DNS 劫持的风险;

  • 2)低延时:Shark 长连接采用就近接入点长连接的方式,省去了传统 HTTP 需要多次建连、握手的消耗,端到端数据传输延时相比 HTTP 大幅缩短;

  • 3)安全高:Shark 采用自定义二进制协议进行数据传输,进行了通道级别的 TLS 加密,防篡改,更安全;

  • 4)体验好:Pike 1.0 与 Shark 共享服务集群,Shark 长连通道在海外多地都部署了接入点,代理加速接入,网络延时及成功率表现要优于常规请求。

PS:移动网络下 HTTP、DNS 的优化文章,可以看看下面这几篇:

  1. 全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

  2. 美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

  3. 百度APP移动端网络深度优化实践分享(一):DNS优化篇

3.4 v1.0 的技术痛点

Pike 1.0 作为 Shark 的衍生产品固然有其闪光的地方,但是对 Shark 的强依赖所带来的痛点更是让开发人员叫苦不迭,主要痛点如下。

3.4.1)代码结构耦合:

在客户端 SDK 方面,Pike 1.0 代码与 Shark 代码结构耦合,共用底层通道建连、数据加解密、二进制协议等逻辑。

Pike 1.0 与 Shark 代码结构示意图:

耦合带来的弊端一:代码优化升级困难。针对一个 SDK 的变更经常需要更多地考虑对另一个 SDK 是否有负面影响,是否影响面可控,这就无端地增加了开发成本。

耦合带来的弊端二:Shark 与 Pike 1.0 的网络配置环境共用,如上图所示,通过 DebugPanel 对 SharkTunnel 进行网络环境配置都会同时对 Shark 和 Pike 1.0 生效,但是业务方在使用的时候往往只关注其中的一个 SDK,不同 SDK 之间的相互影响引入了很多客服问题,也给客服问题的排查带来了较多干扰因素。

3.4.2)账号体系混乱:

Pike 1.0 在同一个 App 上只支持一种设备唯一标识 UnionID,不同 App 上注册使用的 UnionID 会有不同,例如美团使用美团唯一标识,点评则使用点评唯一标识。

假如一个业务只在一个 App 上使用的话 Pike 1.0 自然可以很好地工作,但是同一个业务有可能需要在多个 App 上同时使用(如下图所示),如果业务方不对账号体系进行兼容的话,美团 App 上使用点评唯一标识作为推送标识的业务将无法工作,点评 App 上使用美团唯一标识作为推送标识的的业务也会无法工作。

这就导致同一个业务在不同 App 上的推送标识 ID 逻辑会非常复杂,后端要同时维护多套账号体系之间的映射,才能解决账号体系混乱的问题。

Pike 1.0 账号体系不兼容示意图:

3.4.3)推送连接不稳定:

Pike 1.0 由于共用 Shark 的通道逻辑而缺乏推送场景专项优化,在检测通道异常、断连恢复等方面表现不够优秀。在通道可用性上,Shark 与 Pike 1.0 关注的 SLA 也有着很大的不同。

例如:Shark 在长连接通道不可用的情况下,可以通过降级短连接来规避业务网络请求持续失败所带来的成功率下降问题。但是对于 Pike 1.0 此时如果通道不能快速恢复的话就会造成业务消息投送失败,将直接影响消息投递成功率。所以 Shark 通道针对连接保活的公共逻辑并不能完美地应用在 Pike 1.0 业务场景上。

虽然 Pike 1.0 在 Shark 通道的基础上进一步在协议层强化了心跳探测机制以提高通道可用性,但通道不能及时检测异常还是时有发生。

此外:Pike 1.0 内部使用的事件分发技术的可靠性还暂时没能达到 100%,零星地会上报一些异常断连而导致推送不成功的客服问题。

综上:针对推送连接不稳定专项优化的诉求也就不断被提上日程。

3.5 v2.0 的诞生

Pike 1.0 现有的技术痛点在业务场景日益丰富的现状下遭遇了诸多挑战。

为求解决 Pike 1.0 现有在 Android 和 iOS 平台运营上遇到的问题:

  • 1)我们重新梳理产品架构与代码实现;

  • 2)与基础技术部另一个服务于 H5 的消息投递服务 Pike Web 进行产品融合。

进而推出全新的升级产品——Pike 2.0。

下图展示了 Pike 2.0 的产品全景。针对 Pike 1.0 的现状,Pike 2.0 前后端都做了诸多优化,包括技术架构升级、集群独立、协议扩展等。

其中在客户端方面 Pike 2.0 提供了基于多语言实现服务于多平台的 SDK,在服务端方面 Pike 使用部署 Java 应用的分布式集群来提供服务。

Pike 2.0 产品全景图:

以下内容将主要从客户端视角,详细阐述 Pike 2.0 客户端 SDK 的技术方案设计,从原理上说明 Pike 2.0 带来的技术优势。

4、v2.0 架构设计

针对上文提及的 Pike 1.0 代码结构耦合的技术痛点,Pike 2.0 进行了全新的架构升级,在代码结构、环境配置、服务集群等方面上都与 Shark 保持产品隔离。

4.1 设计思想

经过接近一年的技术积累与沉淀,从 Shark 提炼的 TunnelKit 长连内核组件和 TNTunnel 通用通道组件已经趋于稳定,所以 Pike 2.0 选择基于 TunnelKit 与 TNTunnel 来构建双向消息通道服务。

具体优势有:

  • 1)Pike 2.0 基于 TunnelKit 长连内核构建,能有效地复用现有长连接控制相关的功能,减少不必要的开发工作;

  • 2)Pike 2.0 能够共享 TNTunnel 的相关通用特性,如 Shark 协议封装、数据加解密等,后期维护成本较小;

  • 3)Pike 2.0 协议作为 Shark 协议的 Payload 传输,可以灵活定制自己特性相关的协议。

4.2 整体架构

客户端架构演进图:

整体架构如上图所示,包括:

  • 1)Pike 接口层;

  • 2)Pike 通道层;

  • 3)TNTunnel 通道层;

  • 4)TunnelKit 长连内核层。

4.2.1)接口层:

Pike 接口层旨在为主流前端技术栈中所有需要应用内消息服务的业务提供简洁可靠的接口。

主要是:

  • 1)Pike 2.0 提供了 Android、iOS、MRN 等公司主流技术栈的接入 SDK,业务可以根据自己的需求灵活选择;

  • 2)Pike 2.0 针对不同的消息 QPS,设计了两种不同 Client(详见下方);

  • 3)Pike 2.0 针对线上 Pike 1.0 系统提供了业务无感的迁移方案,业务方无需任何人力投入便可以从之前的 Pike 1.0 系统迁移至 Pike 2.0 系统来进行消息的收发。

针对第 2)点,我们是这样设计的:

  • 1)对于消息量超过 50 条每秒的业务,例如直播弹幕推送,我们推荐接入聚合消息 Client;

  • 2)对于消息量较小的其他业务,普通消息 Client 则可以满足需求。

4.2.2)通道层:

Pike 通道层是特性的实现层,所有 Pike 接口层的 API 调用都会通过线程调度转变成封装的 Task 在 Pike 通道层完成具体的操作,Pike 通道层是单线程模型,最大程度规避掉了线程安全问题。

Pike 特性如下:

  • 1)断线重连:鉴于长连接的不稳定特征,Pike 2.0 通道通过断线重连机制来使的业务方可以认为在网络没有发生故障的情况下是持续可用的;

  • 2)业务鉴权:业务后端可以通过 Pike 2.0 通道对连接的监控来感知连接变更,同时对接入网络的客户端设备进行可用性判别;

  • 3)别名机制:针对不同业务方对业务标识做了隔离,每个业务可以自定义标识 ID,解决了 Pike 1.0 同一个 App 平台不同业务必须强制使用相同标识 ID 的痛点;

  • 4)上/下行消息:Pike 2.0 是双向通道服务,不仅支持 Pike 1.0 原有的消息推送能力,即服务端向客户端发送下行消息;同时也支持客户端主动发送消息,即客户端向服务端发送上行消息。业务只要通过 Pike 2.0 系统便可以形成消息的闭环;

  • 5)分组/聚合消息:Pike 2.0 支持消息分组和消息聚合来满足高 QPS 业务场景的使用。其中消息分组表示业务可以通过自定义标签来对一组用户进行消息广播;消息聚合表示将短时间内井喷式的消息进行聚合下发以提高系统的吞吐量;

  • 6)消息保序:Pike 2.0 支持同一客户端发送的上行消息有序投递到固定的业务服务器;

  • 7)独立通道:Pike 2.0 默认所有业务是使用一条共享的通道,针对业务量大或者对吞吐量有要求的业务可以自动切换独享的通道来保证消息的投递成功率和时延;

  • 8)通道保活:Pike 2.0 在连接保活的基础上增加了通道巡检,能够在检测到异常的情况下自动重启通道,确保在要求长稳的环境下进一步提升通道可用性。

4.2.3)TNTunnel 通道层:

TNTunnel 通道层是封装通用通道逻辑的功能层,主要涉及通道状态管理、协议封装、数据加解密等通用核心模块,是将通用通道逻辑从原先 Shark 通道中提炼而成的独立分层。

Pike 协议虽然是构建在现有 Shark 协议之上的应用层协议,但是 Pike 通道已经和原先的 Shark 通道在逻辑上完全解耦。

  • 一方面,Pike 2.0 会最大限度地复用 Shark 协议已成熟的技术,但是又不依赖于原有的 Shark 逻辑;

  • 另一面,后续涉及二进制协议、安全协议等协议方面的升级优化都可以同时服务于 Pike 2.0。

4.2.4)TunnelKit 长连内核层:

TunnelKit 长连内核层主要功能是对接 Socket 来处理 TCP 或者 UDP 数据的发送与接收,管理各个连接的可用性等。

每条 Pike 2.0 通道在 TunnelKit 中都是维护一条连接的,通过心跳保活机制和连接管理来保证在网络环境正常的情况下永远有一条连接来承载 Pike 数据。

TunnelKit 作为所有通道层的基础,是决定上层长连接通道稳定性最重要的一层。

5、v2.0 工作机制

在进行了全新推送架构升级的基础上,Pike 针对上文提及的 Pike 1.0 账号体系混乱、推送连接不稳定的痛点重新设计并完善了工作机制。

其中,PikeClient 作为 Pike 系统对接业务方的门户,在整个 Pike 2.0 系统中起着至关重要的作用,本节将以 PikeClient 为切入点介绍其工作机制。

5.1 PikeClient 生命周期

为了更好地维护 Pike 2.0 内部状态,PikeClient 使用状态机来负责生命周期管理。

PikeClient 生命周期图:

如上图所示,PikeClient 生命周期主要包括如下几个部分:

  • 1)onStart:该状态是业务方调用 StartClient 或者 RestartClient 之后进入的状态,此时 PikeClient 已经正常启动,之后 Pike 2.0 内部会发起业务鉴权并根据鉴权结果流转到其他的状态,如图所示如果业务鉴权失败则进入 onStop 状态,如果业务鉴权成功则进入 running 状态;

  • 2)onStop:该状态是业务方调用 StopClient 或者业务鉴权失败之后进入的状态,此时 PikeClient 已经停止工作,客户端进入该状态之后需要 Restart 才能重新使用;

  • 3)running:该状态是 PikeClient 长稳工作的状态,此时 Pike 2.0 等待响应服务推送的下行消息或者随时准备发送上行消息。作为双向消息通道,Pike 2.0 处理上下行消息的能力是完全并行的;

  • 4)onReceive: 该状态是 PikeClient 成功接收到下行消息之后进入的状态,Pike 2.0 将接收到的消息投递给业务方之后重新进入 running 状态等待下一次操作;

  • 5)onSendSuccess/onSendFailure:该状态是 PikeClient 发送上行消息之后进入的状态,业务方可以通过监听该状态来获取本次消息发送的结果。

通过基于状态机的生命周期管理,既严格定义了 PikeClient 的工作流程,也可以准确监控其内部状态,提高了 PikeClient 的可维护性。

5.2 PikeClient 工作模式

针对 Pike 1.0 混乱的账号体系痛点,Pike 2.0 设计了全新的工作模式。

如下图所示,Pike 通过通道代理模块提供共享通道和独立通道两种模式来满足不通业务场景的需求。

5.2.1)共享通道模式:

共享通道模式是 Pike 2.0 基本的工作模式,新增的业务方在默认情况下都会使用该模式接入 Pike 2.0。

在 Pike 2.0 中 PikeClient 与 Pike 通道服务是多对一的共享关系,每个业务方都会有自己的 PikeClient,每个 PikeClient 都可以自定义消息推送标识 ID 而避免使用全局标识 ID。业务后端可以精简推送标识逻辑,避免同时维护多套账号体系。

不同业务的 PikeClient 仅在接入层面做了业务隔离,在 Pike 2.0 通道中会由 Pike 通道服务完成统一的管理。这种多对一的共享关系使得所有 Pike 业务共享 Pike 2.0 通道特性,同时又可以针对每个业务的使用场景设置其特定的消息处理能力,每个接入 Pike 2.0 的业务方都只需要关注其自己的 PikeClient 即可。

5.2.2)独立通道模式:

独立通道模式是共享通道模式的拓展能力,Pike 2.0 通过配置控制来决策是否切换至该模式。

Pike 2.0 默认情况下所有业务方都是共享同一个 Pike 通道服务,然而鉴于业务场景的不同,每个业务对于消息吞吐量,消息时延等 SLA 指标的诉求也有差异,例如游戏业务对于消息时延过长的容忍性就比较差。针对特殊业务 Pike 2.0 提供了独立通道切换的能力支持。

所有 PikeClient 都通过 Pike 通道代理模块来对接 Pike 通道服务,Pike 通道代理模块可以通过开关配置来控制 PikeClient 与特定的 Pike 通道服务协同工作。通过运用代理模式,既保证了原有结构的完整性,在不需要调整 Pike 通道代码逻辑的基础上就能够完成独立通道能力支持;又可以扩展通道切换能力,有效地管理通道切换的流程,让 Pike 2.0 通道最大化提供业务能力的同时避免资源浪费。

5.3 PikeClient 保活机制

PikeClient 的保活完全依赖 Pike 2.0 通道的保活,针对 Pike 1.0 推送连接不稳定的痛点,Pike 2.0 通道在吸收 Pike 1.0 在保活机制方面沉淀的技术的基础上继续优化,最后设计出基于心跳探测、重连机制和通道巡检的三重保活机制。

保活机制如下图:

5.3.1)心跳探测:

心跳探测是一种检查网络连接状态的常见手段,Pike 长连接是 TCP 连接,而 TCP 是虚拟连接:如果实际物理链路中出现诸如异常网络节点等因素导致连接出现异常,客户端和服务端并不能及时感应到连接异常,这时就会出现连接的状态处于 ESTABLISHED 状态,但连接可能已死的现象,心跳探测就是为了解决这种网络异常的技术方案。

PS:关于 tcp 协议为什么还需要心跳保活,可以详读这篇《为何基于TCP协议的移动端IM仍然需要心跳保活机制?》。

客户端在心跳巡检计时器设置的心跳周期到达时判断是否存在上次心跳超时的异常,如果心跳超时则认为该连接已经不可用了,则会从连接池移除该连接并触发下文的重连机制。

为了更快地发现通道异常,Pike 2.0 对于心跳周期与心跳超时都是可配置的,针对不同 App 使用的场景可以灵活地设置。

而且在每次发送上行数据的时候都会及时检测上次心跳是否超时,使得心跳探测结果不必等到下次心跳周期到达的时刻才知悉。

Pike 2.0 并不是采用固定心跳频率来发送心跳包,Pike 2.0 会利用通道的上下行数据包来动态减少心跳包的发送次数。

此外,智能心跳也是 Pike 2.0 持续关注的话题,感兴趣的读读下面这些:

  1. 微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)

  2. 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)

  3. 移动端IM实践:实现Android版微信的智能心跳机制

  4. 移动端IM实践:WhatsApp、Line、微信的心跳策略分析

  5. 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

  6. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

  7. 正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)

  8. 一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

5.3.2)重连机制:

重连机制是 Pike 2.0 作为长连接通道最核心的特性,也是 Pike 2.0 连接稳定性建设最重要的一环。

客户端会在发送消息、接收消息和心跳探测三个环节来决策是否需要触发重连:

  • 1)一方面,如果主动发现连接池中可用连接不足则自动启动重连机制;

  • 2)另一面,当现有可用连接关闭时也会自动触发重连机制。

Pike 2.0 在重连的过程中会采用斐波那契数列退避算法来发起建连请求直至建连成功:

  • 1)一方面,Pike 2.0 保证只要在网络可用的情况下总能够维持可用的长连接来服务于业务消息;

  • 2)另方面,Pike 2.0 在网络持续不可用的情况下避免连续建连使得系统满载。

有关断线重连这方面的文章,可以系统的读一读下面这些:

  1. Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

  2. 正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)

  3. 手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

PS:如果需要实践性的代码,也可读一下开源工程 MobileIMSDK ,它对于 im 的心跳和重连机制有完整的逻辑实现,可以借鉴参考。

5.3.3)通道巡检:

通道巡检是在心跳探测和重连机制的基础上进一步提升 Pike 2.0 稳定性的有效机制。

客户端会根据心跳周期设置一个全局的巡检定时器,在每次定时器设置的时刻到达时,客户端会触发通道异常检测逻辑,一旦发现异常都会尝试重启通道。

Pike 2.0 首先会在触发通道异常检测的时候获取当前通道状态,如果通道当前没有主动关闭但是通道处于不可用的状态,Pike 2.0 会强制执行一次自启动。

此外,在通道巡检的过程中,巡检管理器会不断收集消息收发过程中出现的超时异常,当超时异常次数连续累计超过配置的最大阈值时,Pike 2.0 会认为当前通道可用性较低,需要强制关闭并执行一次自启动。

6、v2.0 新增的技术特性

Pike 2.0 作为 Pike 1.0 的升级版,不只是为了解决 Pike 1.0 的技术痛点,通过新增特性以开拓新的应用场景也是 Pike 2.0 关注的点。

6.1 聚合消息

随着公司内直播业务的兴起,公司内部也有很多业务方使用 Pike 1.0 作为弹幕、评论、直播间控制信令等下行实时消息的传输通道。

但 Pike 1.0 基于早先的设计架构为弹幕、评论这种短时间需要处理海量消息的场景提供可靠服务的能力渐渐力不从心。

主要表现在 QPS 大幅增长时,消息投递成功率降低、延时增加和系统性能开销增长等方面。Pike 通过引入聚合消息为直播场景中消息的投递提出更加通用的解决方案。

6.1.1)设计思想:

直播场景中涉及的消息主要具备以下特点:

  • 1)弹幕作为一种实时互动的载体,短时间内需处理大量的图片、文本等信息,如果不做聚合会浪费大量的带宽;

  • 2)直播间相比普通推送场景,由于用户已经进入直播间,用户行为也相对统一可控,所以更需要一种群组消息来统一处理;

  • 3)直播间对于不同类型的消息处理逻辑可以区分优先级,比如抽奖、控制信令是要求可靠性不能丢弃,而对于弹幕则可根据直播间热度、服务承受能力适当丢弃。

聚合消息在设计上主要采用下述思想:

  • 1)从时间维度对消息进行聚合,减少不必要的带宽消耗;

  • 2)采用消息分级策略,根据消息的类型设定不同的优先级,保证重要消息的可靠性;

  • 3)抽象出类似直播间的聚合单元,统一管理加入聚合单元的用户行为;

  • 4)采用客户端主动拉取的策略;

  • 5)提供上行消息能力,提供更完整的消息流通路径。

针对第 4)点:相比传统的服务端推送策略,主动拉取是利用客户端天然分布式的特点将用户状态保存在客户端,服务端通过减少状态维护进而可以留出更多的资源用于业务处理。

6.1.2)方案流程:

Pike 2.0 针对每个聚合单元都使用环形队列来维护消息列表,发送到该聚合单元的消息在经过优先级过滤之后都会插入队列 tail 指针标示的位置,随着该聚合单元内消息不断增加最后达到最大队列长度时,head 指针会不断移动来给 tail 指针腾出位置。聚合单元通过控制最大长度的环形队列来避免消息短时间井喷式增长带来的服务性能问题。

客户端在主动拉取的时候都会携带上一次获取到的消息处在环形队列中的偏移量,这样服务就会将偏移量标示的位置到 tail 指针标示的位置之间的消息进行聚合作为本次拉取的结果一次性返回给客户端。不同客户端各自维护自己的偏移量,以此来避免服务端对于客户端的状态维护。

客户端与服务端的具体交互如下图所示:客户端在加入聚合单元之后主动拉取,如果本次拉取携带的偏移量能够从服务的环形队列中获取到聚合消息,那么就将消息回调给业务之后马上进行下一次拉取操作。如果本次携带的偏移量已经位于环形队列 tail 指针的位置,那么服务端将不做任何响应,客户端等待本次拉取超时之后开始下一次拉取操作,重复该流程直至客户端离开该聚合单元。与此同时,业务服务端如果有消息需要推送,则通过 RPC 的方式发送给 Pike 服务端,消息处理模块将执行消息分级策略过滤之后的有效消息插入环形队列。

聚合消息交互流程图:

6.2 消息保序

Pike 1.0 在设计之初就只适用于消息推送的场景,而 Pike 2.0 在其基础上演进为双向消息投递服务,即不仅支持下行的消息推送,还支持上行的消息投递。Pike 2.0 在上行的消息投递方面进一步拓展了消息保序的功能。

这里的消息保序主要包含两个层面的含义:

  • 1)首先每一个业务客户端发送的消息都最大程度地到达同一个业务服务器;

  • 2)其次这些消息是按照客户端发送的时序一致地到达该业务服务器。

6.2.1)粘性会话:

为了使每一个业务客户端发送的消息都最大程度地到达同一个业务服务器,Pike 2.0 引入了粘性会话的概念。

粘性会话指的是:同一客户端连接上的消息固定转发至某一特定的业务方机器处理,客户端断连重连后,保持新连接上的消息仍转发至该业务机器。

粘性会话可以归纳为如下的流程:

  • 1)首次业务登录的时候 Pike 2.0 服务器会利用负载均衡算法选择一台业务服务器,并将该业务服务器的路由标识通过业务登录结果通知客户端并保存,之后如果通道状态稳定的话所有的上行消息就都会投递到该业务服务器;

  • 2)如果期间通道状态波动出现断连的情况,Pike 2.0 在发起重连之后会重新进行业务登录,这一次业务登录会将之前保存的路由标识重新上报给 Pike 2.0 服务器,这样 Pike 2.0 服务器就会通过路由标识重新绑定该业务服务器;

  • 3)如果路由标识指示的业务服务器已经停止提供服务,那么 Pike 2.0 服务器会重新通过负载均衡算法选择新的一台业务服务器,同时客户端会获取到新的路由标识,之后的逻辑重复该过程直至 Pike 2.0 客户端退出。

6.2.2)时序一致性:

我们都知道 TCP 是有序的,那么在同一个 TCP 连接的前提下什么情况会出现客户端发送的消息乱序到达业务服务器呢?

原因就是:Pike 2.0 服务器从 TCP 中读出消息之后将其投递给业务服务器是通过 RPC 异步调用的。

为了解决这种问题:最简单的方案当然是客户端将消息队列的发送窗口限定为 1,每一条发送消息都在 Pike 2.0 服务器投递给业务服务器之后才能收到 ACK,这时再发送下一条消息。但是考虑到网络传输在链路上的时延远远大于端上处理的时延,所以该方案的 QPS 被网络传输设了瓶颈,假设一个 RTT 是 200ms,那么该方案理论也只能达到 5 的 QPS。

Pike 2.0 为了提高上行消息保序投递的 QPS,采用服务端设置消息队列缓存的方案。

如下图所示:客户端可以在发送窗口允许的范围内一次性将多条消息发送出去,服务端把收到的消息都按顺序缓存在消息队列中,然后串行的通过 RPC 调用将这些缓存的消息依序投递给业务服务器。

这种保序方案将 QPS 性能的瓶颈点从之前网络传输在链路上的时延转移到了 RPC 调用的时延上,而实际场景中一次 RPC 调用往往在几个毫秒之间,远远小于网络传输在链路上的时延,继而显著地提升了 QPS。

消息时序一致性问题,在实时通信领域是个很热门的技术点:

  1. 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

  2. 如何保证IM实时消息的“时序性”与“一致性”?

  3. 一个低成本确保IM消息时序的方法探讨

  4. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

7、v2.0 的稳定性保障

7.1 监控体系

Pike 2.0 依赖美团监控平台 Raptor 完成监控体系建设,服务端和客户端都建设了各自完善的指标监控。

Pike 2.0 客户端通过利用 Raptor 的端到端指标能力和自定义指标能力输出了超过 10+个监控指标来实时监控 Pike 系统,这些指标覆盖通道建立、消息投递、业务登录、系统异常等多维度。

在实时指标监控的基础上 Pike 2.0 针对不同指标配置了报警阈值,以推送消息为例,如果特定 App 的大盘数据在每分钟的上下波动幅度超过 10%,那么 Raptor 系统就会向 Pike 项目组成员推送告警信息。

基于所有 Raptor 监控指标,Pike 2.0 提炼核心 SLA 指标如下:

Pike 2.0 会定期输出基于核心 SLA 指标的大盘数据报表,同时可以基于 App、业务类型、网络类型等多维度对数据进行筛选以满足不同用户对于指标数据的需求。

7.2 个案用户追踪

监控体系能从全局的角度反映推送系统稳定性,针对个案用户,Pike 管理平台提供完整的链路追踪信息。

每个 Pike 2.0 连接都由唯一标识 Token 来区分,通过该唯一标识 Token 在 Pike 管理平台的“连接嗅探”模块主动探测便能获得对应连接上所有信令的交互流程。

如下图所示:流程中明确标注了客户端建立连接、发起鉴权、绑定别名等信令,点击对应信令可以跳转信令详情进一步查看该信令所携带的信息,再结合 SDK 埋点在美团日志服务 Logan 的离线日志就可以快速发现并定位问题。

8、建设成果

截至 2021 年 6 月,Pike 共接入业务 200+个,日均消息总量约 50 亿+,Pike 2.0 消息到达率 >99.5%(相比 Pike 1.0 提升 0.4%),Pike 2.0 平均端到端延时<220ms(相比 Pike 1.0 减少约 37%)。

部分应用案例:

  • 1)直播场景消息服务方案:支持直播业务的直播互动功能,具备了支持同时在线百万级别大型直播的能力;

  • 2)消息推送、Feed 流预加载等实时触达方案:支持营销类、控制类等业务消息实时推送,业务消息到达率最高提升 10%,长连通道建联耗时减少 5%;

  • 3)IoT 设备接入方案:支持取餐柜业务 IoT 接入能力,帮助业务消息到达率从 98.4%提升到 99.6%;

  • 4)小游戏场景消息投递方案:支持美团小游戏场景通信能力,消息到达率达到 99.8%以上,上行延时低至 195ms。

9、未来展望

Pike 实时消息推送服务在美团应用广泛,目前主要集中在实时触达、互动直播、移动同步等业务场景。随着公司业务的快速发展,Pike 对可用性、易用性、可扩展性提出了更高要求,希望提升各种业务场景下的网络体验。

因此未来 Pike 的规划重点主要是:提供多端、多场景下的网络通信方案,不断完善协议生态,在各种应用场景下对抗复杂网络。

具体就是:

  • 1)拓展通用基础能力:提升通道性能。通过优化保序方案,提供专用通道,优化传输协议等方式,进一步提升吞吐量和稳定性,降低推送时延;

  • 2)建设物联网的接入:提供 IoT 接入层方案。为公司内物联网应用场景(单车、充电宝、取餐柜、智能头盔、仓库、门店设备等)提供统一的 IoT 接入层解决方案,支持多种接入协议(HTTP、MQTT、CoAP 等),为业务提供安全可靠的设备连接通信能力;

  • 3)优化弱网通信体验:在移动端和 IoT 端基于美团自研 MQUIC 网络协议库,探索 Pike over QUIC,在桌面端探索 WebTransport 技术,通过全面支持 QUIC 协议,提升弱网大包场景下的网络性能,降低长尾分布的请求耗时。

附录:更多实时消息推送技术文章

  1. iOS的推送服务APNs详解:设计思路、技术原理及缺陷等

  2. 信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑

  3. Android端消息推送总结:实现原理、心跳保活、遇到的问题等

  4. 扫盲贴:认识MQTT通信协议

  5. 一个基于MQTT通信协议的完整Android推送Demo

  6. IBM技术经理访谈:MQTT协议的制定历程、发展现状等

  7. 求教android消息推送:GCM、XMPP、MQTT三种方案的优劣

  8. 移动端实时消息推送技术浅析

  9. 扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别

  10. 绝对干货:基于Netty实现海量接入的推送服务技术要点

  11. 移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

  12. 为何微信、QQ这样的IM工具不使用GCM服务推送消息?

  13. 极光推送系统大规模高并发架构的技术实践分享

  14. 从HTTP到MQTT:一个基于位置服务的APP数据通信实践概述

  15. 魅族2500万长连接的实时消息推送架构的技术实践分享

  16. 专访魅族架构师:海量长连接的实时消息推送系统的心得体会

  17. 深入的聊聊Android消息推送这件小事

  18. 基于WebSocket实现Hybrid移动应用的消息推送实践(含代码示例)

  19. 一个基于长连接的安全可扩展的订阅/推送服务实现思路

  20. 实践分享:如何构建一套高可用的移动端消息推送系统?

  21. Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

  22. 腾讯信鸽技术分享:百亿级实时消息推送的实战经验

  23. 百万在线的美拍直播弹幕系统的实时推送技术实践之路

  24. 京东京麦商家开放平台的消息推送架构演进之路

  25. 了解iOS消息推送一文就够:史上最全iOS Push技术详解

  26. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

  27. 解密“达达-京东到家”的订单即时派发技术原理和实践

  28. 技术干货:从零开始,教你设计一个百万级的消息推送系统

  29. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

  30. 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

  31. 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

  32. 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

  33. 消息推送技术干货:美团实时消息推送服务的技术演进之路

  34. >> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3662-1-1.html

用户头像

JackJiang

关注

还未添加个人签名 2019.08.26 加入

开源IM框架MobileIMSDK、BeautyEye的作者。

评论

发布
暂无评论
消息推送技术干货:美团实时消息推送服务的技术演进之路