云原生时代下的监控

大纲

  • Observability甚至是什么?它与Monitoring有什么不同?

  • 概述现代可观察性的三大支柱:日志log记录,metric收集和请求跟踪trace

  • 每个方面在资源利用率,易用性,易操作性和成本效益方面的优缺点

  • 日志、指标、trace 结合使用时涉及的挑战

  • 在现代云原生环境中监控什么以及如何监控; 什么更适合作为指标聚合而不是记录; 如何以及何时使用来自所有三个来源的数据来获得可操作的警报和富有洞察力的分析

  • 使用其他工具加强上述三个工具是有意义的

在现代云原生环境中“监控”生成以及如何监控

我们的系统整体行为(或行为不当)的方式正在发生变化,这些系统需要满足的要求正在发生变化,这些系统需要提供的保证正在发生变化。

为了成功应对这些挑战,我们不仅需要改变构建和运营软件的方式,还要更好地了解我们的服务,这反过来又为我们提供了一个关于性能的更短的反馈循环,更短的反馈循环又能够帮助我们建立更好的服务。为了制定这种良性循环,了解什么是可观察性以及它与监测的不同之处变得非常重要。

云原生时代下的监控_第1张图片 Virtuous cycle of better Observability

1.1 监控

当我在Google中输入“监控”时,出现的前两个结果如下:

观察并检查一段时间内(某事物)的进度或质量; 继续进行系统审查,保持定期监督。

对我而言,监控意味着既有失败又有以人为中心的东西。让我们再谈谈这个,因为这构成了这篇文章的基石。

在过去,我们可能首先测试了我们的应用程序,交给QA循环测试, 然后我们可能会发布我们的代码,然后“监控”它。老实说,我并不认为每个人都在用这种方式管理软件生命周期,在当今这个时代,它通常被认为是一种“旧的方式”。

我们“监控”了一些东西,因为我们期望某些东西能以某种方式表现,同时,我们期望某些事情以非常具体的方式失败,并希望密切关注这一特定的失败。可是,当故障模式的数量增加并且故障本身变得更加难发现时,“明确的,可预测的故障” 的监控方法则成为了问题。

随着我们采用的架构越来越复杂,“可能出错的东西”的数量呈指数级增长。我们经常听说我们生活在一个“失败为常态”的时代。正如SRE书指出:

选择接受失败的模式需要设计我们的服务能在失败时能采用一些策略快速应对(降级机制:重试,超时,断路和速率限制),这意味着将全面、显式的故障模式转变为部分,隐式和软故障模式。

由于弱一致性而可以容忍的故障模式保证了最终一致性或积极的多层缓存等机制。故障模式甚至可以在负载增加的情况下故意触发,有可能完全降低我们的服务,但我们的服务能运行。

但所有这一切都是以增加整体复杂性为代价的,我们丧失了轻松推理系统的能力。

这让我想到了“监控”的第二个特征 - 它以人为中心。我们选择“监控”某些东西的原因是因为我们知道或怀疑某些东西可能出错,并且当它确实出错时会产生后果。严重的后果,需要人为干预,以尽快纠正。

我并不认为自动化一切是灵丹妙药,但像Kubernetes这样的平台的出现意味着以前人类和以故障为中心的监控工具帮助“监控”的几个问题已经解决了。这些平台免费提供的功能包括健康检查,负载平衡和失败服务等等。这是他们的主要价值道具。

随着越来越多的传统监控职责被自动化,“监控”已经 - 或者很快 - 不再以人为本。虽然这些平台都不能真正使故障服务变得坚不可摧,但如果使用得当,它们可以帮助减少硬故障的数量,使我们成为工程师,以应对我们的系统可能出现的微妙、模糊、不可预测的行为。这种失败远没有那么灾难性,而是比以前更加繁多

然后讨论这个问题 - 我们如何设计这种系统的监控?

对于如何为这些系统设计监控,实际上并不是如何设计系统本身。

我认为即使在这个勇敢的新世界中,“监控”仍然应该是硬性失败以及以人为中心。即使范围急剧缩小,“监控”的目标也没有改变,现在面临的挑战是确定并最大限度地减少仍然以人为中心的“监控”。现在,我们需要设计我们的系统,使得整个故障域中只有一小部分是一种难以操作的类型,由人来操作。

但是有一个悖论。最大限度地减少“硬,可预测”故障模式的数量并不意味着系统本身作为一个整体会更简单。换句话说,即使基础架构管理变得更加自动化并且需要更少的人力资源,应用程序生命周期管理也变得越来越困难。硬故障模式的数量减少是以 隐式故障模式和整体复杂性的急剧上升为代价的,“监控”每个故障明显变得不可行且也是不必要的。

1.2 可视化

在我看来,可观察性实际上是关于理解系统在生产环境中的表现。如果“监控”最适合报告系统的整体运行状况,那么 “可观察性”旨在提供对系统行为的高度细化的见解以及丰富的上下文,非常适合提供隐式故障模式所需的信息和调试所需的信息。”监控“主要用于发现失败,这反过来要求我们能够主动预测这些失败。

可观察系统是一种能够自行公开足够数据的系统,以便生成信息(找到尚未制定的问题的答案)并以简单的方式轻松访问这些信息。

1.3 插曲 - 黑盒监控

对于没有经验的人来说,黑盒监控是指通过将系统视为黑盒并从外部进行检查而得出结论的监控类别。

虽然有些人认为黑盒监控已成为过去,我认为黑盒监控仍然有其地位,因为我们大部份的核心业务和基础设施组件都外包给了第三方供应商。我们对供应商组件的性能的监控是有限的,特别是外包组件能够影响我们系统的整体性能时,了解我们所拥有的服务如何受到外包组件变幻莫测的影响变得非常重要。

除了第三方集成之外,将我们自己的系统视为黑盒子可能仍然具有一定的价值,特别是在微服务环境中,不同团队拥有的多个服务可能涉及为请求服务。对于个别团队来说,将其他团队拥有的服务视为黑盒子似乎是务实的。这使得各个团队能够根据他们公开的合同设计与不同团队拥有的其他系统更好的集成,并保证他们的SLA。

云原生时代下的监控_第2张图片 Blackbox monitoring

1.4 白盒监控与可观察性

白盒监控“是指基于从系统内部获得的信息的”监控“类别。白盒监控不再是一个革命性的想法。如今,时间序列,日志和trace都比以往任何时候都更加流行,已经持续了几年。那么。Observability是否仅通过其他名称监控白盒?嗯,不太好

云原生时代下的监控_第3张图片 Whitebox vs Blackbox monitoring

1.5 数据和信息

白盒监控和可观察性之间的区别实际上是数据和信息之间的差异。信息的正式定义是:

监控和可观察性之间的区别不仅在于是从系统的内部报告数据还是通过将系统视为黑盒而收集数据,在我看来,重点不是怎么来的数据,而是我们计划用它做什么以及我们如何轻松实现。

Whitebox监控是一个很棒的数据来源。可观察性是我们在需要时能够从这些数据中轻松快速地找到密切相关信息的能力。可观察性更多地是关于我们可能需要哪些关于系统在生产中的行为的信息以及我们是否能够访问这些信息。我们并不关心信息是否经过预处理的或者它是否从动态数据中得出的,我们收集的原始数据可能有多种用途。

  • 我们可以使用我们收集的数据来寻找具有高严重性后果的显式故障模式 - 即将发生的中断。换句话说 ,我们使用数据的特征设置警报 Alerting,以规避或者提前及时告知故障的发生

云原生时代下的监控_第4张图片 Alerting
  • 我们可以使用这些数据来了解服务的整体健康状况,在这种情况下,我们认为这是一个Overview。

云原生时代下的监控_第5张图片
  • Alerting和overview则称为 Monitor

云原生时代下的监控_第6张图片
  • 我们可以使用这些数据来调试我们事先无法预测的罕见和隐式故障模式。在这种情况下,我们使用数据来调试我们的系统。

云原生时代下的监控_第7张图片
  • 我们还可以将数据用于分析等目的,以便在正常稳定状态下更好地理解我们的系统在生产中的行为,在这种情况下,我们正在使用数据来理解我们现在存在的系统

云原生时代下的监控_第8张图片
  • 我们可能还想了解我们的服务如何依赖于当前的其他服务,以便让我们了解我们的服务是否受到其他服务的影响,同时,如果我们想对其他服务性能进行分析,我们也可以利用这些数据。

云原生时代下的监控_第9张图片
  • 我们还可以更加雄心勃勃,确保我们的系统不仅现在正常运行,而且还要确保我们有数据来理解我们系统的行为,以便我们能够不断改进和维护它,而不仅仅是现在或者明天,而是在整个系统的生命周期中。虽然解决明天的问题确实不应成为我们今天的目标,但认识它们仍然很重要。不要等到我们被问题困扰时才意识到原来我们可以做得更好。我们可以预见到今天已知的硬故障模式并为它们“监控”,但是明天已知的硬故障模式通常不会在今天以非常明确的方式展现出来,他们通知在极端异常的情况下或在某些微妙的场景下出现,且不是人们能立马解决的。

这些都是不同的目标。我们可以优化其中一些甚至所有这些。白盒监控是帮助我们实现上述所有目标的重要组成部分(可能是最重要的组件),但白盒监控本身并不具备可观察性。

云原生时代下的监控_第10张图片 Monitoring vs Observability

不同的组织可能对“监控”下的内容有不同的要求。对于一些人来说,依赖性分析可能是他们“监控”的积极部分。对于其他人来说,安全审计可能是其监控目标中不可或缺的一部分。因此,我认为Observability是一种频谱,随着服务的发展不断发展。

另一种区分“监控”和“可观察性”的方式是用我们对问题的反应方式:主动和被动。同样,对于不同的组织,这可能会有所不同,但我认为区分这两个目的很重要。主动生成数据中的信息是因为我们觉得我们可能一直需要它们,这与在调试和分析时主动收集数据并动态生成信息不同。

云原生时代下的监控_第11张图片

另一种区分两者的方法是根据Ops与Dev职责区分。我认为“监控”是需要on-call的。可观察性我认为是需要强制开发人员/软件工程师参与。

云原生时代下的监控_第12张图片

此外,值得注意的是,频谱中存在因果关系。很多时候,人们在一层“监控”(错误率和请求持续时间等指标)往往是“症状”,导致“症状”的原因在其他层级。

云原生时代下的监控_第13张图片

解决问题的方式通常是通过一些粗粒度度量(增加的错误率或响应时间)或trace信息(服务B慢,可能是来自下游服务C的某些类型的请求的速度慢)发现症状,然后反复深入研究以证实或使我们的猜测无效,直到我们找到根本原因。

云原生时代下的监控_第14张图片

这让我想到了下一点

1.6 可观察性不仅仅是数据收集

如果我们希望从数据中获取信息,那么访问数据就成了一种要求,而Observability不仅仅是数据收集。获得数据后,能够轻松地从这些数据中获取信息变得非常重要。

云原生时代下的监控_第15张图片

虽然原始数据确实比预处理信息更具延展性,但在实际需要之前推迟处理信息会产生其他开销,即收集,存储和即时处理。理论上听起来很好,但只要我们能够实现可观察性目标,实施细节无关紧要,如果我们愿意,如何最好地处理和存储正在收集的数据是实现建立和维持良性循环的梦想的一个关键因素。数据的可用性也成为关键问题,数据收集的障碍也是如此。

最后,我认为Observability最重要的方面不是数据收集或处理。仅靠我们处理的数据并不能解决问题。解决问题还涉及工程师的直觉和领域经验,通过问正确的问题来找到问题的根因。实际上,如果没有良好的工程直觉和领域知识,即使有很多好用的工具,也不可能获得良好的可观察性。这就是本文其余部分旨在解决的问题,希望能够为您提供一些思考方面的建议,以便从中获得更好的见解。

2. 可观察性的三大支柱

具体的示例帮助我们更好地理解日志log,指标metric和跟踪trace。让我们假设我们的系统或子系统的架构如下所示:

云原生时代下的监控_第16张图片

2.1 日志

日志是随时间发生的离散事件的不可变记录。有些人认为事件与日志相比是不同的,但我认为,就所有意图和目的而言,它们可以互换使用。

事件日志一般有三种形式:

  • 明文 :日志记录可能采用自由文本的形式。这也是最常见的日志格式。

  • 结构化 :最近几年比较流行的方式。通常,这是以JSON格式发出的日志。

  • 二进制 :考虑Protobuf格式的日志,用于复制和时间点恢复的MySQL binlog,systemd日志日志,BSD防火墙pf使用的pflogformat,它通常用作tcpdump的前端。

日志很有用,特别是在提供有价值的洞察力以及平均值和百分位数不显示的长尾的充足背景时。回到上面我们看到的例子,让我们假设所有这些不同的服务也以不同的粒度发出日志。某些服务可能会为每个请求发出更多日志信息。仅查看日志,我们的数据格局可能如下所示:

云原生时代下的监控_第17张图片

当我查看上图时,第一反应就是数据非常丰富。当我们以非常精细的粒度进行搜索时,记录我们可能感兴趣的任何内容且所有内容都变得非常有用,但只是查看这些数据,就不可能一眼就看出请求生命周期是什么,甚至是哪个 请求遍历的系统,甚至是任何特定系统的整体运行状况。 当然,数据可能很丰富,但没有进一步处理,这是非常难以理解的。但我们需要的是信息而不是数据。

我们是否需要有关请求生命周期的信息?或者我们是否需要有关特定服务的资源利用率的信息?或者我们是否需要有关特定主机健康状况的信息?或者我们是否想要了解特定服务崩溃的原因?或者我们是否需要有关分布式键值存储中的复制滞后的信息?或者我们是否在寻找有关最终一致系统收敛多长时间的信息?或者我们正在寻找有关GC暂停的信息?或者我们是否试图收集有关症状的信息,或者我们是否试图找到根本原因?

坦率地说,我们可以收集无数的数据点,我们可以回答无数的问题,从最琐碎到最困难的问题。

然而,两个非常重要的信息,涉及整个请求生命周期的命运(通常是短暂的)和整个系统的命运(在比请求生命周期长的数量级的持续时间内测量)。我将trace和指标看作是在日志之上构建的抽象,它沿着两个正交轴预处理和编码信息,一个是以请求为中心,另一个是以系统为中心。

云原生时代下的监控_第18张图片

2.2 Trace

Trace是一系列因果相关的分布式事件的表示,这些事件通过分布式系统对端到端请求流进行编码。单个trace可以提供对请求所遍历的路径以及请求结构的可见性。请求的路径允许我们理解请求服务中涉及的服务,并且trace的结构有助于理解在执行请求时异步的接合点和影响。

云原生时代下的监控_第19张图片

trace背后的基本思想很简单 - 确定应用程序、代理、框架、库、中间件以及可能位于请求执行路径中的任何其他内容的特定点,检测这些点并使这些点相互协调。这些要点特别令人感兴趣,因为它们代表执行流程中的分支(OS线程或绿色线程),或跨越网络或流程边界的跳跃。

Trace通常表示为有向非循环图,它们用于识别在每个层完成的工作量,同时使用发生在语义之前保留因果关系。实现这一目标的方法是在代码中的特定点添加检测。当请求开始时,它被分配一个全局唯一ID,然后在整个请求路径中传播,以便每个检测点能够在将ID传递到请求的曲折流中的下一跳之前插入或丰富元数据。当执行流程到达其中一个服务的检测点时,将发送记录以及元数据。这些记录通常在提交给收集器之前异步记录到磁盘,然后收集器可以根据系统不同部分发出的不同记录重建执行流程。

收集此信息并重建执行流程,同时保留因果关系以进行回顾性分析和故障排除,使人们能够更好地了解请求的生命周期。最重要的是,了解整个请求生命周期可以调试跨多个服务的请求,以查明增加响应时间或资源利用率的来源。因此,trace在很大程度上有助于人们了解请求的生命周期中系统的哪些组件减慢了响应。

2.3 Metrics

度量标准是我们数据的数字表示,因此可以充分利用数学建模和预测的力量,在当前和未来的时间间隔内推导出我们系统行为的知识 - 换言之,时间序列。

metric只是在一段时间内测量的数字,并且数字针对存储,处理,压缩和检索进行了优化。因此,指标可以实现更长时间的数据保留以及更轻松的查询,而这又可以用于构建仪表板以反映历史趋势。此外,指标允许随着时间的推移逐渐降低数据分辨率,比如可以聚合成每日或每周频率。

历史时间序列数据库的最大缺点之一就是不适合探索性分析或过滤。在这方面,分层metric模型以及像Graphite这种缺少标签系统在这方面特别严重。Prometheus这样的现代监控系统则使用metric名称以及标签来表示每个时间序列。

云原生时代下的监控_第20张图片

这允许数据模型中的多维聚合。使用metric标准名称和标签来标识度量标准。Prometheus的指标是不变的; 更改metric的名称或添加或删除标签将会生成新的时间序列。存储在时间序列中的实际数据称为样本,它由两个组件组成 - float64值和毫秒精度时间戳。

3. Log/metric/trace 在资源利用率,易用性,易操作性和成本效益方面的优缺点

在我们看到如何利用每个标准的优势来制定出色的可观察性体验之前,让我们根据三个标准评估三者中的每一个:

  • 易于生成/仪器

  • 易于处理

  • 易于查询/搜索

  • 信息质量

  • 成本效益

3.1 日志

到目前为止,日志是最容易生成的,因为没有涉及初始处理。事实上它只是一个字符串或一串JSON,这使得以日志形式表示我们想要发出的任何数据变得非常容易。大多数语言,应用程序框架和库都带有对日志记录的内置支持。日志也很容易记录,因为添加日志行与添加print语句一样简单。只要我们的搜索空间本地化为单个服务,这对于向下钻取分析非常有用。

不幸的是,日志的效用是有限的。我要告诉你关于日志的其他所有事情都会让人感到痛苦。虽然日志生成可能很容易,但各种流行的日志库的性能特性还有很多不足之处。

大多数高性能的日志记录库获得的资源很少且要求快速被处理掉。但是,许多语言和框架的默认日志记录库会影响整个应用程序的性能。此外,除非使用RELP之类的协议来保证可靠的消息传递,否则日志消息也可能丢失。如果使用日志数据进行计费或付款,这一点就变得尤为重要。最后,除非日志记录库可以动态地对日志进行采样,否则日志记录能够对整个应用程序性能产生负面影响。正如Slack上提到的那样:

在处理方面,原始日志几乎总是被标准化,过滤和处理,如Logstash,Scribe或Heka之类的工具,然后它们被保存在像Elasticsearch或BigQuery这样的数据存储中。如果应用程序生成大量日志,那么日志可能需要在像Kafka这样的代理中进一步缓冲,然后才能由Logstash处理。像BigQuery这样的托管解决方案有配额限制。在存储方面,虽然Elasticsearch可能是一个出色的搜索引擎,但运行它会涉及真正的运营成本。即使您的组织配备了操作ELK专家的运营工程师团队,也可能存在其他缺点。一个很好的例子 - 我的一个朋友告诉我他在Kibana的图表中经常看到一个急剧下降的斜率,不是因为服务的流量下降,而是因为ELK无法跟上绝对数量的索引被抛出的数据。但即使日志处理不是问题,我所知道的任何人似乎都没有完全弄清楚如何使用Kibana的UI,更不用说享受使用它了

尽管使用外部的日志管理系统成本很高,但是大量组织选择外包日志管理,这证明了日志内部运营的操作难度大,价格昂贵且脆弱。

一个经常被提出的解决日志记录成本开销问题的解毒剂是采样或仅记录可操作数据。但即使采取积极的措施,它也要求我们先做出可行的决策。因此,我们记录“可操作”数据的能力完全取决于我们能够预测将来可行的内容或将来可能需要哪些数据的能力。虽然对系统的更好理解确实可以让我们对现在收集的数据进行有根据的猜测并证明是未来真正的信息来源,但可能每一行代码都是有可能成为日志的来源。

3.2 Metric

总的来说,基于metric的日志监控的最大优势在于(与日志生成和存储不同),metric的传输和存储具有持续的开销。与日志不同,metric的成本不会随着用户流量或任何其他可能导致数据急剧上升的系统活动而增加。

这意味着,对于metric,应用程序流量的增加不会像日志那样导致磁盘利用率、处理复杂性,可视化速度和运营成本的显著增加。metric存储随着捕获的时间序列数量的增加而增加(当更多主机/容器被启动时,或者添加新服务或现有服务被更多地检测时),但与每次指标发送UDP数据包的statsd客户端记录到不同的statsd守护程序。

收集后的metric对数学、概率和统计变换(如采样,聚合,汇总和关联)更具有可塑性,这使其更适合报告系统的整体运行状况。

metric也更适合触发警报,因为针对内存时间序列数据库运行查询比对ELK等分布式系统运行查询更有效,更不用说更可靠了,在决定是否进行聚合之前汇总结果即可快速设置警报。

当然,有些系统只能严格查询内存中的结构化事件数据,以获得可能比ELK稍微便宜的警报,但运行大型分布式内存数据库的操作开销,即使它们是开源的,也并不值得去做,特别是 当有更容易的方法来获得同样可操作的警报时。metric类似于系统性能的黑盒前端,因此最适合提供此信息。

云原生时代下的监控_第21张图片 Metrics as blackbox frontends

日志和指标的最大缺点是它们是系统范围的,除了在特定系统内发生的事情之外,很难理解其他任何东西。当然,指标也可以是请求范围,但这需要伴随标签的增加,这会导致存储量增加。虽然新的Prometheus存储引擎已针对高流失时间序列进行了优化,但指标并非最适合高度精细化的请求范围信息。对于没有花哨联接的日志,单个日志行或度量标准不会提供有关系统所有组件中请求发生的情况的大量信息。在最佳使用时,日志和指标可以让我们进入数据孤岛,但仅此而已。

虽然这些可能足以理解各个系统的性能和行为 - 无论是有状态还是无状态 - 但在理解遍历多个系统的请求的生命周期时,它们会成为一个裁剪者。

3.3 Trace

云原生时代下的监控_第22张图片

Trace捕获请求在流经分布式系统的各个组件时的生命周期。通过使用额外的键值对来丰富上下文的支持,可以在trace中对特定于应用程序的元数据进行编码,这可以为开发人员提供更多的调试功能。

分布式跟踪的用例是无数的。虽然主要用于服务间依赖性分析,分布式分析和调试稳态问题,但跟踪也可以帮助进行退款和容量规划。

到目前为止,跟踪是最难在现有基础设施中落地的,因为为了使跟踪真正有效,需要修改请求路径中的每个组件以传播跟踪信息。根据您的要求,您可能会被告知请求流程中的好处不会超过缺点,或者被告知这些好处是使调试更难的盲点。

我们已经实施了一年多的请求跟踪服务,但还没有完成。使用这些类型工具的挑战是,
我们需要在每个组件周围添加代码,以真正了解在请求的生命周期中发生的情况。
令人沮丧的是,如果代码未被检测或标头没有携带id,则该代码成为操作的风险盲点。

跟踪检测的第二个问题是由开发人员设置代码是不够的。我们大量应用程序是使用开源框架或库构建的, 这些库或者框架往往采用不同的语言,这让添加trace变得更具挑战性,因为每种语言、框架和有着完全不同的并发模式。实际上,trace在组织中成功部署的前提是,有一种核心语言并且有一套整个公司内统一使用的框架。

跟踪的成本并不像日志记录那样具有灾难性,主要是因为跟踪几乎总是被大量采样以减少运行时间开销以及存储成本。可以做出抽样决定:

  • 请求开始时生成跟踪

  • 所有参与系统都记录了整个请求执行过程的跟踪

  • 在请求流程的中途,只有下游服务才会报告跟踪

4. 最佳做法

鉴于上述日志的特征,任何关于日志记录的最佳实践的讨论本质上都体现了权衡。我认为有几种方法可以帮助缓解日志生成、处理、存储和分析方面的问题。

4.1 Quotas

我们要么记录所有感兴趣的内容并为此支付处理和存储费用,要么我们选择性地记录,虽然我们牺牲了保真度,但仍然可以访问重要数据。大多数关于日志记录的讨论都是围绕着日志级别,但我很少看到用日志存储配额来限制服务可以生成日志数据量。虽然Logstash和朋友确实有用于限制日志摄取的插件,大多数都是在事件生成后会基于关键字或者某些阈值进行过滤限制。

如果将日志记录作为内部服务提供 - 并且有许多公司就是这种情况 - 那么建立具有配额和优先级的服务层可能是第一步。任何面向请求或服务的用户都被分配了最高优先级,而基础结构任务或后台作业或任何可以容忍有限延迟的内容在优先级列表上都较低。

4.2 动态采样

无论是否有配额,能够动态采样日志变得非常重要,这样可以即时调整日志生成速率,以减轻日志转发,处理和存储系统的负担。用前面提到的人的话来说,他通过关闭EC2登录获得了50%的提升:

它让我信服的唯一一点就是能够根据需要动态增加或减少日志记录。但需要注意的是,如果你不总是运行完整的日志记录,可能最终日志无法提供它最原始的价值。

4.3 记录是一个流处理问题

数据不仅用于应用程序性能和调试用例,它也构成了所有数据分析的来源。从商业智能的角度来看,这些数据通常具有巨大的实用性,并且企业愿意为理解这些数据而向所需的技术和人员付费,以便做出更好的产品决策。

这里有趣的方面是,企业可能想要回答的问题与我们在调试过程中可能想要回答的问题之间存在惊人的相似之处。例如,可能具有商业重要性的问题如下:

过滤出用户查看此文章的次数总计不到100次的异常国家/地区

然而,从调试的角度来看,问题看起来可能更像:

筛选执行超过100个数据库查询的异常页面
或者,只显示来自印度尼西亚且加载时间超过10秒页面

虽然从技术角度来看这些并不是类似的查询,但执行这些分析或回答这些类型的查询所需的基础结构大致相同

业务可能感兴趣的可能是:

用户A查看了产品X.

使用一些额外信息扩充此数据可能会使可观察性成熟:

用户A查看了产品X,页面需要0.5秒才能加载
用户A查看了产品X,其图像未从缓存中提供
用户A查看了产品X并阅读了审核Z,其中API调用的响应时间为300毫秒。

这些查询都可以通过事件实现。事件本质上是结构化的键值对。将业务信息与有关请求生命周期的信息(计时器,持续时间等)相结合,重构已有的分析功具达到可观察性的目的。

如果您考虑到这一点,日志处理可以很好地融入在线分析处理(OLAP)账单中。从OLAP系统获得的信息与在系统边缘进行调试或性能分析或异常检测的信息相比没有太大差异。大多数分析管道都使用Kafka作为事件总线。向Kafka发送丰富的事件数据允许人们使用KSQL(KSQL是来自Confluent的优秀人员的Kafka流式SQL引擎)实时搜索流。

KSQL支持各种强大的流处理操作,包括聚合、连接、窗口化、会话化等等。Kafka日志是流数据的核心抽象存储,同一份数据可同时进入离线数据仓库和流处理。无论是各种数据库、搜索索引还是公司的其他数据服务系统, 所有内容都是日志的流媒体物化后的视图。这些派生视图所需的丰富数据和ETL,现在都可以使用KSQL以流方式完成创建。监控,安全性,异常和威胁检测,分析以及对故障的响应可以实时完成,满足这些场景的实时性要求。任何人通过一个简单而熟悉的SQL界面即可实现以上功能。

无论如何,事件在进入Kafka前注入所有Observability所需的信息和元数据,在重新利用流处理工具时会很有帮助。此模式提供的另一个好处是该数据可以定期从Kafka日志中过期。因为调试所需的事件大多数仅在事件生成后的相对较短的时间段内有价值,这与业务为中心信息通过ETL处理的数据不同。当然,只有在kafka已经成为组织的一个组成部分时,这个功能有才有意义。将Kafka简单地引入技术栈以进行实时日志分析其实是没有必要的,特别是在没有任何重要JVM专业知识的非JVM组织中。

4.4 对未来的新希望

日志记录仍然是一个未解决的问题,我希望有一套OpenLogging的规范,在OpenTracing的脉络中,它将作为社区驱动开发的一个最重要的例子和目标。一个专为云计算时代设计的规范,由CNCF推进,由许多后端实现。规范日志的规范必须是结构化事件,并针对高容量,低保真度事件的动态采样进行规则化,封装成一个lib,支持所有语言,并集成到所有主流的框架中。一个规范,允许我们充分利用流处理技术,并规范了所有CNCF项目的日志记录格式,尤其是Kubernetes。

4.5 Metric

Prometheus不仅仅是服务器。我认为Prometheus是一套标准和项目,服务器只是整体中的一部分。

Prometheus在编制指标的展示格式方面做得很好,我很乐意看到它成为标准。虽然Prometheus不提供长期存储,但大约一年前添加到Prometheus的远程写入功能允许人们将Prometheus指标编写到OpenTSDB或Graphite等自定义远程存储引擎,从而有效地将Prometheus转换为直写缓存。随着最近推出的通用写后端,人们可以通过HTTP和Protobuf将时间序列从Prometheus传输到任何存储系统,如Kafka或Cassandra。

然而,远程读取略微更新,我只是看到在过去几个月中才发现的有价值的功能。InfluxDB现在本身支持Prometheus远程读写。远程读取允许Prometheus在查询执行期间从远程后端读取原始样本,并在Prometheus服务器中计算结果。

此外,在即将发布的2.0版本中对Prometheus存储引擎的改进使Prometheus更加有利于云原生工作负载,并且时间序列名称大量流失。Prometheus强大的查询语言,以及使用相同查询语言定义警报并使用模板化注释丰富警报的能力,使其成为所有“实现监控目的”的理想选择。

但是,使用指标时,务必注意不要破坏标签空间,标签的类型需要控制在一定范围并且保持唯一性,不要为所有的指标都设置报警。为了使警报有效,我们只需要识别系统的硬故障模式即可。有些人认为,“监控”的理想信号数量在3-5之间,绝对不超过7-10。在与朋友交谈时不断出现的一个常见痛点是他们的“监控”是多么嘈杂。嘈杂的监控会导致用户不再关注指标。换句话说,这会浪费指标服务器的存储空间,或者更糟糕的是,错误警报会导致严重的警报疲劳。

4.6 Trace

虽然历史Trace难以实现,但服务网格的兴起使得Trace功能几乎毫不费力。Lyft利用service mesh pattern,在不改变应用程序代码的情况下为所有应用程序提供跟踪信息。service mesh pattern通过在网格级别实现跟踪和统计信息的收集,这允许将个体服务视为黑盒的情况下,仍然在整个网格上获得令人难以置信的可观察性。即使构成网格的应用程序需要能够将header转发到网格中的下一跳,但这种模式只需要少量的代码调整即可在现有的架构中集成。

4.7 使用其他工具来增强上述三个工具

异常跟踪器(我认为这些是日志++)在过去几年中已经走过了漫长的道路,并且提供了优秀用户界面,而不是简单从文本或大量JSON来发现异常。异常跟踪器还提供完整的回溯,局部变量,每个子例程或方法调用,错误/异常的发生频率以及其他对调试非常有用的元数据。异常跟踪器旨在做一件事 - 跟踪异常和应用程序崩溃 - 他们做得非常好。虽然它们不能消除对日志的需求,异常跟踪器需要更多的日志。

一些新工具还通过将网络数据包视为事件来源并使用数据包捕获来构建整体服务拓扑来帮助实现可见性。虽然这绝对比在整个堆栈中检测所有应用程序代码的开销更少,但它主要用于分析不同组件之间的网络交互。虽然它无法帮助调试多线程服务的异步行为或单线程服务中的死循环问题,但使用指标或日志来增加它可以更好地了解单个服务中发生的情况,可以帮助人们更好的理解整个服务

5. 总结

可观察性监控不完全相同。可观察性意味着更全面的内容,包括“监控”、应用程序代码检测、即时调试时的主动检测以及对系统各个组件的更透彻理解的文化。

可观察性意味着能够 并且有信心 能够构建系统,知道这些系统在生产环境中是一定会损坏。这是关于理解我们正在构建的软件可以并且几乎总是在不同程度上被毁坏(或者很快就会崩溃),尽管我们做出了最大的努力。

在一台笔记本电脑运行代码与利用CI中在生产环境中运行代码区别,就如同在室内游泳池游泳与在充满食人鱼的波涛汹涌的河流中游泳之间的区别一样。如果我们想要保障我们正在运行的服务的质量,但却无法在生产环境中进行调试以便快速修复自己的服务,这是不可接受的。

所以这篇文章的总结是,软件开发和操作应该在云原生环境下进行。

5.1 生产前测试

单元测试在保障产品的质量方面与监控一样重要。虽然很少有人对代码进行模糊测试,但是他们的代码是针对一组随机生成的输入进行测试的,但模糊测试只能针对一个服务的输入集进行全面测试。

端到端测试可能允许对系统进行一定程度的整体测试,故障注入/混沌工程可能有助于我们了解系统承受故障的能力水平,但复杂的系统以复杂的方式失败,并且目前还没有一种好的测试方式能够预测未来可能导致失败的点。

尽管存在这些缺点,但测试一样重要。如果不出意外,测试我们的代码可以让我们编写更好,更易维护的代码。更重要的是,研究证明,在许多分布式系统中,“测试错误处理代码可以防止58%的灾难性故障”。虽然现在有很多工具能帮助我们了解服务在生产中的行为,但并不能否定测试的必要性和重要性

5.2 线上测试

生产测试并不是一个非常新的想法。诸如A / B测试,Canary Deployments(EEP),黑暗交通测试(有人称之为阴影)等方法已经存在了一段时间。

然而,能够在生产中进行测试绝对要求在需要时可以停止并回滚。这意味着只有那些能在生产环境中获得快速测试反馈的才能在生产中进行测试。它还意味着要留意服务关键绩效指标的变化。对于HTTP服务,这可能意味着错误率和关键端点的延迟等指标。对于面向服务的用户,这还可能意味着用户参与度的变化。生产中的测试本质上意味着主动“监控”生产的变化。这也引出了我下一个观点。

5.3 监控

监控非常重要,我认为它在您的可观测性范围内占据了一席之地。

为了在生产中进行测试,我们需要有效的监测。监控既以故障为中心(我们主动监控KPI的变化)以及以人为中心(我们希望在线上推送变更进行测试的开发人员能尽快收到警报)。

我之所以选择称之为Tier I Monitoring,是因为我认为这些是任何线上服务的质量保障的最低要求。这是警报的来源,我相信metric是达到此目的最佳方式。

但是,我们可能会捕获一些其他信息,但不能用于警报。有一种观点认为所有这些信息都没有多大价值,需要被抛弃。但是,我相信这是我经常发现自己需要的那种信息,我希望它以仪表板的形式呈现给我。

Tier II monitoring一个很好的例子是GitLab的仪表板,它恰当地命名为车辆的仪表盘,或者提供有关正在运行的Go进程的信息。我之所以选择这个例子,是因为GitLab因其透明度而闻名,这些都是真实公司的真实现场制作仪表板。我发现分析这些仪表板比在博客上面写一些简单的例子更有意义。

虽然这些指标并不特别有助于调试bug或我们甚至不知道存在的问题,但是拥有这样的仪表板让我对系统有了一个Overview,我发现这一点非常有用,特别是在版本发布之后,因为它让我在触发警报前,就能快速了解关键指标是否受到变更的影响。监测那些可能存在内存泄漏的heap使用情况将是Tier II monitoring的一个很好的例子。我真的想知道我是否推出了有内存泄漏的代码,而这种case却不需要添加报警

5.4 探索

探索可以回答一个人们无法主动思考的问题。这通常涉及查询原始事件或记录上下文中丰富的数据,并且非常强大,可以显示我们事先无法预测的答案。

5.5 动态探索

到目前为止,所有这三种方法的问题在于它们要求我们提前记录有关系统的信息。这意味着我们需要的数据需要提前生成。

动态仪器技术并不新鲜。但是,像DTrace这样的实现主要是以机器为中心的,并且主要关联仍然局限于地址空间或特定机器的事件。最近的学术研究将这些想法与分布式跟踪的一些想法结合在一起,允许人们“在系统的各个模块中通过有效的选择、过滤和分组事件,在系统的某个点获得任意metric, 甚至可以跨越组件或机器边界“。

Pivot Tracing这篇论文提出一个突破性概念:Baggage Abstraction。

Baggage是每个请求中的元组容器,它在遍历线程,应用程序和机器边界时与请求一起传播。元组遵循请求的执行路径,能捕获之前发生的关系。使用行李,数据透视跟踪可以在执行请求期间有效地记录所有的连接。

行李传播的概念已被纳入OpenTracing规范,该规范现在允许“来自移动应用程序的任意应用程序数据从请求发起到最后进入存储系统,整个流程都是透明,我们可以跟踪到整条链路情况”。

虽然这仍然与白皮书描述的内容不完全相同,但它仍然使我们更接入真正的端到端跟踪以及动态地丰富跟踪数据以获得更好可见性的能力。

Facebook的Canopy在Pivot Tracing论文的在基础上,并将其与Scuba的基础事件模型相结合,使数据探索变得前所未有的动态。

5.6 未知

最后还有未知。我们无法了解或不需要知道的事情。即使我们完全了解我们的应用程序和硬件性能,但完全看到应用程序层下面的各种抽象层是不切实际的 - 或者是不必要的。

我们必须承认还有很多未知的事情这个事实。这也引出了我最后一个观点。

5.7 选择你自己的Observability Adventure

可观察性 ,和其他大多数事物一样 ,并不是特别有用。系统的可观察性的价值直接源于我们从中获得的商业价值。

对于许多企业而言,拥有良好的警报策略和基于时间序列的“监控”可能是实现业务目标所需的全部。对于其他人来说,能够调试大海捞针类型的问题可能是产生最大商业价值所需要的。

因此,可观察性并不是绝对的。根据您的服务要求选择您自己的Observability目标。

你可能感兴趣的:(云原生时代下的监控)