第二章:数据可观测性的组成部分-灵析社区

攻城狮无远

正如在第1章中介绍的,数据可观测性是与其他领域(如应用程序或分析)相交的(IT)可观测性领域的一部分。在本章中,我们将介绍如何将数据可观测性及其交互添加到系统中,如图2-1所示。


正如在第1章中讨论的,数据可观测性通过结合所有领域为观察者提供了更广泛的观察,以解释系统的内部状态。然而,如果不遵守一些预防措施,这种组合本身可能成为一个挑战。本章将深入介绍观察是什么以及它们应该包含什么。

本章介绍了数据可观测性的三个基本组成部分:观察可访问的通道、描述观察结构的观察模型以及为您的数据系统提供主动能力的期望。

数据可观测性信息通道

数据可观测性的第一个组成部分是向观察者传递观测结果的通道。这些通道包括日志、跟踪和指标。这些通道适用于可观测性的所有领域,并且不严格与数据可观测性相关联。

接下来的章节将定义可观测性的三个主要通道。您可能已经熟悉这些通道,但如果不熟悉,有数百本书籍和博客深入探讨了它们的定义。如果您想深入了解,请阅读《Distributed Systems Observability》这本书的第一章,该书专门介绍了这些通道。我还推荐阅读《Observability Engineering》的第二部分,以及《Cloud Observability in Action》。

日志

日志在任何系统中都非常常见。它们通常是文件中的文本行(称为日志文件),表示应用程序在执行过程中发生的事件。

因此,日志是由IT系统生成的最常见的观测通道。它们可以采用多种形式(例如,自由文本行、JSON),旨在封装有关事件的信息。日志中的一行(通常,日志是一系列行的流)是记录操作的结果。

记录是IT中几十年来的最佳实践,尤其是在基础设施、应用程序和安全领域。日志已被用于调试和优化IT系统或流程。甚至已经开发了日志的标准,如Syslog,它规定了日志的结构,并允许通过中央系统来控制异构基础设施。

虽然日志对捕获系统行为的信息至关重要,但使用日志来重新创建多步骤的过程是困难的。这是因为日志包括系统内的所有活动,而进程的日志可能与其他并发进程交错,或分散在多个系统中(例如,分布式系统、服务网格)。

跟踪

优秀的书籍《可观测性工程》将跟踪描述为一种“基本的软件调试技术,通过在程序执行期间记录各种信息来诊断问题”。

跟踪可以被看作是日志的一个特定情况 - 步骤的重连,这些步骤由一个进程执行。因为跟踪代表了同一进程的所有事件之间的关联,所以它们允许从日志中有效地派生整个上下文。这个概念已经被扩展,以满足分布式系统的需求,通常被称为分布式跟踪,其中跟踪事件(也称为跨度),如调用 web 服务、访问文件或查询数据库,会在不同的系统中产生,但作为全局跟踪(通常是一个 ID)相互关联。

跟踪和它们的跨度是一种有效的方式,可以跟踪服务和服务器之间的操作,因为它们传递了服务器、服务和事件时间戳等信息。因此,观察者可以轻松浏览服务上的日志,在给定时间内分析他们需要生成观察结果的特定事件的日志。

实际上,跨度还传递了可能对观察者来说有意义的日志,观察者可以当场分析,而不仅仅是用来重新连接跟踪信息。

然而,一些系统可能尚不支持分布式跟踪;因此,跟踪在本地不被支持(不可观察)。这些系统可能已经被标记为不本地可观察的。在这种情况下,一种解决方案可能是利用现有的日志来解释它们的内容,以根据分散在日志行中的信息重建跟踪(这种可能性在第6章中有所涉及)。

观察的最后一个通道是度量,与日志和跟踪密切相关,因为两者都可以包含度量。然而,由于其简单性,度量在与日志和跟踪相比具有重要优势。

指标

每个系统状态都有一些可以用数字表示的组成部分,而这些数字会随着状态的变化而变化。度量提供了一种信息来源,使观察者不仅可以使用事实性信息来理解,而且可以相对容易地利用数学方法从大量度量中获取见解(例如,CPU负载、打开文件的数量、平均行数、最小日期)。

由于它们的数值性质,需要记录它们。这就是为什么度量曾经是日志的一部分,同时也出现在跟踪中。因为它们的用途非常直接,多年来我们看到了简化度量的发布或收集的标准,独立于常规日志和跟踪。

然而,在图2-2中,我展示了一个所有组件都混合在一起的情况(这种情况经常发生);两个应用程序正在发送有关形成跟踪的事件的日志,而在非结构化(已记录的)文本中的某处提供了多个度量。这可以让您更好地理解为什么标准已经出现,以简化跟踪和度量的收集和使用。

根据我所描述的内容,谈论日志、度量和跟踪似乎有点奇怪,因为它们都是由数据产生的(比如数字“3”不能记录、测量或跟踪任何东西;它只是一个数字)。这就是为什么将数据可观测性视为与其他领域交叉的领域至关重要,比如应用程序和分析,这意味着来自多个领域的日志、度量和跟踪产生的信息必须相互连接。让我们在下一节来解决这个问题。

观察模型

为了确保全面的数据可观测性,关键是要对来自不同渠道和格式、涉及多个领域的观察进行建模。在接下来的章节中,我将介绍一个模型,该模型对数据可观测性的维度进行了编码,并支持了我在第1章中提出的用例的解决方案。

我想强调的是,我提出的模型是我在许多项目和用例中看到的可行模型。虽然随着时间的推移,模型可能会发生变化,包括更多的复杂性或更多的关系,但我打算详细展示,只要它们之间的连接足够充分,可以避免逆向工程或近似,来自不同领域的观察如何轻松地共同工作。

这个模型至少会为您提供一个可行的起点,用于生成代表您需要观察的系统状态的信息。但是,您可以将其视为一个核心模型,您可以扩展以满足额外的、可能是定制的需求。在第3章中,我将解释您可以使用的不同策略,以自动生成模型的大部分信息,并在第4章中提供与多种常见数据技术(如Python pandas、Apache Spark、SQL等)相关的现成配方。

在图2-3中,该模型被设计为一个实体图,其中每个实体提供了关于系统状态的一些信息,以及它们如何相互关联。链接清楚地标识了数据可观测性与其他领域之间的交叉点。例如,稍后在本章中,您将了解到数据源(数据可观测性)与可访问它的服务器(基础设施可观测性)之间存在链接;因此,链接本身是这两个领域之间交集的一部分。

图2-3中提出的模型旨在结构化数据观察,以最大程度提高外部观察者对其整体可解释性,并提供一种通用语言,可以独立于参与观察的人员、时间和技术使用。

为了提高模型的可读性,它分为三个空间:

  • 物理空间

(在图2-3中位于左侧)将观察与有形实体相连接。即使服务器可能是虚拟的,用户可能是系统或应用程序用户,物理空间代表一个可以物理检查的空间。

  • 静态空间

(在图2-3中位于中间)表示相对缓慢变化的实体,与动态空间形成对比。它表示系统的状态,可以手动构建。

  • 动态空间

(在图2-3中位于右侧)是系统中正在发展或变化得如此之快,以至于无法整合、文档化或手动构建的部分。这是自动化甚至不是一个问题,而是一个必要性。

在每个空间中,引入了实体以实现某种可观察性。让我们逐个介绍这些实体,以了解它们的目的以及它们与其他实体的关系如何在数据可观测性中发挥作用。

物理空间

在本节中,我将介绍数据可观测性领域中可以被视为有形的信息:服务器和用户(或它们的虚拟替代品,如容器和系统用户),如图2-4所示。

服务

服务器与运行被观察的IT系统的机器相关联。它旨在提供有关物理设备的信息。然而,在云计算时代,它也可以代表容器、虚拟机、Pod等,提供对基础设施观察的访问。因为我正在定义核心模型,所以将服务器组件保持简单,没有编码容器、虚拟机或集群等内容,这些可以作为模型的扩展。

然而,关于服务器的核心信息必须帮助观察者进入其他系统(例如Datadog)以分析基础设施的状态。为了确保观察者具备这种能力,服务器必须传达的信息类型包括IP地址、容器ID、机器名称或任何能够适当识别底层基础设施的信息。在“数据源”部分,我们将看到服务器如何以及何时帮助观察者。

用户

在数据使用环境中,涉及多种类型的用户,以不同的方式参与其中。最明显的两种用户是数据用户和数据消费者。但是,我们还可以考虑数据所有者、数据架构师和在数据治理或更一般的数据管理组织中定义的其他角色。在数据可观测性中,我们将更具体地考虑数据生产者和数据消费者,通过他们与数据或系统的互动——核心模型显示了两个示例,将在“应用程序版本”和“应用程序执行”部分讨论。

我们有兴趣观察用户,因为这可能是观察者可以用来改善对情况的理解的最简单的可操作信息来源。我们可以简单地询问用户有关数据问题或他们可以提供的任何有助于我们理解过程的信息;他们通常具有有关数据以及系统应该如何工作的某些知识。 与服务器一样,用户可以是虚拟的抽象,比如不包含个人信息的标识符(例如GitHub帐户ID)或所谓的系统或服务帐户,例如root或sparkuser,这些帐户向观察者提供了关于用户对系统行为(例如安全性)或其责任(例如隐私)的影响的提示。

在后面与系统内的应用程序相关的部分,我将讨论随时拥有这些信息的优势。 尽管到目前为止,我已经将我们对物理空间的考虑限制在用户和服务器上,但其他元素,如地理位置(例如托管数据库的服务器的地理坐标)也可以成为物理空间的一部分。但是,我建议从一个简单的模型开始,以获得所需的核心可见性,然后逐渐添加其他用例。也就是说,地理位置信息非常适合用户和基础设施可观测性领域。

现在让我们讨论静态空间,其中包括大多数专有的数据可观测性实体。

静态空间

物理空间允许观察者将与数据有关的事件与可以访问的“事物”联系起来(即使是虚拟的)。在本节中,我将介绍静态空间(见图2-5),它赋予了观察者分析系统在静止状态下的能力,或者在时间维度对其状态的影响不如物理空间大(例如,服务器的存在,用户的代码更改)。这些实体与数据和应用程序以及它们的结构演变相关,并在静态空间内发挥作用。

数据源

数据源提供有关存在哪些数据以及如何使用它的信息,无论这是一个简单的CSV文件、Kafka主题还是数据库表格。本地文件路径、主题名称和表格名称通常是数据源的一部分信息。

数据源存在于静态空间中,因为数据源不会迅速改变。当然,文件可以复制或移动到其他位置,但是模型会将复制或移动的文件视为新的数据源。在数据库中重命名表格也类似于移动它。不过需要注意的是,重命名和移动数据源可能会带来重大后果。由于应用程序期望数据位于特定位置,因此在生产环境中,数据可能已被移动(例如,mv),应用程序可能会失败。在这种情况下,将会有多个数据源实体,每个数据源位置一个,因为将数据源从一个位置移动到另一个位置是将其复制然后删除。这个复制然后删除的操作实际上是一个转换,将由其自己的实体表示——这个衍生将在本章后面介绍。

数据源还是一个观察的要素,位于数据可观测性领域的主要组成部分,并与服务器相链接,这是与基础设施可观测性领域的交叉部分。

一些突出显示可以获得数据源可观测性的用例包括:

  • 数据迁移到/从另一台服务器
  • 数据重复或冗余
  • 数据在服务器上的可用性(例如,服务器迁移或升级)
  • 数据访问(即,如果机器与访问数据的物理连接)

然而,数据不仅仅是一个来源,它还是多种类型信息的存储库。在下一节,我们将探讨这意味着什么。

schema

尽管前面介绍的数据源提供了关于如何访问数据的信息,但它并没有涵盖用户可能在数据中找到的信息类型。

模式实体提供了有关数据源结构的可见性。模式是元数据的一个重要组成部分(其他组成部分可能包括定义、标签等),它传达了关于可用于数据源的字段(或列)的信息,包括那些可能是深层的(嵌套的)。模式的每个字段至少都有一个名称和一个关联的类型,该类型可以是本机的(例如,字符串、整数、地址)或概念性的(例如,地址、SKU_ID),也可以两者都有。

尽管模式位于静态世界中,但它仍然是一个不断变化的实体。对于数据库数据源,它提供了一个动态示例,以表格的形式,可以在其中添加、删除或重命名列。但是,模式使跟踪这些更改相对容易。

模式与数据源相关联,因为它允许观察者识别数据源中可用的信息类型。

由于数据源的模式可能会发生变化,模型可以通过以两种不同但非排他的方式保留所有模式版本来编码这些变化。每种方法都支持有趣的用例:

  1. 数据源模式的每次修改都会创建一个新的模式实体,以及变更或版本的时间。以下是观察者如何利用这些信息的示例: 立即查看新旧模式之间发生了什么变化。 验证新模式是否与新要求匹配。 察觉由于转换错误而导致的未经计划的更改。
  2. 数据源的每个数据使用者都会创建一个与其自身数据源使用相关的模式实体。这使观察者有机会: 意识到由于缺少信息而导致其使用失败,并提出信息请求。 确认可以用来改进其结果的新信息。 适当地更改其使用方式以匹配重命名的信息。

有趣的是,根据语义,模式是一个观察,要么是数据可观测性的(a)主要组件的一部分,要么是(b)数据和分析可观测性之间的交叉点。

在模型的这一部分,我们可以恢复数据的相当大部分可见性。然而,我们仍然缺少大量关于数据在系统的其余部分,特别是在应用程序和分析中的运行方式的信息。本节的其余部分将专注于实现这两个领域内的数据可观测性。

血缘

血统实体,更准确地说是技术数据血统,可能是最难发现的信息,因此可见性最低(截至撰写本文) - 结果,它也是最少被使用的观察,因此我们仍然有很多需要从中学习的地方。关于如何使用血统的文献很多(本节末尾将列出一些示例),但关于如何具体收集它的信息很少。

血统(literal translation: 行 + 年龄)是指数据源之间的直接连接。数据源的血统是其一组直接上游数据源及其血统。技术数据血统可以位于数据源级别或字段级别。我们应该考虑到,与数据源级别相比,模式级别更复杂,因为它提供了有关数据源模式如何相互连接的信息。这导致了一个连通图,其中数据源的每个字段都有其自己的血统,将其与上游数据源的字段连接起来,如图2-6所示。


数据源之间的连接是通过执行输入(源)到输出(结果)的转换的应用程序创建的。这些转换可以包括以下事件:

  • 由Java Web服务器发出的SQL查询,将表格(输入)转换为JSON HTTP响应(输出)。
  • 由报告工具生成的SQL,从一系列表格(输入)计算和呈现(输出)关键绩效指标。
  • Spark作业从多个Parquet文件(输入)创建数据仓库中的视图(输出)。
  • Kafka应用程序使用流API消耗主题(源)并生成另一个主题(输出)。
  • 机器学习脚本训练模型(输出),使用从CSV文件(输入)创建的特征矩阵。
  • 即使人类将数据从纸上的表格(输入)复制到Excel表格(输出),也算是一种血统。

血统中包含的信息本质上是输入和输出数据源和/或模式之间的映射。

为了将此映射与数据源和模式编码在一起,图2-3中呈现的模型显示血统与模式相关联,从而实现以下用例:

  • 立即了解遵守转换所需的最小信息子集,有助于优化。
  • 通过沿着列维度对数据的子集进行分区,从而实现进一步的处理优化。
  • 将转换与数据源存储和位置分离,以便更轻松地进行变更管理(例如,从在数据湖中处理文件的代码到在湖仓库中的表上执行分布式SQL)。
  • 从输入和输出之间的依赖关系生成语义(用法)信息。

尽管在概念上很简单,但血统具有以下特点,因此变得复杂:

  • 难以记录:所有数据源都必须记录,并且必须应用于所有字段。
  • 可能会更改:即使是对SQL查询的简单修改也会更改数据血统。
  • 数量众多:公司的数据上不断进行许多转换。即使是一个简单的CRUD应用程序也由许多转换组成。

尽管存在这些复杂性,我将血统信息留在静态空间的一部分,因为血统依赖于将数据转换为创建所需输出的人,而静态空间为我们提供了观察这些变化的能力。

在考虑血统时,我们还可以看到它与以下方面非常匹配:

  • 分析可观测性 血统包含了分析结构以及如何使用数据进行分析。
  • 用户/目的可观测性 血统编码了可以使用数据源实现的内容。
  • 应用程序可观测性 血统由应用程序执行,数据应用程序存在来执行血统。

在讨论血统对用户/目的可观测性和应用程序可观测性的贡献时,还有很多探讨的空间,我们将在后续进一步讨论。

应用

应用程序提供了数据可观测性的另一个方面,因为它是提供数据可见性的关键。事实上,应用程序位于所有信息的中心:它们是用户的产物,是分析的容器,是数据的消费者和生产者,它们在基础设施上运行,同时配置或实施它们的安全性。

必须记录有关应用程序的信息,以便观察者可以理解哪个系统正在运行以及相关的逻辑。

我倾向于将应用程序视为通往可观测性其他领域的大门,因为应用程序在所有方面都相对中心。事实上,提到一个应用程序可能会很简单,例如:

  • Spark作业的groupId:artifactId。
  • Tableau工作簿的路径。
  • Python脚本的组织/模块名称。
  • 一个编排器描述符(例如,GCP Workflow)中的步骤URN,用于调度SQL。

图2-3显示了“应用程序”没有指代任何具体内容,但因为它仍然位于可观测性模型的最中心位置,所以必须要执行。我将在“应用程序执行”中解释如何执行此操作。

有人可能会认为血统应该直接连接到应用程序。例如,SQL在Oracle中连接两个表并在Snowflake中创建视图是在将运行它的应用程序中编写的,因此在这两个实体之间创建了直接连接。

然而,我认为这种观点在静态空间中过于强烈地将“数据”和“应用程序”可观测性领域耦合在一起。在一些繁琐的情况下,这种直接连接是完全不合适的:

  • 血统修改:当血统被修改并创建了新的血统时,初始血统不再是应用程序的一部分。在这种情况下,血统应该与应用程序版本连接(参见“应用程序版本”)。
  • 血统在运行时生成:当血统在运行时生成时,例如动态生成的SQL,所有SQL都不存在于应用程序中,直到运行和使用。在这种情况下,血统将连接到应用程序的运行时(执行)(参见“应用程序执行”)。

当然,应用程序与血统并不是完全断开的;它只是不会直接连接到血统。相反,它通过两个组件,应用程序存储库和应用程序版本,扮演了嵌入大部分观察模型的容器的角色。

应用程序存储库

应用程序存储库通常被认为是在图2-3中所呈现的模型中的离群值,因为它提供了应用程序源代码的存放位置等信息(例如,源代码、报告配置等)。

乍一看,似乎与数据之间没有或几乎没有关联。然而,应用程序存储库提供的信息旨在编码数据可观测性与应用程序可观测性之间的关联。

由于应用程序的源代码可能会移动,应用程序存储库可以表示其最新位置(希望不会同时有多个位置),并暗示其以前的位置。我选择将这种时间性的概念编码为不同的实体——应用程序版本中。

存储库的主要用途之一是为观察者提供应该分析系统的确切位置。例如,如果某个应用程序在生成数据源时出现问题,知道应用程序存储库的位置会告诉观察者应该查看的确切位置。然而,他们还需要知道应用程序的版本,以便适当地分析情况——尤其是在问题发生时的版本,这就是应用程序版本有用的地方。

应用程序版本

应用程序版本是静态空间中的最后一个实体,也是最关键的一个,因为它是其他实体之间的粘合剂。应用程序版本是观察模型中的入口点,用于指示在出现与数据相关的问题时应用程序的确切运行版本。

版本可以是:

  • 版本号(例如,v1.0)
  • Git 哈希(例如,d670460b4b4aece5915caf5c68d12f560a9fe3e4)
  • 时间戳(例如,1652587507)

版本允许观察者浏览应用程序仓库中正在运行的应用程序的历史记录。版本还在进行根本原因分析时非常有用。如果版本太旧,可能表明应用程序尚未更新。如果版本未知/更新,可能表明引入了逻辑错误或未知的转换。

您将看到,版本与血统或更接近核心数据可观测性实体(例如,数据源、模式)没有直接关联。因此,为了在应用程序和数据可观测性之间建立桥梁,我们必须考虑正在执行、读取、转换和生成的内容。这就是动态空间的作用。

动态空间

动态空间(参见图2-7)允许观察者利用使用数据的系统行为。其主要目的是在运行时(即数据运行时上下文)创建可见性。


此外,环境的状态对于运行时发生的事件非常敏感,例如由于现实世界事件而导致数据更改,由于虚拟机重启而导致应用程序被终止等。换句话说,它非常动态和不可预测(至少是确定性的),这就是我称之为动态空间的原因。动态空间的组成结构如下所述,从应用程序执行开始。

应用程序执行

应用程序执行提供给观察者有关正在运行的应用程序及其对数据的使用的信息。

如前所述,应用程序是打开观察模型中其他组件更多可见性的工具,因为其源代码描述了使用数据的分析(例如,数据血统)。通过捕获实际运行情况及其执行,应用程序执行向观察者传递信息,例如:

  • ID:允许观察者确定哪些应用程序可观察信息是需要审查的(例如,在应用程序日志系统中)。
  • 启动日期:允许观察者了解上述信息的相关期间。
  • 当前配置及其在执行之间的更改:快速识别不正确的设置。

应用程序执行直接连接到其他实体,例如应用程序(是什么)、服务器(在哪里)和用户(谁)。因为观察者了解应用程序执行及其与应用程序内部某些数据使用行为的连接(请参阅血统执行和数据指标),观察者将能够:

  • 连接到服务器以分析它可能如何影响执行,或者更好的是,使用服务器的可观察性信息来获取此可见性,而无需连接到它(例如Splunk、Elastic)。
  • 确切知道哪些应用程序正在运行或用于在服务器上运行,并分析其性能或负载。
  • 轻松快速地识别执行操作的人员,因此可能能够帮助描述情况。

但是与应用程序的连接如何?图2-3中呈现的模型不将应用程序执行与应用程序相连接,因为观察者需要了解有关应用程序执行的最重要信息是其版本。此外,由于版本涉及源代码,因此可以推断它也涉及应用程序。

拥有关于正在执行的版本的信息非常强大。此信息提供了即时的见解,例如部署的版本是否不是最新版本,或者哪些更改可能导致问题(例如git diff)。

此外,请考虑应用程序可能会在不同服务器(例如,环境)上的不同版本中执行,使本节中描述的信息变得更加有价值。

血缘执行

血统执行实体可能不太明显,但也是最复杂的,因为它可能会有大量的实例。 血统执行简单地提供有关血统执行的信息。因此,它可以代表许多不同的事物,例如SQL作业的执行、Python转换、复制命令、机器学习训练等。血统执行旨在向观察者提供有关血统行为的明确信息,包括连接到数据源发生的频率和时间等信息。

我不会说血统执行在本质上传达了大量信息,但它是观察模型的基石。没有血统执行,第1章中介绍的数据可观察性的大多数用例都是幻想,或者依赖于最佳努力的协调,这不可避免地会导致虚假的相关性(主要是在协调数据和应用程序可观察性领域)。

血统执行在与其他核心实体(如血统和应用程序执行)的连接方面信息丰富。如果与血统的关联清晰,观察者就可以知道哪些血统是可观察的,并可以进一步分析这种关联。 血统不能单独执行,因为它只表示数据源(模式)之间的连接,而不表示这些连接是如何实现的。这些信息在代码中可用,可以使用应用程序版本观察。例如,数据转换可以在Spark RDD中实现,然后在Spark DataFrame中实现,然后在Spark SQL中实现,然后在Snowflake中实现为物化视图,依此类推。

为了理解血统(转换)是如何执行的,观察者必须使用前一节介绍的应用程序执行的信息。这就像血统是由应用程序自身启动的子程序(或子应用程序、子进程)执行的,例如,当从Kafka消耗某些事件时,应用程序会在表中创建一个条目,然后执行相关的血统。 此外,应用程序不限于运行单个血统,或者每个血统只运行一次,甚至总是运行相同的血统。由于这种多样性,使观察者能够看到这种极端(非确定性)情况至关重要,因为不可想象这种复杂性可以保存在一个人的大脑中。 由于血统执行在模型中的核心地位,观察者获得了对图2-8中显示的内容的整体可见性(但不限于此)。


在图论中,我们将其称为遍历(在遍历图时收集信息)。我将其称为精神震撼,因为观察者可以轻松地深入浏览信息的许多层,如图2-8所示,从血统到更改其中一个涉及的模式的用户。 但是,我们可以通过数据度量进一步扩展这种可见性。关于数据度量的一个令人兴奋的事情是,它有潜力以自下而上、可扩展和实时的方式支持数据质量。

数据度量

数据度量是可观测性中度量规格的一部分。在讨论可观测性时,数据度量通常是最常疑似的对象,因为它们在分析中很容易被利用来推断或预测(未来或依赖)事件,例如,使用它们与多元时间序列分析、马尔可夫链等的时间依赖性。

在数据可观测性的上下文中,我专注于我们可以直接与数据相关联的度量,例如描述性统计。然而,数据度量实体带有一个细微之处,可能对其有巨大的影响——度量始终与其分析使用(例如,转换)相关联。

数据度量的作用是向观察者提供关于在其消耗或生成期间数据的值在某些条件下是什么样子的信息。至少可以考虑三种度量类型:

  • 单变量

与所观察的数据源的一个字段/列相关的度量。例如:

列的描述性统计(例如,最小值、最大值、空值、级别)

分布(例如,密度、偏度)

公式(例如,平方和、乘积)

  • 多变量

多个字段/列的组合的结果。例如:

公式(例如,两个字段的乘积之和)

组合(例如,科尔莫哥洛夫-斯米尔诺夫)

  • 外部

与其他数据源的字段进行聚合的结果。这种度量非常复杂,甚至可以被认为是边界度量,因为它与关键绩效指标(KPI)或结果过于接近。

重要的是要注意,这些度量不旨在取代数据项目(例如,数据科学、分析报告)分析阶段所需的探索性分析。这些度量的目的是允许在其使用的上下文中理解数据,而不是在之前。换句话说,数据度量的主要用途不是为潜在用户提供他们可能发现的初步见解。

尽管如此,对于数据度量的潜在用户来说,获得对数据可靠性的信任至关重要,因为如果数据源在其他用途上是可靠的,那么他们自己的数据使用也很可能是可靠的。请记住,信任(特别是与数据质量相关的信任)需要时间,当数据的可靠性与真实且可理解的用途相联系时,信任会更加坚定。

因此,数据度量必须与暴露给观察者的数据源相连接,以展示行为(正确术语应该是状态)。在图2-3中,我展示了数据度量与模式相连接。这是因为度量高度依赖于数据源在使用过程中存在的字段。

最后,这些度量必须与数据源的使用相关联,由线性执行表示,该线性执行指示了数据源组合何时执行。这种连接具有前所未有的观察模型能力,使观察者能够了解数据系统的状态。例如,它允许观察者执行以下分析:

  1. 数据转化的百分比及其波动对输出的影响
  2. 在分析中涉及的数据子集(通过筛选器)的统计变化的影响
  3. 用于机器学习训练的数据使用时间段的增加及其对性能的影响(例如,一年与18个月的数据)。

这些是数据度量和数据可观测性模型的关键组成部分,它们使观察者能够更深入地理解数据的状态和行为。

到目前为止,我已经向您介绍了一个系统需要产生的观察结果,以被视为数据可观测。现在,我将扩展这种能力,以包括系统本身、其创建者或用户对数据的使用方式。

期望

到目前为止,我们已经介绍了系统需要生成的观察信息的类型和实体,以便让观察者能够了解数据在系统中的行为。

在这一部分,我将讨论数据可观察性的第三个组成部分,它涉及在数据不断满足其内容(例如,年龄可用,至少有10,000行)或行为(例如,从收入中减去支出是正数)的假设时创建可见性。这些假设通常来自业务规则、数据探索或仅仅是数据定义,它们指导了必须应用的转换。因此,当执行这些转换的应用程序被部署时,这些假设可以变成期望,因为它们似乎在开发过程中已经得到足够的验证,可以继续进入生产环境。

正如你将看到的,这些期望可以来自数据生态系统的不同部分(例如,用户、应用程序等)。如果期望对观察者可见,它将为观察者提供关于观察到的数据状态与其预期行为的对比的关键见解。

通过设置具体的期望,就像在软件开发中的测试一样,观察者可以更好地了解与期望一致的数据行为。此外,如果某些期望未能实现,观察者立刻知道需要关注的地方,就像测试报告告诉软件开发人员需要集中注意力的地方一样。

因此,它们提供了关于观察者期望发生的事情的可见性,代表了积极或消极的事件。例如,知道一个期望,比如“地址总是以数字开头”,对99%的条目来说是真实的,可以确保不能使用的数据只有1%。没有事故。它只为观察者提供两个信息:期望本身以及它是否为真或为假。另一方面,如果已知一个转换会失败,如果辅助数据不完整,那么当它变为假时,可以创建、触发一个事件,并做出相关的决策(例如,根本不执行转换)。

在设置期望时,您将希望既为数据的行为制定规则,又检测异常。下一节将讨论期望的这两个方面,以及应用程序如何成为其自身的观察者,并对数据行为的状态做出决策。

规则

规则是开发和监控中常用的工具;它基本上是一个函数,用于评估从数据中提取的信号(例如,行数、字段列表),并与一系列检查(例如,“> 10,000”)进行比较,这些检查编码和验证了期望是否得以满足。如果当前信号通过了规则,它将返回一个“true”响应;如果没有通过,它将返回一个“false”。函数的逻辑通常非常简单,因此很容易将结果与输入关联起来。例如,使用机器学习模型返回结果的规则更像是异常检测器而不是规则。

因此,用于数据可观察性的规则将使用由模式、数据度量、血统等传达的信息创建。例如,如果数据度量报告字段“年龄”的空值数量,一个规则可以是“年龄”的空值数量必须低于10,或者低于5%,甚至不能在两次执行相同血统的情况下增加超过0.01%。另一个使用模式信息的示例是“年龄”字段必须存在且为整数类型的X。

实际上,规则分为两类:

  • 单状态规则

这些规则仅在给定时间的系统状态信息上执行,就像示例中的要求“年龄”的空值必须低于10一样。状态信息也可以组合以创建内在检查,例如将空值数量与总数进行比较(例如不超过10%)。

  • 多状态规则

这些规则需要多个状态,例如一个或多个时间段的状态、连续状态或抽样状态。多状态规则甚至可以包括从可用状态中随机抽取的状态列表。

每个类别都可以分为单变量和多变量,当一个规则使用来自同一状态的一个或多个观测时。图2-9说明了这四种变体。


虽然观察模型的实体是根据可用信息计算或提取出来的,但规则则不太具体,需要更多的洞察力来创建。所需的洞察力可以来自多个来源,如:

  • 人类知识和经验
  • 系统的历史
  • 与其他系统的相似之处

让我们看看创建规则的两种方法。

明确的规则

明确的规则是由用户创建的,作为他们正在构建的假设的表示,他们期望这些假设在他们的应用程序运行并在生产中使用时保持为真。这些假设主要来自以下渠道:

经验:一个人对数据或所涉及的用例的经验是生成规则的绝佳方式,因为它基于过去的经验或应用知识。例如,业务规则以不同方式经验:作为对业务应该如何进行的限制,作为断言业务结构的一种方式,或作为控制或影响业务行为的方式。我还指的是基于多年经验形成的直觉或直觉,这些直觉或直觉是基于用例或实际经验(如网络等)形成的假设。但这并不意味着这些假设总是可靠的。一个人可能存在偏见或误解整个情况。然而,考虑到这些“直觉”假设仍然是值得的,因为它们比没有强得多,更重要的是,它们表达了用户的期望。然后,如果这些规则没有得到满足,由于系统的可观察性,团队可以进行分析以确定规则的有效性,并可能舍弃或调整它们。

探索:在使用数据创建管道、报告、特征和其他类型的数据转换时,人们将学习数据,或至少更好地理解数据。因此,将形成并将这些假设整合到基于这些学习的应用程序中。例如,如果数据没有重复项或营业额始终大于零,您可能会认为这些条件是真实的。然后,您可能不会明确地制定其规则,或者可能不会在要实施的业务逻辑中指定它们,尽管这些假设是规则的绝佳来源。帮助制定规则的这一过程的一种方法是创建数据概要文件(使用分析器)。分析数据会生成一系列从提供的数据中推断出的静态规则。但是,这些规则需要谨慎使用,并经过仔细审查,利用团队的经验来选择最合适的规则,同时避免引入规则过于接近手头数据并因此可能在生产中迅速失败的情况。使用数据分析仪的使用将在第6章中进一步详细介绍。它们将被称为扫描仪。

发现:当应用程序和数据正在使用时,可以发现新的案例,例如未知的未知(意外的案例)或边际案例(未考虑业务逻辑)。一旦发现,它们通常被视为需要分析和最有可能修复的事件。如第1章所讨论的,必须进行多个流程,例如根本原因分析、故障排除和影响分析,以确定和修复问题。流水线的每个阶段都可以发现(从历史中学到的)新规则的机会,包括在管道的不同阶段之间的事件之间的交互或因果关系(强、一致且不变的相关性)。

还值得注意的是,随着世界的不断变化(例如,产品被抵制、法律被调整和平台被升级),规则可能已经过时。因此,必须考虑对这些规则进行维护。我经常鼓励团队至少在使用或生产数据的应用程序的每个新版本中迅速审查规则,以便进行验证。验证规则需要一个简单的反馈流程;但是还有其他选择,例如使用辅助规则。

辅助规则

在前一节中,我介绍了完全是人工分析结果的规则。在这里,我将介绍一种替代方法,允许发现规则。 虽然规则不能基于非显式行为,但它们仍然可以通过简单的分析(例如,启发式方法)或甚至是学习(例如,关联规则挖掘)来发现。这些规则是在观察的协助下创建的,因此它们是“数据驱动的”。

辅助规则的强大之处不仅在于能够创建新规则,还能更新现有规则,甚至是显式规则。如果有效地完成,辅助规则可以减轻长期维护规则所需的负担。 引入辅助规则到数据可观察性系统的方法是保持人与系统的互动。因为规则在结构上是全面的,所以可以由拥有知识来审查、接受或拒绝这些规则的人进行审查。以这种方式验证规则对于提高规则的信任级别以及最终提高规则检测的问题准确性非常重要。例如,辅助系统可以估计(例如,基于自相关性)某个值似乎在19,945.62左右,并且标准差在783.09左右,因此可以提出一些规则,例如遵循某些分布,这些分布也可以根据观察估计或作为观察本身(例如Kullback–Leibler分布与一些分布的差异)。只要我们有足够的观察数据,可能性是无限的。也就是说,随着时间的推移,辅助规则还应该利用在发现过程中积累的知识,即在事后创建的规则,这些规则提供了如何预测未知事件的信息。

推荐和更新规则的机会是自动异常检测无法比拟的优势,我将进一步讨论这种方法。然而,这种异常检测通常不涉及人类,它们的控制程度较低,而且它们的随机性不会产生关于受控制的内容的高度确定性。为了提高和加强这种感觉,这正是数据可观察性的目标,我将首先讨论规则与服务级别协议之间的关系。

与服务级别协议(SLA)/服务水平目标(SLO)的关联

服务级别协议(SLAs)和服务水平目标(SLOs)已经存在了相当长的时间,用于建立合同,并且是避免关于服务预期质量的主观争议的一种方式。它们有助于建立和维护生产者和用户之间的信任关系,这对于双方都能够自信地参与有价值和可持续的关系至关重要。

这种关系也存在于数据领域。数据团队在某种程度上是一种服务;数据团队为专用用例生产数据,或者将其提供给未来使用。

因此,数据团队和数据消费者/用户都有期望,即使这些期望没有被明确表达、没有被记录下来,并且在涉及数据时也没有被直观地共享。这已经导致了我在第一章中提到的问题。SLAs和SLOs是消除这些问题的良好解决方案。

数据的SLAs是参与方之间的合同,包括可以满足的期望,如果不能满足,就会应用罚款或其他处罚。罚款/处罚的重要性可能与在期望未被满足的情况下经过的时间长度一样重要。因此,“检测时间”和“解决时间”等运营指标对于可持续成功至关重要。

要在数据中建立SLA,需要获取用户的意见,以确保服务质量足够高,使他们实际使用数据。在SLA中考虑越多的用户,服务就越好,服务水平就越高,关系就越好——只要确保期望的相关成本是可以接受的。

在制定数据的SLA时,需要考虑以下几个复杂因素:

  1. 如何定义约束 用户可能很难定义重要的约束,因为可能会有大量可能的约束条件。考虑到数据源中的每个字段都可以有10个以上的关联指标(例如,对于年龄字段,可以有最小值、最大值、平均值、标准差以及分位数、估计的分布、空值、负值等)。
  2. 数据的使用会有所不同 每个用户对数据都会有不同的用例,因此会有不同的期望和约束。
  3. 大量用户 随着自助数据和分析的普及,用户数量不断增加,从而创建了更多的数据用例和约束。

这就是数据可观察性至关重要的地方。数据观察可以用作服务级别指标(SLIs),通过提供有关数据和用户行为的足够信息,可以识别、辅助和维护规则。由于生产者和消费者都生成这些观察结果,因此更容易就SLIs中的哪些关键绩效指标应该用于确定数据团队可能满足哪些SLAs达成共识。这将为所有SLAs设定标准,同时保持为其他SLIs在SLAs发现过程中稍后使用的机会敞开。同时,生产者和消费者都可以将它们用作SLOs(或仅作为信息来源,例如通过通知系统)。

没有数据可观察性,如果考虑到可以在100多个列上计算的指标数量,乘以不同检查的数量,那么范围就太广了。这是如此之大,以至于对于双方来说,没有充分的证据证明它们的有效性,以及一种有效地随时间改进它们的方法,这似乎令人望而生畏,甚至不可能承诺一部分期望。

自动异常检测

规则是确保数据符合期望的一种强大方法,尤其是在数据使用的上下文中。然而,规则依赖于人们来创建和验证它们(至少我强烈建议如此)。对人们时间和可用性的依赖无疑是数据验证与数据规模成倍增长的瓶颈。已经达到高度成熟水平的公司需要考虑这一点。

此外,辅助规则在结构上有一定的约束,因为它们必须是明确的并且可以完全解释,这可能是相对于其他更不透明的解决方案(如基于学习的规则)的一个弱点。

考虑到规则的目的是拦截未达到的期望,我们还没有讨论的另一种方法是使用可用的数据可观察性信息进行自动异常检测。

异常是与预期状态不同的系统状态。这是显式编码为规则和隐式发现为不符合期望的期望之间的联系。

在我们的情况下,系统状态对应于基于核心观察模型的数据可观察性信息的历史记录。因此,这些状态也可以看作是具有许多随机但相关(非独立)变量的随机过程(每个实体的实例都可以视为一个变量)。

因此,自动异常检测是利用一些基于学习的方法来推断或预测何时应将状态视为异常的过程。

可以使用的方法有很多,包括机器学习:

  • 监督学习:这需要对数据可观察性信息(或状态本身)进行标记才能正常工作。因此,需要花费时间来收集足够的数据来训练算法,以及为团队提供标记异常的高准确度。
  • 无监督学习或统计分析:无监督学习方法可以帮助根据其统计属性识别异常。例如,统计学习方法可以自动识别异常值,并假设异常可能显示异常行为,从而在不需要详细的先验知识的情况下检测潜在的质量问题。
  • 增强学习和主动学习:这种方法非常先进,仍然需要团队的一些时间。代理需要进行大量模拟以进行验证,但主动学习实质上是依赖人在环中的。

我的意图不是深入讨论每种方法,因为这至少需要另一本书,而且每个主题已经有足够的论文和书籍了。然而,让我强调一下,尽管这些方法在理论上可以扩展,但它们仍然有一些不足之处:

  • 冷启动问题:为了使异常检测高效运行,需要数据和人来确保学习阶段的可靠性。
  • 黑盒担忧:迄今为止介绍的方法自动生成异常,但对于原因几乎没有信息。因此,团队必须重构上下文并理解原因。
  • 性能挑战:异常检测不能百分之百准确。因此,需要控制团队的性能,以避免警报疲劳,即团队开始忽略检测到的异常。

回到黑盒担忧,值得注意的是,已经付出了大量的努力来使机器学习模型具有解释性(这在我的谦虚意见中是分析可观察性的一部分)。这个挑战并没有完全解决,尤其是对于深度学习等方法来说。然而,密切关注这种能力的发展是减少黑盒担忧影响的必要途径。

我将在这一部分的最后提到另一种方法,这种方法很少被考虑用来解决黑盒担忧,它提供了规则和异常检测的有趣组合——有限状态机的学习。当数据可观察性信息不断增长,尤其是如果触发的规则也被标记为真阳性或假阳性时,这种方法可能是有希望的。

防止垃圾输入,垃圾输出

数据社区应该为反对“垃圾进,垃圾出”(GIGO)的借口而战斗的一个原因是,GIGO只是一种借口,而不是一种解释。当有人生气并询问为什么他们收到了无关紧要的信息时,唯一提供的答案是信息无关紧要,因为最初的数据本身就是无关紧要的。首先,它并没有解释任何问题,而是被视为对问题重要性的回避,不会建立信任,因为制作者并不觉得有责任尽力避免这种情况。坦白说,我们都曾经历过这种情况,而且都曾身处其中的双方。

换句话说,这是一种“推卸责任”的做法,害处大于好处。与之相反的观点是,如果一个应用程序能够意识到垃圾输入,它就应该禁止生成垃圾输出。要做到这一点,应用程序需要能够执行以下操作:

  1. 评估提供的数据是否为垃圾
  2. 将经分类的数据标记为垃圾

但为什么这种行为如此常见是一个有趣的问题。答案必须与在生产中的行为缺乏可见性以及对问题重要性的了解有关。此外,这种情况极度时间敏感,通常涉及一些权力不平衡(管理者-贡献者,买方-卖方,用户-提供者等),这使得情况非常尴尬。此外,受到这种批评的人有一种天然的倾向,认为他们必须能够解决所有情况并避免所有问题。让我们明确一点:这不是人们的期望。人们期望的是能够分析问题,并在理想情况下能够预见、恢复并保持信任,而不是避免一切!

当数据由外部来源提供并且我们对数据几乎没有或根本没有影响时,理解这一点尤为重要,在这种情况下,似乎不可能避免一切,同时又不能责怪制作者(我的意思是,指责制作者)。

好消息是,数据可观察性的第三个组成部分,即期望,满足了这些确切的要求。通过实施数据可观察性,以下是可能的情况:

  1. 输入数据在应用程序生成其结果之前被标记为垃圾。然后,应用程序可以选择: 不继续执行,避免生成垃圾输出 尽力清理数据,确保清理过程是可观察的,然后继续执行
  2. 根据结果的资格,将输入数据标记为垃圾。然后,应用程序可以选择: 回滚数据并记录 记录数据为垃圾的原因,因为事后发现垃圾 与第一种情况一样,尝试清理传入数据或其输出,仍然确保这些过程是可观察的

这种逻辑可以使用两个不互斥的过程来实现。第一个是使用条件。

前置条件和后置条件

条件语句在编程中常常被使用,比如在实现一个HTTP端点时。例如,如果端点的业务逻辑期望接收一个以UTF-8编码的JSON有效负载,其中包含在customer顶级字段下的非空整数age字段,并且这些条件没有得到满足,应用程序可以决定向客户端返回错误,或者在某些情况下,比如在继续之前重新编码,可以宽松处理编码。此外,如果HTTP端点的副作用是更新表并获取数据的当前状态,但它获取了多行而不是一行,它可以采取诸如回滚、删除或仅返回错误的操作,让客户端了解其可能发送的垃圾数据。

我刚刚描述的内容对于任何程序员来说都非常自然:它甚至不仅仅是最佳实践;它是直观使用的。因此,想法就是在创建数据应用程序、流水线等时直接使用这种模式。 在数据应用程序中直接实现前置条件和后置条件的有趣优势是,它受到良好的保护,无需依赖其他外部组件来确保其可行性。当然,用于构建数据的系统需要允许这种做法,而在某些系统中,尤其是低代码和无代码工具(例如ETL、报告工具)中,这种做法并没有被系统性地考虑到。

在下一节中,我将介绍电路断路器,从概念上讲,它们与此处描述的条件并没有太大的不同,但在系统尚未(或不支持)支持条件的情况下,在结构上提供了一种替代方法。

电路断路器

电路断路器起源于电气电路领域。在电气系统中,电路断路器是一种安全装置,旨在保护电路免受损坏。这个设备关闭电路,允许电流流动,直到满足可能导致电路断开的某些条件。在这种情况下,该设备会打开电路,禁止电流流通,直到解决了潜在问题并采取措施再次关闭电路。

这个想法被Michael Nygard重新应用于软件架构,并得到了Martin Fowler的支持。在软件架构中,一个额外的组件包装一个函数,以防止在某些条件下执行该函数。预防措施可以简单到在调用包装器时直接返回错误,并且电路处于断开状态时。

在数据管道中,这可能更多地是预/后条件的替代方案,特别是在用户无法在用于创建管道的系统中引入条件的情况下,例如在低代码无代码系统或受限制的界面(无论是图形界面还是API)。因此,系统在管道中有额外的组件(电路),以防止在不满足条件的情况下断开它。事实上,以这种方式实现的电路断路器类似于应用程序外部的预/后条件。

电路断路器的好处是它们更容易在事后添加(特别适用于遗留系统)。然而,它们也有缺点。例如,如果条件依赖于前后步骤(例如,特定用例的SLA/Os、自定义检查),那么电路断路器将是另一个需要维护并与步骤逻辑保持一致的应用程序。因此,电路断路器可能会存在于每个步骤之前和之后,这将使管道的长度变为原来的三倍。

总结

数据可观测性不是一次性的项目,而是需要所有数据从业者 embrace 的一种文化转变。通过养成习惯和在整个组织中标准化观察,数据可观测性变得自然而根深蒂固,成为数据文化的一部分。通过采用标准化的观察模型,组织可以增强团队和项目之间的沟通与协作。此外,数据可观测性引入了一个框架,用于利用观察来评估假设和验证期望。在下一章中,我们将深入探讨数据可观测性在组织中的影响,探讨其对体系结构和跨不同角色和领域的沟通的影响。

阅读量:2017

点赞量:0

收藏量:0