做者简介java
锦洋,负责饿了么蜂鸟APP的架构、研发等工做。目前关注的技术方向为移动端监控、移动端架构、移动端性能优化等方向。git
在这个重视稳定性的年代,不少公司在移动端性能监控上花了很大的力气,对业务可用性监控的投入不足,可是移动端可用是由性能可用和业务可用共同组成,缺一不可,由于业 界性能监控已经比较成熟,有不少第三方的平台,因此避开性能监控不谈,下面介绍一下饿了么物流移动端在业务可用性监控体系建设上的一些探索。github
饿了么物流移动端做为骑手直接使用的配送工具,须要天天承载千万量级的配送单量,骑手app具有如下三个特色:时效要求高,网络环境复杂,重度使用。骑手须要在30分钟内将订单配送到用户手中,中间实施屡次订单操做,可谓争分夺秒,若是遇到网络或者定位异常均可能致使有损操做,为了保证骑手的操做顺畅,咱们须要将骑手整个配送过程归入可用性监控体系建设中,通过长期的探索,咱们创建一套本身的移动端业务监控体系。数据库
整个监控体系就像一个数据漏斗:后端
第一层 E-Monitor:全局业务监控,纵观全局,掌握业务大盘趋势;api
第二层 TimeBomb:异常事件监控,定点插针,实时报警;安全
第三层 Dogger:单点日志监控,全量日志,还原现场;性能优化
第四层 EDW:离线大数据,T+1报表,大数据分析业务健康度;bash
下面给你们详细介绍一下这四层监控网络
你们都知道做为移动端自己不须要对接口监控敏感,由于后端有各类维度的API服务监控,可是App做为上层应用,接口的成功失败,并不能彻底替代用户的感知,这是有调用方的特征决定的。一次业务请求包含:准备请求数据->发送请求->网络链路->请求回调->解析->渲染,任何一个环节的失败均可能表明着用户的一次交互失败,因此要想彻底掌控线上大盘的核心功能使用曲线,彻底依赖后端接口监控是不行的,必需要梳理调用链路,搭建客户端业务监控。
做为全局业务监控只看单个用户的数据是没有什么意义的,须要将全部用户的数据采集,存储,可视化。这里数据的采集咱们使用饿了么MT部门提供的Skynet做为采集和上传通道,它具有编译期AOP插入,序列化存储,针对移动端优化的对齐上传等特性,保证了数据采集上传的可靠,稳定。
而在服务端的存储和可视化咱们采用LinDB+E-Monitor的监控架构,LinDB是一款优秀的时间序列数据库,适合存储设备性能、日志等带时间戳的数据。能轻松处理高写入和高查询负载。配合E-Monitor强大的可视化能力,能够完美展示骑手订单操做主流程的稳定状况,异常报警。
报警的策略有如下几种:移动端经常使用的是阈值模型和趋势模型配合同环比
最终生成一个大盘的监控面板,这里由于铭感数据只放出了部分脱敏面板
TimeBomb-定时炸弹,从名字就能够猜到它和异常有关,它专门负责监控在规定时间和次数限定下没有达成用户交互结果的逻辑,TimeBomb做为全局业务监控的补充,在排查异常中立下汗马功劳。它的设计初衷是经过简单的代码插入,由计数,时间间隔等条件触发异常事件上传, 适用于:
登陆屡次登陆不上
屡次点击确认送达,都失败
定位一直报错
定位上传屡次失败
任何接⼝口屡次报错
等等...
总结来讲,TimeBomb能够随意定义异常的监控力度,而且能够灵活的远端配置次数,时间,采样率。
TimeBomb的数据采集和展现是经过咱们自研的服务,主要包括两个功能:
骑手App经过TimeBomb完成了不少异常问题的上报,修复,观测,优化,再观测,这是一个异常问题解决的正向循环,并且特别适合一些须要多轮验证的极端case的排查观测。
Dogger包含两个部分:
Trojan日志写入上传SDK
Dogger-Service 日志解析服务
Trojan是一个面对高性能,极致体验要求下,产出的轻量级,高效率的移动端日志监控方案,它就像一只听话的狗狗,他在客户端默默的记录着用户的各项操做日志和技术性能埋点,最终在须要的时候,把日志抛上来,交给Dogger-Service解析,经过完善的埋点,咱们能够很快的还原骑手的操做现场,借助对特定日志的横向分析,能够帮咱们快速定位问题。
Trojan具有如下四个特色:
Trojan的架构图:
Trojan 用C的方式经过mmap(内存映射)的方案写入日志,对比java api的写入方式性能提升了一倍,低CPU,低内存消耗。
在性能监控这种大数据量写入的场景上知足了咱们的需求,再配合文件的gzip压缩能够将日志这种多重复字母的文件达到50倍的压缩效果,实测一个43M的文件,压缩上传只要860kb。1M之内的文件上传对移动端来讲也是一个能够接受的大小,这也对将来trojan除了完成逻辑回放,提供了可能。
通过三个版本的迭代,Trojan已经涵盖了用户的点击事件,页面生命周期,请求监控,流量,电量,内存,线程等方方面面, 文件的写入和上传都完成了,那一个几十M的文件该如何分析尼?下面就介绍一下咱们的Trojan配套解析服务Dogger-Service。
Dogger-Service 主要的功能分为三个部分:
经过ActionChart咱们能够直观的看出骑手在时空坐标系下的操做和资源使用状况,能够方便协助咱们观察某个时间点出现某个问题的环境,这种全局掌控用户操做多是行业内第一次达到。
经过对原始数据解析,咱们能够拖拽时间滑片,直接定位到某个时间段查看骑手的日志明细,也能够选择某个关注的Tag,或者直接经过关键字搜索高亮查找,Origin模块让咱们能够灵活的查找问题的蛛丝马迹,给定位问题的root cause提供了保障。
这样就够了吗?
当前实现了对电量,网络,流量,卡顿,请求,生命周期,内存,定位的数据分析。好比下面的内存分析,咱们能够经过最长间隔,知道骑手有哪些时间段app是关闭着的,内存的峰值和低谷,平均内存各是多少,内存波动比较大的时间段是哪几个,波动大表明着资源开销可能异常,是须要仔细排查的点。
能够Loc Tag查看骑手的定位轨迹,分析是否有定位漂移或者定位失败状况
还能够经过PunchLoc Tag查看定位上传的失败占比,分析失败的缘由是否和当时的网络状态有关
经过THttpReq能够查看网络请求的Host和Path占比状况,方便优化请求流量
Trojan和Dogger-Service组成了Dogger这个有机的总体,日志和解析配合,可让咱们在排查单个case的时候,对用户的行为了如指掌,丰富的埋点数据能够为咱们的排查提供数据支撑。
目前Dogger服务中的日志写入sdk Trojan已经开源,欢迎交流学习
当咱们有了实时的全局大盘和异常监控,还有单个用户的全周期日志数据,就够了吗?
大盘的曲线正常,异常的毛刺消除只能表明业务大盘稳定,可是业务功能真实的质量还不能一律而论,这时咱们须要对数据漏斗的终点---离线数据池进行大数据挖掘分析来作最后的监控兜底。
下面介绍一下最后一层监控EDW
离线报表监控做为全局大盘的另外一种视角,E-Monitor属于实时大盘监控,只能观察实时曲线趋势和昨天作对比,判断粗粒度的业务是否异常,可是离线数据能够挖掘分析完整一天的数据,细粒度的判断每个订单的健康程度,聚合定位失败的缘由占比,获取复杂条件筛选出的各类比例,让咱们从上帝视角观察整个业务线,评估线上业务健康度,分析趋势,表征产出,是移动端监控体系中不可或缺的利器。
公司大数据平台部自研的edw为咱们提供了优质的离线大数据服务,它融合了即时查询、数据抽取、数据计算、数据推送、元数据管理、数据监控等多种数据服务的平台型产品。
当前咱们在流量,定位质量,骑手多设备使用,离线送达,推送质量,订单异常等关键业务场景都有完备的离线报表。好比上图的流量报表,能够知晓线上流量消耗Top 100的骑手device_id 和流量数据,而排行第一的骑手response数据远大于request数据,经过Dogger拉日志后发现,骑手有屡次下载app的行为。第二幅图则是线上主流程的偏向业务的流转时长监控,由于数据敏感因此打码了。这些报表能够说明线上业务的真实健康度,这一点可以让咱们对全局的把控更有自信。基于离线数据的聚合分析,能够发现优化点,为改善方案提供依据。
这里记录一下最近发生的一次网络层问题的排查过程,让你们直观感觉这几层监控的做用。
第一步:咱们的gafana的监控发现Android骑手的订单相关请求平均成功率下降到了98.69%,而正常请求成功率应该在99%以上
上面说到grafana属于可用性全局监控,若是这边的数据异常,将会影响全盘,因此咱们不敢怠慢,立马着手排查。
首先咱们怀疑是DNS解析问题,咱们经过EDW拉取了出现问题骑手的id,而后配置了Dogger的骑手日志拉取,通过分析发现,DNS失败的场景多发生在断网等弱网环境,属于正常状况,并且咱们发现日志上出问题的请求的requestID在后端的trace系统上都查不到,查看了skynet网络监控拦截器的代码
apmNetInterceptor插在最后一个,数据没有传上去,说明请求在发送前就已经抛了错,因此咱们开始排查请求发送前的逻辑。 第二步:经过EDW抽取出现问题骑手,对他们的请求失败缘由聚合,获得了ioException异常占比最大
第三步:因为请求前的日志数据过少,因此咱们升级了okhttp到3.11,使用EventListener来获取请求生命周期埋点,针对上报问题的骑手发了内测版本,但愿得到出问题请求的链路明细。
完整的链路大体以下:
再次捞出有问题骑手的日志,发现有些时候网络状态是良好的,可是在 responseHeaderStart以后会直接抛错或者是 timeout:
因而咱们撸了多遍okhttp的源码,以为应该是链接池复用的问题,复用了已经失效的链接. 咱们又加入 IOException 的 stacktrace日志.发现一个奇怪的问题:
线上的请求走的居然是http/2的协议,仔细阅读Okhttp 握手相关的代码发现,Okhttp 在 https的状况下会判断服务端是否支持 http/2,若是支持则会走 http/2的协议,相关代码参见RealConnection.java的establishProtocol方法。
private void establishProtocol(ConnectionSpecSelector connectionSpecSelector,
int pingIntervalMillis, Call call, EventListener eventListener) throws IOException {
if (route.address().sslSocketFactory() == null) {
if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
socket = rawSocket;
protocol = Protocol.H2_PRIOR_KNOWLEDGE;
startHttp2(pingIntervalMillis);
return;
}
socket = rawSocket;
protocol = Protocol.HTTP_1_1;
return;
}
eventListener.secureConnectStart(call);
connectTls(connectionSpecSelector);
eventListener.secureConnectEnd(call, handshake);
if (protocol == Protocol.HTTP_2) {
startHttp2(pingIntervalMillis);
}
}
复制代码
最终发现的确是 Okhttp在 http/2上对链接池的复用问题存在 bug ,在StreamAllocation.java上
public void streamFailed(IOException e) {
boolean noNewStreams = false;
synchronized (connectionPool) {
if (e instanceof StreamResetException) {
} else if (connection != null
&& (!connection.isMultiplexed() || e instanceof ConnectionShutdownException)) {
noNewStreams = true;
}
socket = deallocate(noNewStreams, false, true);
}
}
复制代码
当协议是http/2的时候,noNewStreams为false 而在ConnectionPool.java的connectionBecameIdle就不会将这个connection从ConnectionPool中移除
boolean connectionBecameIdle(RealConnection connection) {
if (connection.noNewStreams || maxIdleConnections == 0) {
connections.remove(connection);
return true;
} else {
}
}
复制代码
结合前段时间,后端将路由层切换了公司的SoPush服务上,而SoPush是支持Http/2的,切换的时间和曲线异常时间吻合,能够肯定问题就在这里。
线上使用的Okhttp版本仍是3.8.4, 在Okhttp 3.10.0版本以后,加入了对http2的链接池中的链接作了严格的ping验证, 下面是 changelog
能够看到 http/2 才刚加Ping机制,因此OKhttp对Http/2支持有问题的版本是<3.10,可是即便使用了3.11的最新版本依旧有必定几率发生这个问题.因而咱们以为先强制指定Android版本的协议为http/1.1,后面接入集团的网络库再支持Http/2。修改完再次发布内测版本,曲线恢复正常,问题解决。
此次网络层的排查,咱们使用E-Monitor监控和分析问题严重程度,EDW离线数据过滤出问题骑手ID,Dogger单点日志灵活埋点验证修复方案,就这样一次由第三方变更引发的客户端可用性异常就这样解决了,业务可用性监控功不可没。
上面就是饿了么物流移动当前在业务可用性监控领域作出的一些探索,咱们按照数据漏斗,从全量埋点,异常监控,单用户日志,离线数据,由面到点再到面,每个切面都插入了不一样纬度的监控,但愿能作到全面覆盖业务,稳定性和质量兼顾,由于咱们深信,只有作好监控,才能作到可报警,可排查,可优化。可是移动端可用性监控是一个长期建设的工程,须要不断的优化迭代,当前咱们也面临数据冗余和性能监控冲突,监控自己带来的性能损耗等问题,将来咱们也将在这些问题上作进一步探索、实践和分享。
阅读博客还不过瘾?
欢迎你们扫二维码经过添加群助手,加入交流群,讨论和博客有关的技术问题,还能够和博主有更多互动
![]()
博客转载、线下活动及合做等问题请邮件至 shadowfly_zyl@hotmail.com 进行沟通