你好,我是陈现麟。
通过学习“雪崩”系列的内容,我们掌握了构建一个稳定的分布式系统所需的四大方法:熔断、限流、降级和扩容,再也不用担心由于一个局部的小问题,导致整个系统出现重大的故障了。
在“雪崩”系列课程中,我们曾经提到需要基于系统内部的运行状态,来进行相应的降级和扩容操作,特别是在扩容机制中,需要通过服务过载的信息来进行相应的扩容,可是我们应该如何来获得系统内部的运行状态呢?
其实这就是分布式系统中的可观测性问题,那么从这节课开始,我们将用 2 节课的时间来讨论,如何通过分布式系统的可观测性,来解决系统监控与告警的问题。在这一节课中,我们先讨论需要监控的原因,然后分析监控与可观测性之间的关系,接着介绍搭建一个可观测性系统涉及的开源组件,最后,重点讨论对于一个大规模的分布式系统,设计监控系统应该遵循的经验和原则。
如果一辆汽车没有仪表盘,我们就不知道汽车当前的速度,只能凭着感觉开,很容易出现超速甚至意外,另外由于不知道当前还有多少汽油或者电量,一不小心就会因为能源耗尽抛锚在路上。监控之于分布式系统,更甚于仪表盘之于汽车,因为分布式系统的内部更加复杂,更容易出现意外的情况。那么对于“为什么需要监控”的这个问题,我们就从监控有哪些作用的角度来回答。
第一,从规则角度,监控信息是扩容、缩容和报警等规则的数据来源。只有通过监控了解了系统的状态信息,才能基于状态信息设置一定的规则,当规则满足后,就触发扩容、缩容和报警等相关处理。
第二,从全局角度,基于监控信息,我们才能构建监控大盘。监控大盘能让我们快速地了解当前系统的情况,并且能回答当前系统表现的一些基本问题。
第三,从长期角度,通过监控信息,可以分析系统的长期趋势。比如从系统当前磁盘的使用情况和增长速率,我们可以推测出什么时候需要进行扩容。
第四,从实时角度,在系统出现变更的时候,可以通过监控系统,迅速了解最新的变更是否异常。比如缓存命中率是否下降,请求时延是否变长。
第五,从调试角度,当系统出现报警信息的时候,通过监控系统能帮我们快速定位问题。在前面的“雪崩”系列中,虽然我们已经知道如何保障系统的稳定性了,但是既然故障出现了,就一定要定位到根本原因,然后彻底去解决。
在 2018 年以前, IT 领域一直使用监控这个术语,来表示通过采集系统、服务和网络的内部信息,诊断和预测系统的行为。到了 2018 年, CNCF Landscape 率先出现了 Observability 的概念,将可观测性( Observability )从控制论( Cybernetics )中引入到 IT 领域。
在控制论中,可观测性是指系统可以由其外部输出,来推断其内部状态的程度,系统的可观察性越强,我们对系统的可控制性就越强。自此以后,“可观测性”逐渐取代了“监控”,成为云原生技术领域最热门的话题之一。
那么,在 IT 领域中,为什么会用“可观测性”逐渐取代“监控”呢?我们先来感性认识一下,一般来说,监控主要告诉我们以下的信息,这些信息主要表现为结果。
而一个可观测系统,除了告诉我们这些结果信息之外,还需要能回答出导致这些结果的原因。
从上面的对比中,我们可以初步了解到监控和可观测性之间的区别,接下来,我们再进一步从基本概念的角度,来讨论监控和可观测性概念的差别。
如下图,在 IT 建设中,我们将“可观测性”能力划分为 5 个层级,其中告警( Alerting )与应用概览( Overview )都属于传统监控的概念范畴,因为触发告警的往往是明显的症状与表象。但在云原生时代,架构与应用部署方式的变化是非常频繁的,不告警并非意味着一切正常,因此,通过获取系统内部的信息,来主动发现( Preactive )问题就显得非常重要了。
可观测性通过排错、剖析与依赖分析,这三个部分来主动发现故障,具体如下。
并且,这三部分的逻辑关系是:首先,无论是否发生告警,运用主动发现能力,都能对系统运行情况进行诊断,通过指标呈现系统运行的实时状态;其次,一旦发现异常,逐层下钻,进行性能分析,调取详细信息,建立深入洞察;最后,调取模块与模块间的交互状态,通过链路追踪构建“上帝视角”。
因此,主动发现能力的目的,并不仅仅是为了告警与排障,而是通过获取最全面的数据与信息,构建对系统、应用架构最深入的认知,而这种认知可以帮助我们提前预测与防范故障的发生。
通过上面的讨论,我们可以看出可观测性是监控的扩展和进化,监控是建立在可观测性收集的数据之上的,我们可以结合下图,从三个维度进行理解。
首先,监控到可观测性是从黑盒往白盒方向的进化。监控更注重结果,即当前出现了什么问题,或者将要出现什么问题;而可观测性也同等关注问题出现的原因,即通过内部状态的展示来回答这个问题。
其次,监控到可观测性是从资源往服务方向的进化。监控的使用主体主要是运维,监控的对象主要为系统资源相关,而在云原生时代,分布式系统越来越复杂,仅仅通过系统层面监控是远远不够的,所以可观测性使用的主体引入了研发。通过研发的加入,增加了服务内部状态和服务之间调用关系的暴露,大大增强了我们对系统的控制力。
最后,监控到可观测性是处理方式从被动监控到主动分析的进化。在监控为黑盒的情况下,我们完全不了解系统内部的情况,只能等待监控信息触发报警后,再进行处理;而当监控为白盒的情况下,研发人员可以方便地了解系统内部运行的情况,并且进行分析,主动发现问题。
搭建一个可观测性平台,主要通过对日志( Logs )、链路( Traces )与指标( Metrics )这三类数据进行采集、计算和展示,它们的具体信息如下。
日志信息( Logs ),即记录处理的离散事件。它展现的是应用运行而产生的信息,或者程序在执行任务过程中产生的信息,可以详细解释系统的运行状态。虽然日志数据很丰富,但是不做进一步处理,就会变得难以查询和分析。目前,我们主要通过 ELK 来处理。
追踪链路( Traces ),处理请求范围内的信息,可以绑定到系统中,单个事务对象的生命周期的任何数据。在很大程度上, Traces 可以帮助人们了解请求的生命周期中,系统的哪些组件减慢了响应等。目前,我们主要通过分布式调用链跟踪系统 Jaeger 来处理。
指标信息( Metrics ),它作为可聚合性数据,通常为一段时间内可度量的数据指标,透过它,我们可以观察系统的状态与趋势。目前,我们主要通过 Prometheus 进行采集和存储,通过 Grafana 进行展示来解决。
基于上面的开源组件,我们可以很方便地搭建一个可观测性平台,来提升极客时间后端分布式系统的可观测性。
同时,我们也可以看出,当前对于可观测性的三类数据 Logs 、 Traces 和 Metrics 的处理系统是割裂的,这会导致它们相互之间的数据不通、标准不统一、组件繁杂。所以 CNCF 社区推出了 OpenTelemetry 项目,旨在统一 Logs、 Traces 和 Metrics 三种数据,实现可观测性大一统,这是一个非常有雄心的计划,目前正在推进中,我们敬请期待。
在可观测性的五个层次中, Overview 和 Alerting 这两个部分和业务结合得非常紧密,完全是依照业务场景来定制的。并且 Overview 是我们使用可观测性系统主要的入口, Alerting 是可观测性系统将故障通知到工程师的通道,在可观测性系统中,它们是和工程师日常工作非常紧密的两个部分。
因此,一个设计良好的 Overview 和 Alerting 非常影响可观测性系统整体的使用效率和体验,那么接下来,我就将我在工作过程中,对设计 Overview 总结的一些经验分享给你, Alerting 将会在下一课中介绍。
在公司中,每一个层级的工程师,所关心的目标是不一样的,所以, Overview 应该分层设计,你关心的目标是什么,你的 Overview 就应该展示什么。一般来说,层级越高,关心的事情越偏业务,不要将各层的关注点混合在一起。
首先,对于整个研发部门来说, Overview 展示的是,能够实时体现公司业务状态最核心的指标,例如 Amazon 和 eBay 会跟踪销售量, Google 和 Facebook 会跟踪广告曝光次数等与收入直接相关的实时指标;而 Netflix 由于是订阅制,销售数据不实时反映业务的情况,则通过反映用户满意度的指标——播放按钮的点击率来替代,即视频每秒开始播放数,简称为 SPS( Starts Per Sencond )。
其次,对于运维研发、 DBA 、基础服务之类的各级研发团队,同样需要有自己的 Overview ,总体原则依然是,团队的目标是什么, Overview 就应该展示什么,并且整个团队的人都需要关心这个 Overview。
最后,最低一层的 Overview 对象不是工程师,而是为每一个服务、机器节点建立 Overview 。因为相对于部门组织来说,工程师的数量大,并且变化比较频繁, Overview 的维护成本非常大。并且,个人查看自己负责的服务和机器的 Overview 需求,可以通过团队、服务和机器节点的 Overview 来解决。
通过对 Overview 分层设计,保证了每一层的专注力都能聚焦在核心指标上,如果上层指标出现异常,我们可以查看下一层的指标,进一步诊断问题,并且结合 Logs 和 Traces ,直到找到问题发生的原因。
在分层设计中,我们已经知道对 Overview 进行分层设计的方法了,这里我们主要来讨论 Overview 内容的设计经验。
除了上文提到的“ Overview 应该分层设计,你关心的目标是什么,你的 Overview 就应该展示什么”之外,还有一个非常重要的原则是,一个 Overview 不应该超过一个页面。
首先,在使用上,我们经常要持续观察系统的情况,如果一个 Overview 有多个页面,我们就需要不停地切换,这非常影响我们的专注力,效率非常低。
其次,在内容上, Overview 的信息应该越精简越好,精简到不能再精简为止,如果超过了一个页面,就说明信噪比比较低,聚合和精简做得不彻底。
最后,在日常维护上,Overview 不超过一个页面,相当于规定了指标的最大数量,也就避免了我们只增加指标,从来不去清理的问题。
Google SRE 团队在介绍它的监控系统时,明确说明监控系统的四个黄金指标是延迟、流量、错误和饱和度,如果系统只能监控四个指标,那么就应该监控这四个指标,具体介绍如下。
延迟是指服务处理某个请求所需要的时间。我们在计算延迟的时候,应该区分成功的请求和失败的请求,比如,某一个接口的一个实例触发了熔断,被熔断的请求时延非常低,如果将熔断的请求时延和正常请求一起统计的话,就会产生误导性的结论。
流量是用来度量系统负载的。对于 API 接口来说是请求的 QPS ;对于音视频流媒体来说,是并发数或者网络 I/O 速率。
错误是指请求失败的速率,包含显示错误,比如 HTTP 500 以及隐式错误,比如 HTTP 200 回复中包含的错误。
饱和度描述的是,系统当前的负载占满载的百分比,一般来说,以整个系统最受限的资源的指标来表示,比如,对于 Redis 这样的内存系统,内存就是它的饱和度指标,假设当前机器使用内存为 16 G ,机器总内存为 32 G ,那么当前系统的饱和度为 50%。
分位值是指把所有的数值从小到大排序,取前 n% 位置的值,即为该分位的值。它更加能描述数据的分布情况,比如,请求时延 60% 的分位置为 3 s ,说明有 60% 的请求时延小于或者等于 3 s ,40% 的请求时延大于或者等于 3 s ,依据这个信息,我们就能判断出,当前接口时延大于 3 s 的比例。
由于平均值容易受到少数极值的影响,所以,当请求时延的平均值为 3 s 时,我们不能判断出接口时延的真实情况。比如, 100 个请求的时延为 10 ms,有 1 个请求的时延为 102 s 的情况下,虽然平均时延很大,但是 99% 的请求时延都很快,在 10 ms 以内。
一般情况下,我们经常会通过计算多个分位值,来进一步了解数据的分布情况,比如,请求的时延情况,我们经常会通过 80% 、90% 、99% 、99.9% 多个分位值来度量。
而对于采样频率,我们需要对系统的不同部分,选择不同的频率。比如 CPU 使用率的变化是非常大的,我们可以选择 1 s 采集一次,而对于变化非常缓慢的磁盘容量, 1 分钟一次的频率可能都高了。
并且,我们可以通过降低历史数据的采样频率,来降低存储空间,提高访问速度。比如,对于 CPU 使用率,超过一个月的数据,可以从 1 s 一个采样点,聚合为 1 分钟内只保留 3 个数据:最大值、最小值和平均值。
本节课,我们先从规则、全局、长期、实时和调试的角度,分析了需要监控的原因,这样你就明白了监控的重要性。
通过讨论两个很容易混淆的概念,即监控和可观测性之间的关系,我们将多个维度进行对比,得出监控是可观测性的一部分,可观测性是监控的扩展和进化这个结论。
为了了解开源社区主流的实现方式,我们介绍了可观测系统需要收集的关键数据:日志( Logs )、链路( Trace )与指标( Metrics ),这样你就知道如何搭建一个可观测性平台了。
最后,我们讨论了监控系统的设计经验,依据这些设计经验,你在设计一个监控系统的时候,就能游刃有余了。
你平时在使用监控系统的过程中,碰到最大的痛点是什么呢?
欢迎你在留言区发表你的看法。如果这节课对你有帮助,也推荐你分享给更多的同事、朋友。