Python 中具有可观察性的关键组件介绍


发布日期 : 2022-09-16 00:54:12 UTC

访问量: 218 次浏览

搜索代码

当编写的应用程序以一种基本上不可见的方式执行大量代码时, 应该怎么解决以下问题呢,如代码是否有效, 运作是否良好,以及谁在使用,如何使用?

可观察性是查看数据的一种能力, 数据会告知代码在做什么。 在这种情况下, 主要的问题领域是分布式系统中的服务器代码。 这并不是说可观察性对于客户端应用程序不重要, 而是因为客户端往往不是使用 Python 编写。 同样也不意味着可观察性对数据科学来说无关紧要; 数据科学中的可观察性工具(主要是 Juptyter 和快速反馈)是不同的。

可观察性的重要之处

可观察性为什么如此重要呢? 可观察性是软件开发生命周期 (SDLC) 的重要组成部分。 发布应用程序不是结束, 这是一个新周期的开始。 在此周期中, 第一阶段是确认新版本运行良好。 否则,可能会有回落的情况。 哪些功能运行良好,哪些有细微的错误? 我们需要了解发生了什么才能知道下一步该做什么。

无论是自然灾害、底层基础设施的推出, 还是应用程序进入一个奇怪的状态, 任何时候都可能因任何原因出现各种问题。 在标准 SDLC 之外, 需要知道一切都在有序运行。 如果没有运行, 那么需要想办法知道失败的原因。

反馈

可观察性的第一部分是获得反馈, 当代码提供有关它正在处理的信息时, 反馈可在多方面提供一定的帮助。 在暂存或测试环境中, 反馈有助于发现问题, 更重要的是, 能够以更快的方式对问题进行分类。 这改进了围绕验证步骤的工具和通信情况。

监视器

当相关系统中存在复杂的操作时, 需要确保系统能够很好地处理该操作。 在这种情况下, 需要将可观测系统中的数据聚合到仪表板中。 编写应用程序时, 这些仪表盘需要成为设计标准的一部分, 它们显示数据的唯一方式是应用程序与其共享数据。

警报

警报系统将可观测性数据与预期数据进行比较, 并在不匹配时发送通知。 可观察应用程序在以下两个方面具有警报友好性:

  • 能够产生足够的数据, 具有足够的质量, 可发送高质量的警报;
  • 警报具有足够的数据, 或者接收器可以轻松获取数据, 以帮助对源进行分类。

高质量警报有三个属性:

  • 低误报:如果有警报,肯定是出现了问题;
  • 低缺失警报:当出现问题时,会触发警报;
  • 及时:快速发送警报以缩短恢复时间。

这三个属性处于三方冲突中, 可以通过提高检测阈值来减少误报, 但代价是会增加丢失的警报, 也可通过降低检测阈值来减少丢失的警报, 不过这样做的代价是会增加误报。 通过收集更多的数据来减少误报和漏报, 但同样都要以时间为代价。 改善以上三种属性情况有些困难, 这就是可观测性数据的重要性所在。 高质量的数据可以减少这三种情况发生。

日志记录

有些人喜欢取笑基于打印的调试。 然而,在一个大多数软件都不是在本地 PC 上运行的世界里, 打印调试是所能做的一切重要事情。 日志记录是打印调试的形式化方式。 Python 日志库尽管存在许多错误, 但其允许进行标准化日志记录。 最重要的是, 这意味着可以从库中登录。

应用程序负责配置日志的去向。 然而具有讽刺意味的是, 在应用程序负责配置多年后, 这种情况变得越来越不真实。 现代容器编排环境中的现代应用程序记录标准错误和标准输出, 并信任编排系统来正确管理日志。 如果想让操作员知道发生了什么, 请使用日志记录, 而不是打印。

日志记录级别

日志记录最重要的特点之一是日志记录级别。 日志记录级别允许适当地筛选和路由日志。 但只有在日志级别一致的情况下才能做到这一点。 至少,应该在应用程序中保持一致。

在某些帮助下, 选择不兼容语义的库可以通过应用程序级别的适当配置进行追溯修复, 并通过使用 Python 中最重要的通用约定来做到这一点:使用 getLogger(__name-_)。 大多数合理的库都遵循这个约定, 过滤器可以在发出之前修改日志对象。 同时可将过滤器附加到根据名称修改的消息中, 以具备适当级别的处理程序。

import logging

LOGGER=logging.getLogger(__name__)

考虑到这一点, 现在必须实际指定日志级别的语义, 以下是最受欢迎的选项:

  • 错误:遇到错误会立即发送警报, 应用程序处于需要操作员注意的状态(这意味着关键和错误被折叠);
  • 警告:我喜欢称这些为“营业时间警报”, 有人应该在一个工作日内看到这个警告;
  • 信息:信息是在正常流程中发出, 它旨在帮助人们在已经怀疑存在问题时了解应用程序正在做什么;
  • 调试:默认情况下不会在生产环境中发出此命令, 如果需要了解更多信息, 可在生产显式中打开。

在任何情况下, 都不应在日志中包含 PII(个人可识别信息)或密码。 无论级别如何,都是如此。 包括级别更改、调试级别被激活等等。 日志聚合系统很少是 PII-安全的, 尤其是在 PII 法规不断发展的情况下(HIPAA、GDPR 等)。

日志聚合

现代系统几乎总是分布式的。 冗余、扩展,有时是管辖权需求, 这意味着水平分布, 微服务意味着垂直分布, 登录到每台计算机以检查日志不再现实。 出于某种适当的控制原因, 这通常是一个糟糕的主意, 它允许开发人员登录计算机会给他们太多的特权。

所有日志都应发送到聚合器中。 有商业产品, 可以配置ELK堆栈, 也可以使用任何其他数据库(SQL或no-SQL)。 作为一种技术含量非常低的解决方案, 可将日志写入文件并将其传送到对象存储。

记录查询

将所有内容记录到一个位置后, 日志过多。 特定的聚合器定义了如何编写查询, 但无论是通过存储进行爬网还是编写 NoSQL 查询, 记录查询以匹配源和详细信息都比较有用。

指标抓取

指标抓取是一种服务器拉取模型, 指标服务器定期连接到应用程序并提取指标。 至少,这意味着服务器需要所有相关应用程序服务器的连接和发现。

Prometheus 作为标准

Prometheus

如果指标聚合器是 Prometheus, 则将 Prometheus 格式作为端点非常有用。 几乎所有系统都包含 Prometheus 端点的兼容性填充码。 使用客户端 Python 库将 Prometheus 填充程序添加到应用程序中, 可以让大多数指标聚合器来抓取。 Prometheus 希望一旦发现服务器, 就会找到一个指标端点。 这通常是应用程序路由的一部分, 通常位于 /metrics。 无论 Web 应用程序的平台如何, 如果可以在给定端点提供具有自定义内容类型的自定义字节流, 则 Prometheus 可能会被抓取。

对于最流行的框架, 有一个中间件插件或等效的东西可以自动收集一些指标, 如延迟和错误率。这通常还不够。 如想要收集自定义应用程序数据,例如, 每个终端节点的缓存命中/未命中率、数据库延迟等。

使用计数器

Prometheus 支持多种数据类型, 其中一种重要且微妙的类型是计数器, 计数器总是会有提前警告。 当应用程序重置时,计数器将归零。 计数器中的这些“时期”通过将计数器“创建时间”作为元数据发送来进行管理。 Prometheus 将会比较来自两个不同时期的计数器。

使用仪表

仪表要简单得多, 它们测量瞬时值, 将其用于上下波动的测量, 例如,分配的总内存、缓存大小等。

使用枚举

枚举对于整个应用程序的状态很有用, 可以在更精细的基础上收集。 例如,如果您使用的是功能门控框架, 则可以具有多个状态(例如,使用中、已禁用、阴影)的功能作为枚举, 可能用处显著。

分析

分析与指标的不同之处在于它们对应于连贯的事件。 例如,在网络服务器中, 事件是一个外部请求及其产生的工作。 特别是,在事件完成之前, 无法发送分析事件。 事件包含特定的度量值, 如延迟、对其他服务的结果请求的数量和可能的详细信息等等。

结构化日志

当前可能的一个选项是结构化日志记录, send 事件只是发送具有格式正确有效负载的日志。 可从日志聚合器查询此数据, 解析数据并将其引入适当的系统中,以便对其进行查看。

错误跟踪

可以使用日志来跟踪错误, 也可以使用分析来跟踪错误。 针对错误进行优化的系统可以发送更多的数据,因为错误很少见。 Python 中的错误跟踪系统通常挂接到通用异常处理程序中, 通过收集数据,并将其发送到专用的错误聚合器。

使用哨兵

在许多情况下, 自己运行哨兵是正确的做法, 发生错误时,表示出现问题。 可靠地删除敏感数据是不可能的, 因为恰恰是在这种情况下, 敏感数据可能会出现在不应该出现的地方。

快速、安全、可重复

可观察的系统开发速度更快, 因为它们可以为您提供反馈, 运行起来更安全, 当它们出错时,会更快地发出通知。 可观察性有助于构建可重复的过程, 存在一个反馈的循环。 可观察性也提供了有关应用程序方面的知识。

前期投资有回报

构建所有可观察性图层是一项艰巨的工作。 这也常常让人感觉像是在浪费工作, 正确构建它可以让您在各个阶段大大加快开发的速度, 包括测试、监控,甚至是新人的入职等。 在一个客户流失与技术一样多的行业中, 仅仅减少新员工的入职开销也是值得的。 事实上,可观察性很重要, 因此如在流程的早期编写并始终维护它。 反过来,它也将会帮助并维护您的软件。