写点什么

SRE 实战 (01) 初识 + 探索 SRE 如何推进好大夫在线技术债务改造

  • 2021 年 10 月 15 日
  • 本文字数:5396 字

    阅读完需:约 18 分钟

SRE实战(01) 初识+探索SRE如何推进好大夫在线技术债务改造

你是否正面临着产品迭代在不断提速(催进度、要 deadline)的同时,服务产线 BUG/故障也在变多、有大量用户投诉要响应,每天都要花大把时间去处理突发情况、去救火,而无法把主要精力都投入到正常项目中的糟糕的工作状态?


如何保障网站的高可用是行业内的痛点,也是工程师焦虑源头之一。大家都在积极尝试去解决这类问题,好大夫在线参考 Google SRE 思想,结合国内其他公司的经验和我们自身的特点,努力落地 SRE,并取得了一定的进展。


接下来我们带着问题一起探索 SRE:


  • 如何去衡量服务的稳定性?

  • 服务接口平均耗时 30 多 ms,为何单机 QPS 提升不上去呢?

  • 容量规划扩缩容,熔断限流,主要参考的指标是什么?

  • 频繁处理用户投诉意见建议,先于用户提前发现问题?

  • 随着时间推移服可用性逐渐下滑,产线 BUG 频出,如何监控服务可用性?

  • 技术债务是如何产生的,如何一步步让工程师陷入绝望的困境?

  • 重要不紧急的技术债务,何去何从,SRE 是如何推进技术债务改进?

  • 是否能提前识别潜在风险,提前解决,让服务保持健康?

  • ...


本系列文章,将尝试带着这些疑问,结合好大夫在线面临的实际问题,一起来探索 SRE 的落地过程,以及如何用 SRE 来转变大家的工作思路。

SRE 基础认知

SRE 职责

SRE 是一个岗位吗?是救火专员吗?需要成为全栈工程师,还是只用盯着监控面板的值班人员?

SRE 的职责主要是保障网站的可用性,是一种认知共识,有一套相关方法论,是一种系统化的思维方式。从故障预防,到故障处理,再到故障复盘,形成一个闭环。[注 1]

从图中可以看出,SRE 涵盖不同的阶段,细分的职责也不相同。涉及日志收集,分析,风险识别,熔断限流,告警,通知。同时每个部分又都是相关依赖的,涉及不同的部门和岗位。是一个整体系统,需要各个方向联动保障。我们可以提供一些抓手,让整个体系运转起来,从而保障了整体的可用性。

SRE 体系工作流

1、故障预防:

随着微服务的推进,业务模块被划分到不同的独立的服务中。链路请求越来越复杂,依赖的中间件也越来越多。这给服务治理带来了不少的挑战,同时对工程师编程能力要求也越来越高。一方面需要加强工程师面向失败编程的意识,一方面增强框架的治理能力。比如关心 RPC 请求异常的 Code 码,失败重试,允许数据中间态的存在,考虑分布式事务一致性,合理的熔断限流策略。


2、故障发现:

包括框架通用埋点日志(RPC 链路/中间件依赖),业务核心链路埋点日志(订单状态流转事件)。日志收集到 CLickhouse,通过不同的分析规则生成相应的指标,然后基于 Prometheus 触发告警,通知到相应的业务方开发。


3、故障处理:

SRE 职能成员(业务开发或系统架构组)收到告警,配合 Grafana 看板快速定位问题,部分操作可以基于治理平台完成。我们采用预先配置截图的交互方式,将常见的排查问题思路固化到看板截图上,方便后期其他 SRE 当值人员故障处理。


4、故障复盘:

及时复盘将排障经验固化到看板中,方便下次告警的时候配合看板截图快速定位问题。针对常见的处理措施,需要集成到治理平台上。

SRE 面临的挑战

如何衡量服务可用性?

第一种从时长考虑:


MTTR、MTTF、MTBF 是体现系统可靠性的重要指标 [注 2]

  • MTTF (Mean Time To Failure,平均无故障时间),指系统无故障运行的平均时间,取所有从系统开始正常运行到发生故障之间的时间段的平均值。MTTF =∑T1/ N;

  • MTTR (Mean Time To Repair,平均修复时间),指系统从发生故障到维修结束之间的时间段的平均值。MTTR =∑(T2+T3)/ N;

  • MTBF (Mean Time Between Failure,平均失效间隔),指系统两次故障发生时间之间的时间段的平均值。MTBF =∑(T2+T3+T1)/ N


很明显:MTBF= MTTF+ MTTR


衡量稳定性:AO = MTBF / (MTBF + MTTF)

第二种从服务质量来看: 请求维度:成功率 = 成功请求数 / 总请求数


这里不能统计单个请求,而是看一段时间的概率分布,比如 5xx 占比,计算一段时间的 5xx 占比达到 5%,持续 10min。这块一般用几个 9 来衡量,比如 3 个 9,4 个 9。[注 3]



设置稳定性目标一般需要考虑:成本,业务容忍度,当前业务的现状。大部分时候 4 个 9 目标比 3 个 9 目标投入成本要高很多。有些底层的服务,稳定性要求就比一般配套服务的高。比如 doctor 医生服务的稳定性就需要 99.99,它一旦有问题很可能就是波及全站的范围。由于很多历史原因,“大泥球”的服务积累的技术债务会很多。这时候针对这个服务定一个合理的指标,比定一个标准的指标要好很多。


选择稳定性目标涉及到了测量方法和判断方法的问题,包含三个要素:


  • 衡量指标,比如 5xx 比例;

  • 衡量目标,总访问量(QPM)code=200 占比小于 95%;

  • 影响时长,QPM 其实就是一个聚合指标,也就是说不能简单的计算单次。这在设置告警规则的时候尤为重要,比如持续 5 分钟,服务 sentry 报错大于 10。


这里的衡量指标就是 SLI,衡量的目标就是 SLO,如果针对服务质量的还有一个 SLA。


接下来的问题就是:如何选择合适的 SLI,设置合理的 SLO。

五大“黄金指标” 

前面也谈到了选择衡量指标的问题,服务相关的指标很多,比如 cpu 负载高了要不要关系,线程数高了要不要关心,QPS 量上涨了要不要关心等等。指标不能多,要设置的合理,比如 cpu 负载高,服务依然能提供稳定的服务,那可以认为服务依然正常。


参照 SRE,Google 运维解密和赵诚老师的课程,一般参考以下五大“黄金指标”,这些指标常用来制定扩缩容,熔断限流,服务降级的策略:


1、容量

主要有服务 QPS/QPM;核心链路 QPS/QPM;单机 QPS;服务最低存活实例数,资源利用率如 CPU 负载。


2、可用性

主要是指核心链路是否异常;每分钟服务 sentry 数;服务端 6xx/5xx/429/430(限流)占比。


3、时延

由于存在长尾效应,平均耗时不一定能反映当前的现状,一般用耗时分布的 95 线/99 线(T95/99)。


4、错误率

主要针对用户侧链路,入口网关流量,如 nginx/kong 请求 Request 的 5xx/4xx 占比。


5、人工介入次数

主要是指程序的鲁棒性;支持自动故障转移;支持幂等;支持失败重试(注意防止雪崩);减少人工干预的次数。


下面给出一些示例:

如果及时发现问题?

选择好了指标,接下来就是要采集数据提炼出想要的指标,绘制监控面板,设置告警规则,触发告警了。这部分组件近几年在快速发展,周边的生态也非常的丰富。我们也经历了从人工 -> 工具化 -> 系统化 -> 平台化进化过程。


SRE 生态及工具集


SRE 工具集主要从数据源采集,分析生成监控指标,判定这些指标阈值触发告警后,及时响应。主要包括以下 6 个部分:


1、数据采集

java 体系的性能消耗比较大,我们选择的是 Fluent-bit 和 gohangout,将收集的数据发布到 Kafka。


2、数据分析

主要有流式分析和离线分析。我们也是两者相结合的,链路分析基于我们自研的一套 TracerLog。我们会分析链路的依赖拓扑关系,找出循环调用,慢接口,慢 SQL,双向依赖等常见的风险点。


3、数据存储

监控体系用的 Prometheus,由于 Prometheus 原生不支持分布式存储,我们采用 Clickhouse 做远程存储。针对存储时间长的会采用稀疏存储模式,大量采用物化视图聚合数据。


4.监控画像

日志查询主要基于 ELK 体系,Grafana 用于分析后的指标聚合展示,慢慢也衍生出了公司的看板文化。


5.告警通知

基于 AlertManager 的 hock 模式,我们研发了电话/短信/企业微信通知,让整个处理流程移动化。


6.告警响应

为了让日常处理平台化,解放运维成本,我们推出了 PaaS 云平台,辅助开发日常运维。

SRE 的切入点:推进技术债务改造

技术债务是如何产生的? 一般技术债务可以分为三类:


  • 不良代码的积累;

  • 业务建模;

  • 业务架构设计。


不良代码积累 

这类技术债务很容易想到。随着服务的不断迭代,服务越来越复杂,需求的变更,烂代码的引入,建模的不合理,不可避免的就带来一些技术债务。技术债务增加,服务稳定性越差,越容易写出烂代码,越容易积累更多的技术债务,服务稳定性也就越来越差,从而形成了一个正反馈回路。

出现这种现象的主要原因有:


1、工程师的过度自信。认为以后会有时间解决,以完成当前项目功能为导向。然而大部分情况下,项目结束后就没有下文了,加 TODO 的地方后续也都没人过问。


2、工程师过度依赖搜索引擎。有些工程师秉承够用就行,面向“搜索引擎编程”,遇到问题先 Google,ctrl+c & ctrl+v 让编程变成了体力劳动。表面上看貌似没啥问题,但不确定性往往就隐藏在这里面。先不说这些第三方的代码质量本身就参差不齐,更可能是破坏最小依赖原则,往往只需要一个组件的某个功能,却引入了整个组件,而这个组件又依赖其他组件。更糟糕的是后续这些依赖没人记得当初是怎么引进来的,不敢去修改,又没人负责升级迭代,从而变成了不定时炸弹(祖传代码)。


3、错误的理解敏捷开发。只剩下了表面上的“快速”,需求粗糙、变更过快,疲于应付,没有安排后续重构(整理)时间。


程序上的墨菲定律:

程序的规模会一直不断地增长下去,直到解决线上问题将有限编码时间填满为止。


直到这个庞然大物不停的出问题,直到解决一个难题却引入另外一个的难题,才意识到重要的难题一直没时间去做,从而把工程师带入泥潭。


艾森豪威尔矩阵:

我有两种难题:紧急的和重要的,而紧急的难题永远是不重要的,重要的难题永远是不紧急。-- 艾森豪威尔 [注 4]

业务部门与研发人员经常犯的共同错误就是将第三优先级的事情提到第一优先级去做。换句话说,他们没有把真正紧急并且重要的功能和紧急但是不重要的功能分开。这个错误导致了重要的事被忽略了,重要的系统架构问题让位给了不重要的系统行为功能。


成效的软件研发团队会迎难而上,毫不掩饰地与所有其他的系统相关方进行平等的争吵。请记住,作为一名软件开发人员,你也是相关者之一。软件系统的可维护性需要由你来保护,这是你角色的一部分,也是你职责中不可缺少的一部分。公司雇你的很大一部分原因就是需要有人来做这件事。

业务建模 & 业务架构设计

其实更难解决的技术债务往往是来自于业务建模的不合理和业务架构设计缺陷,主要原因有:


1、未理解 SOLID 设计原则

  • SRP:单一职责原则;

  • OCP:开闭原则;

  • LSP:里氏替换原则;

  • ISP:接口隔离原则;

  • DIP:依赖反转原则。

这块就不展开了,下次有机会再讨论。


2、过早的引入不需要的设计

虽然 SOA 微服务架构是当下主流,新项目一开始就拆分成不同的服务,大家为了适应这个庞杂的服务调用流程不得不额外付出巨大人力成本。好的系统架构是支持渐进式的,沉淀出特定领域逻辑,等到合适的时候再拆分,或者随业务的发展变化还得支持聚合。对采用什么数据库,什么框架不要提前限定死,应该留有更多的余地。


3、边界划分不合理

软件架构设计本身就是一门划分边界的艺术。边界的作用是将软件分割成各种元素,以便约束边界两侧之间的依赖关系。关于边界划分可以参考[注 5]


4、依赖不合理

高层策略依赖低层组件等,这块可以采用 DIP 设计原则解决。微服务间调用依赖不合理,耦合度高。

我们的尝试:技术债务识别及优化追踪 

基于链路分析找出潜在的风险:


1、慢接口:

慢,会严重影响整个服务的吞吐量,最终反映到用户体验上,造成客户流失。这里不采用平均耗时是因为接口延迟满足长尾效应,延迟越大危害越大,所以优先优化延迟高的接口。一般采用接口的延迟百分位第 99 位(P99)来衡量。目前我们希望优化后端服务 P99<100ms,前端服务 P99<600ms。


2、异常接口:

接口错误率,实时反映服务可用性。一般用作熔断降级的指示灯。根据业务容忍度可用性可以设置成 3 个 9 或 4 个 9。


3、慢 sql:

随着业务的迭代,未经优化的 SQL 可能会产生雪崩。2019 年初,由于搜索引擎蜘蛛的抓取大分页数据导致数据库雪崩,影响全站的故障。目前我们会分析慢 SQL,收集 SQL 指纹,给出相应的优化建议。


4、稳定依赖:

依赖关系必须要指向更稳定的方向。根据最小依赖原则,能不依赖就不依赖,能少依赖就少依赖,高层策略不能依赖低层组件。当然完全没依赖那就变成孤岛了没有意义。当下微服务依然是主流, 各服务对依赖的稳定性要求也不一样,基础服务要求比前台服务高。我们可以参考一个指标: 


  1. Fan-in:入向依赖,这个指标指代了组件外部类依赖于组件内部类的数量;

  2. Fan-out:出向依赖,这个指标指代了组件内部类依赖于组件外部类的数量;

  3.  I:不稳定性,I=Fan-out/(Fan-in+Fan-out)。该指标的范围是[0,1],I=0 意味着组件是最稳定的,I=1 意味着组件是最不稳定的。[注 6]


常见的服务依赖风险点有:

  • 多次依赖,同一条链路下游服务多次调用上游服务不同的接口;

  • 循环依赖,同一条链路下游服务多次调用上游服务同一个接口;

  • 双向依赖:同一条链路两个服务互为上下游,相互耦合调用。

如果对这部分感兴趣可以查看我们之前的一篇文章: 线上系统优化秘笈(Ⅰ) -- 慢接口分析。后续,我们还会对具体如何识别和计算技术债务这块做深入探索,敬请期待。

小结

这次主要分享 SRE 基础认知,以及 SRE 如何以技术债务作为切入点尝试推进系统健康度建设。技术债务一直都是工程师背负的包袱,而这部分对工程师的要求非常高,需要具备长期抗衡意识,这部分的经验积累才是成就架构梦的原始基石,唯有坚持方能蜕变。关于这部分的经典书籍还是非常多的,《代码整洁之道》,《架构整洁之道》,《重构:改善既有代码的设计》也是工程师必备圣经。如果对 SRE 感兴趣可以阅读《SRE Google 运维解密》,《SRE 生存指南》,极客时间赵诚老师的课程《SRE 实战手册》。


参考文献:


  • [注 1] 赵诚《SRE 实战手册》第 01|SRE 迷思

  • [注 2] MTTR/MTTF/MTBF 图解

  • [注 3] 赵诚《SRE 实战手册》第 02|系统可用性

  • [注 4] 《架构整洁之道》第 2 章 艾森豪威尔矩阵

  • [注 5] 《架构整洁之道》第 17 章 划分边界

  • [注 6] 《架构整洁之道》第 14 章 稳定依赖原则


作者简介:

  • 方勇:好大夫基础架构部高级工程师,专注于 SRE、微服务、中间件的稳定性和可用性建设,整体负责好大夫服务治理云平台的设计和搭建。

2021 年 10 月 15 日 14:152363

评论 4 条评论

发布
用户头像
sre能决定开发的架构设计?
2021 年 10 月 18 日 08:29
回复
sre和运维、系统架构不能各自为战,需要整体技术架构设计来保障,如果sre只是运维团队自己搞,那基本没戏。
2021 年 10 月 25 日 10:16
回复
SRE是需要和RD和QA配合,但SRE只能提提建议,实际上还是只能在业务架构的基础上做一些小动作,对主体架构并没有什么影响力。
2021 年 10 月 29 日 17:59
回复
取决于公司对整体技术架构的设计,要么靠技术约束,要么靠规则约束,如果sre只是建议站在外边看,挠挠痒,那就属于自high了。技术架构要向矩阵转,纵向靠整体技术约束+业务团队个性化,横向靠提前达成的共识+发现生成技术负债+设计评审,有公共平台发现和扫荡问题。但总之是要看公司是否整体技术体系的把控能力了。
2021 年 11 月 11 日 11:10
回复
没有更多了
发现更多内容

为什么软件开发很难外包

刘华Kenneth

外包 DevOps 风险 背锅

零基础如何学架构

兆熊

架构

记一次MHA切换故障踩的坑

一个有志气的DB

MySQL 高可用 复制 主从同步 故障分析

测试开发专题:spring-boot自定义返回参数校验错误信息

测试轩

Spring Boot 测试

识别代码中的坏味道(一)

Page

Java 面向对象 重构

游戏发行中学到的重要经验(严肃长文)

谢锐 | Frozen

独立开发者 游戏开发 游戏出海 移动互联网

Web3极客日报#140

谢锐 | Frozen

区块链 独立开发者 技术社区 Rebase Web3 Daily

看完这篇HTTP,跟面试官扯皮就没问题了

cxuan

https okhttp

谈谈双亲委派模型的第四次破坏-模块化

寻筝

Java JVM

谈谈控制感(4):损失的后果很严重

史方远

职场 心理 成长

Binlog2sql恢复误删除的数据

一个有志气的DB

MySQL 安全 数据

“四个维度” 讲明白什么是微服务!

攀鱼飞岩

微服务 单体系统 架构设计 团队组织 康威定律

当你不被尊重的时候,才会想起去尊重别人

小天同学

人生 个人成长 感悟

JVM源码分析之Object.wait/notify实现

猿灯塔

JVM

香港科技大学与OSL海科签订无毒海洋防污技术独家授权协议

极客编

看完这篇,你也是字符编码大神(ASCII、Unicode、UTF-8、UTF-16、UTF-32)

Meandni

Java 面试 Unicode utf-8 utf-16

游戏夜读 | Scikit-learn的2018自述

game1night

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (八)好单元测试的特质

编程道与术

Java 编程 软件测试 TDD 单元测试

决战下半场:小程序技术助力金融APP重回C位

Edd

小程序 数字化转型 app重构

经历过疫情,你懂得了什么

Winann

疫情 个人成长 生活 成长

找一个更好的理由

史方远

职场 成长 工作

战略懒惰有多可怕

Neco.W

创业 重新理解创业 初创公司

Azure App 部署Django 和 PostgrSQL

yann [扬] :曹同学

Python azure

阿里巴巴泰山版《Java 开发者手册》,也是一份防坑指南

古时的风筝

Java规范 Java开发手册

高仿瑞幸小程序 09 云数据库初体验

曾伟@喵先森

小程序 微信小程序 前端 移动

Leetcode 556. Next Greater Element III

隔壁小王

算法

MySQL安全-审计

一个有志气的DB

安全 MySQ

我画了35张图就是为了让你深入 AQS

一枝花算不算浪漫

AQS jdk源码

elasticsearch源码解析(一)——restapi

罗琦

elasticsearch 源码分析 RESTful

初次见面

KAMI

如何在 Mac 上优雅的截图和录屏

Winann

macos 效率 效率工具 Mac

SRE实战(01) 初识+探索SRE如何推进好大夫在线技术债务改造-InfoQ