高品质的音视频能力是怎样的? | Qcon 全球软件开发大会·上海站邀请函 了解详情
写点什么

“延迟”指标如何作用于应用风险识别系统

  • 2020-09-10
  • 本文字数:4542 字

    阅读完需:约 15 分钟

“延迟”指标如何作用于应用风险识别系统

随着近几年好大夫在线全面转向微服务化,服务间调用复杂度急剧上升,故障难定位,技术债务难量化等相关问题随之而来,如服务稳定性没有统一衡量标准,服务容量配比是否合适等等。面对这些问题,好大夫在线基础架构部积极探索落地全链路监控系统,主要包括链路诊断、容量监控、应用运行时健康画像、实时告警及应用风险评估模型。本系列文章将从不同点切入,对好大夫在线落地全链路监控系统做一个介绍。


SRE(Site Reliability Engineering)在选择指标 SLI(Service Level Indicator)时,有四个黄金指标:延迟、流量、错误和饱和度(取自 Google SRE 的书籍)。


本期我们分析一下“延迟”指标如何作用于应用风险识别系统。


接口请求响应时间指示着应用单机峰值的 QPS/TPS(在机器硬件配置相同的情况下)。


响应越快能并发处理的用户请求也就越多,水平扩展时收益也越大,能减少获客成本和机器成本。


请求慢有很多因素,从用户角度来看,CDN 回源、css/js/html 渲染、网络抖动、微服务接口粒度过细、局域网内部请求过多、机器硬件、依赖中间件等等都会影响请求的耗时,接下来我们从微服务局域网请求角度来分析。


应用出现慢接口有哪些表现和危害

  • 用户的耐心是有限的,过慢的请求,会流失用户,将用户导向响应更快的竞品;

  • php 应用会导致 php-fpm 进程数被耗尽,单机处理能力大幅度下降,请求会被积压,从而导致 QPS/TPS 下降,从而造成大量 5xx 错误;

  • 线程、进程阻塞,应用 CPU 负载因为大量的 context 切换而飚高,导致应用响应越来越慢,甚至出现整个系统雪崩;

  • 由于大量线程/进程变慢,资源没有及时释放,导致各种连接池、中间件等连接数被耗尽,触发过载保护,造成客户端连接断开,出现错误数据或者流程中断;


什么是慢接口(高延迟)?

慢接口:直观来看就是接口慢。那接口耗时多少算慢呢?统计接口平均耗时大于某个阈值?一次响应慢就算吗?


MessageQueue 消费事件算吗?定时任务里面的方法执行慢算吗?链路入口的慢接口又是如何判定的?基于这些疑问,我们根据经验总结出慢接口的具体说明。


慢接口:当服务发起方单次 RPC 请求响应耗时大于当前应用 95%请求耗时计数累加 1,一个分析周期后,当前应用累计数排名 TOPK 的接口标记为慢接口。


名词解释:


  • 单次请求,指的是一个请求周期内的响应耗时,比如入口链路耗时时间就是处理完这次请求的总耗时,任何请求都是上游方法请求下游方法的聚合;

  • 响应耗时 = 网络传输耗时 + 应用处理耗时;

  • 每个应用职责不一样,所在链路位置也不一样,每个接口的耗时也不一样,如果取平均耗时,由于长尾效应,分析的数据会失真,根据公司现状分析,取 95%百分位的接口响应时间记为参考值;

  • 为了避免网络抖动和消除突发异常,我们采用累计数,调用量大的系统,看累加总数,调用量小的看请求占比;

  • 一个分析周期,也是为了消除抖动或者突发异常,目前我们采用一个小时为分析周期;


为什么不用平均耗时

因为通常对于延迟这个指标,我们不会直接做所有请求延迟的平均,因为整个延迟的分布也符合正态分布,所以通常会以类似 “90% 请求的延迟 <= 80ms,或者 95% 请求的延迟 <=120ms ”这样的方式来设定延迟 SLO(Service Level Objective) ,熟悉数理统计的同学应该知道,这个 90% 或 95% 我们称之为置信区间。


为什么每个应用的耗时指标设置不一样

由于每个系统目前的机器分布不均衡,调用量不相同,再加上历史遗留代码,改造成本也不一样。为了让优化收益最大化,我们目前的规则是:按应用内接口横向比较,取应用的 p95 耗时,再根据调用频率,优先改排名前 5 的接口。优化是一个持续的过程,如果所有的应用都卡一个指标去优化,对那些老系统来说,短期内很难达成目标。先优化收益高的任务,有效果了,再优化新生成的任务,形成积极的正反馈。


慢接口优化的 SLO

对延迟有一定了解之后,我们要怎么做呢,也就是说我们的目标是什么,延迟 SLO(Service Level Objective) 优化目标,根据前面的分析,我们选择为应用接口访问量大耗时大于当前应用 95%请求的接口。这样随着优化的进行,p95 在逐渐下降 等 p95 达标后,可以优化 p99,p99.9。


慢接口分析模型设计原理


a. 日志存储本地磁盘,基于 Flume 异步收集,推送到 Kafka,日志分析系统 Snow(自研)订阅 Kafka 消息进行流式处理,准实时分析;


b. 每条日志携带的信息比较丰富,日志分析系统采用 Goroutine,按照目前定义的规则(如慢接口、异常事件、慢 SQL、循环远程调用等)进行并发分析;


c. 分析后,生成风险指标 Metrics,判断系统(Dolphin,见:好大夫在线监控系统答辩的 60 分钟)周期性拉取 Metrics 存入 Prometheus,通过预设的判定规则,触发生成风险事件;


d. Task 任务追踪系统(自研)订阅风险事件,生成可追踪的任务后,下发到各个事业部的开发人员名下(直接生成对应的 JIRA 任务);


e. 测试同学管理自己部门相关的改进任务 -> 开发同学进行优化后上线 -> 测试同学线上验证后关闭;


f. 整个流程从风险评估系统发起,到风险评估系统持续追踪验证,形成闭环;


宏观架构如下:



我们如何找到慢接口?


我们将所有 RPC 请求的耗时,记录到日志(从发出请求 到 接收到请求 一个来回),辅助诊断工具“APM 链路分析”,标注风险点。


任务是如何分配的

现在的风险评估模型,分析出来的任务都统一分配给了服务调用方,即分给了上游服务,我们认为,应用负责人应该感知自己调用下游的健康状态,对影响接口的因素要做到心中有数,如果链路跨度比较大, 比如 SystemA::methodA()调用 SystemB::methodB()而 SystemB::methodB()又调用了 SystemC::methodC(),如果 SystemC::methodC() 耗时超过 100ms。这时候 SystemA,SystemB,SystemC 都会生成任务,SystemA,SystemB 负载人 推动 SystemC 负责人 去优化 SystemC::methodC()。


任务追踪系统状态流转

任务状态流转,从创建到关闭形成闭环:



任务优先级是如何划分的

每个应用面临的状态不一样,我们会优先选择收益高的慢接口生成任务,应用方再结合调用量,和修改难易程度和项目排期自己合理安排。


系统抖动产生的任务如何处理

由于网络抖动产生的临时事件,或者依赖的框架异常,中间件突发异常生成的任务,可以直接静默该任务,默认静默一个月。


如何处理(优化策略)

有些应用历史包袱比较重,调用跨度深,或者准备重构的均可以参考以下思路处理。


  • 不管是重构还是要优化,先分析链路调用关系,画出时序图,看看依赖是否合理,应该能发现一些可优化项;

  • 可以从产品层面思考一下,比如用户提交订单 在支付回调的过程中,给用户显示系统处理中页面,让同步请求转成异步请求,减少依赖;

  • 分析慢接口的源头,基于时间线分布,查看是下游慢,还是自己当前应用处理逻辑慢;

  • 判断是否依赖第三方接口,比如依赖微信,上传/下载附件等,考考是否转成异步处理;

  • 是否存在循环调用,频繁的调用下游同一个方法除了徒劳浪费带宽外没啥意义;

  • 是否存在多次依赖,这时候主要考虑是否存在接口粒度过细的情况,如果依赖下游方法过多可以考虑是否需要聚合,当然根据单一职责设计原则,不要盲目聚合;

  • 调用跨度是否过大,RPC 请求如果链路超过 100 次,假设每次请求耗时 20ms,整条链路耗时也会超过 2000ms;

  • 是否可以考虑并发请求,对于跨度大的,请求返回值不相互依赖的可以考虑并发请求;

  • 片段缓存被穿透,导致出现慢 sql;

  • 脚本或者 mq 消费者,大量并发操作中间件,导致中间件过载防护,或超载 阻塞连接或拒绝连接,考虑延迟消费,减少并发量,定时任务分片,分时段执行;

  • get 等幂等请求,是否考虑增加片段缓存;

  • 对条件查询数据库的操作,是否可以转化为查询主键;

  • 高频调用中间件,是否可以调整为批量操作,如批量发布消息,和 Redis 交互 增加 Pipline 减少网络 I/O;

  • 查看应用依赖是否合理,基础应用不应该依赖高层应用,应用间的交互可以基于契约,高层应用也不直接依赖基础应用,大家通过异步回调实现;

  • 代码组织形式是否合理,可以基于设计模式 重构代码,对接口做基准测试 对核心接口的 QPS/TPS 要做到心中有数;


优化的误区

  • 为了减少并发,直接在程序中添加延迟因子,如 sleep(n)。


慢接口模型会分析出这类接口,在优化和平时写代码的时候一定要注意,如果要延迟处理部分逻辑。可以考虑提交事务后触发 mq 异步时间,如果是缓解并发问题可以利用加锁,而不是随机增加 sleep 时间。


  • 强制分离自己的业务领域职责,将自己的依赖的下游往上层抛,让前台代码变的臃肿无法维护,并且没有解决延迟慢的问题,只是将自己的问题抛给了上游调用方。


如 controller 层调用接单服务,优化后,本来 SystemB::AddItemToFlow() 属于 SystemA::CreateOrder()的领域逻辑,拆到 Controller 后,虽然 SystemA 健康了,但整个链路耗时依然很大,并且破坏了 SystemA 的领域逻辑。



  • 盲目申请更大的缓存存储空间,由于数据冷热分布不均,缓存命中率低,扩大缓存后命中率没有显著提升,只会徒增机器成本。


比如按用户展示推荐文章列表,如果直接按入参设计片段缓存,由于 userid 不一样,会大量申请缓存,命中率没有提高,相当于每次还是直接查询数据库。


如何验证优化效果,应用变好或变坏的信号? 关注应用风险评估系统的每周周报,关注风险评级指标,关注优化后的 95 线趋势,以及优化后的任务是否被重新打开。


分析实战

为了方便大家持续跟进任务,我们开发任务跟进系统:“dany”,如下图:



按事业部划分应用归属,既可以查看每个事业部的风险趋势,也可以选择自己应用的任务列表,选择慢接口类型,可以借助 APM 链路分析,更方便的定位问题,测试也可以根据任务状态推进开发优化。接下来我们具体来分析一个:



我们选一个循环调用的方法借助 APM 诊断工具,分析一下:



APM 诊断工具,会给出分析报告,绘出上下游拓扑图,绘出整个调用树,绘出每个方法的时间线,给不健康的方法加上标签 我们可以看出 这条链路中,存在 3 处双向依赖,循环调用 15 组,调用跨度 75,总耗时 1.4s 左右。为了更好的用户体验,我们对界面做了很多支持动态配置的功能,比如筛选指定的风险点。




具体到 1.4 这条链路中,我们可以看到总耗时 147ms。


两处循环调用 1.4.1 和 1.4.2 都是调用 getByHostIdAndType 总耗时 21ms,优化建议可以合并成一次请求。


双向依赖有三处 1.4.4 -> 1.4.4.1 -> 1.4.4.2,我们可以看出层级关系,上游发起请求后,下游又回调了上游应用,这种交叉依赖,很容易形成依赖环,从而导致交叉故障,更早的到达故障临界点。优化建议,聚合接口,上游一次性把参数传给下游,剪掉双向依赖。


从时间线外面可以判断出,下游调用时间 一共消耗 85ms, 去掉下游耗时,1.4 入口耗时 62ms,也就是说,入口方法本身还存在优化空间。


其他的风险点都可以采用类似的方法进行分析,从而制定自己的优化方案。


分析步骤总结

  • 选择应用,查看任务,分析调用链;

  • 分析链路每一个请求的时序图;

  • 按风险进行过滤筛选;

  • 分析耗时时间线;

  • 找出主要可优化的点,然后去评估是否、如何去优化;


作者介绍:


方勇:好大夫在线系统开发工程师,专注于微服务、中间件的稳定性和可用性建设,整体负责好大夫风险评估系统的设计和搭建;


翟康奇:好大夫在线系统开发工程师,专注于分布式任务调度,RabbitMQ 高可用解决方案,负责全链路应用风险分析建模;


刘伟:好大夫在线系统开发工程师,主要负责统一推送平台,中间件运行时指标的监控挖掘及调优,主导 RabbitMQ 多集群管理平台建设。


2020-09-10 08:302054

评论 6 条评论

发布
用户头像
学习了
2020-10-10 10:07
回复
用户头像
挺干的。
2020-09-11 10:59
回复
用户头像
有用
2020-09-10 10:09
回复
用户头像
学到了
2020-09-10 10:06
回复
用户头像
谁写的 这么牛掰
2020-09-10 09:59
回复
好大夫在线技术团队
2020-09-10 13:25
回复
没有更多了
发现更多内容

RT-Thread记录(十三、I/O 设备模型之PIN设备)

矜辰所致

RT-Thread 8月月更 I/O设备模型

Bytebase 1.3.1 - 2022.8.18

Bytebase

SQL优化 database SQL审批

如何让工业制造拥有更强的“数字内核”?

天翼云开发者社区

天翼云TeleDB系列产品升级发布会开幕在即,精彩邀您共鉴

天翼云开发者社区

使用 Canonical MAAS 部署 openEuler 测试

openEuler

centos 开源 操作系统 openEuler MaaS

开源一夏 | MySQL 事务的隔离级别

六月的雨在InfoQ

开源 mysql事务 MySQL 数据库 8月月更

重庆邮电大学新工科训练营 实践Java和大数据方向全真产业项目

神奇视野

青软集团蝉联华为云「千万俱乐部奖」「最佳销售黑钻奖」两大奖项

神奇视野

Golang 使用过程中遇到的小技巧(一)

皮特王

2022“易观之星”年度奖项启动征集,发现卓越数智力量

易观分析

报名 数智化 易观之星

天翼云入选可信边缘计算推进计划与分布式云扬帆计划首批成员单位!

天翼云开发者社区

即刻报名|汽车制造行业如何玩转大数据分析?

Kyligence

数据分析 汽车制造

DPDK技术原理与架构

C++后台开发

虚拟化 DDoS DPDK VPP NFV

金融机构求索数据价值,“数牍方案”提供可行解 数牍科技

数牍科技

隐私计算 金融行业 数据隐私安全

关于Copy On Write Array List,你会安全使用么

华为云开发者联盟

List 开发

天翼云为这场酷炫的元宇宙会议做了这件事

天翼云开发者社区

“客户体验管理”这么热,究竟能给企业带来什么变化?

科技怪咖

企业搭建知识库的重要性,你了解多少?

Geek_da0866

实践基地+新工科实训 青软与西南大学展开多元校企合作

神奇视野

“延迟”指标如何作用于应用风险识别系统_架构_好大夫在线技术团队_InfoQ精选文章