本章内容包括:
- 探讨推动 Fluent Bit 快速增长的因素
- 识别 Fluent Bit 的关键组件
- 回顾与 Fluent Bit 一起使用的技术
- 理解 Fluentd 和 Fluent Bit 之间的关系及区别
路易斯·卡罗尔在《爱丽丝梦游仙境》中写道:“从头开始”,所以我们将在本章中这样做。在深入细节之前,让我们花点时间了解一下 Fluent Bit,并回答一些关于它的重要问题,比如它为什么如此重要并值得写一本书,它在 IT 生态系统中的定位是什么。我们还将解决一个悬而未决的问题:Fluentd 和 Fluent Bit 之间的关系。
1.1 为什么 Fluent Bit 如此重要?
Fluent Bit 本质上是一个专门的事件捕获和分发工具。我们来详细拆解一下这个表述。为什么它是专门的?Fluent Bit 关注的是日志事件、指标和跟踪(有时称为信号):
- 日志 — 可以被看作是日志文件中的每条输出消息或每行,换句话说,是提供有关发生了什么的某些信息的文本字符串。消息可以是完全非结构化的,也可以是完全结构化并自我描述的消息。
- 指标 — 由我们的 IT 硬件和软件生成的测量值,通常是带有描述标签的数值。例子包括计算机中每个 CPU 核心的使用情况或每分钟处理的事务数量。
- 跟踪 — 跟踪是一组在我们软件执行过程中关键节点记录的值,通常与事务对齐。跟踪与日志事件有很多相似之处。关键的区别在于跟踪事件之间有关系,有时,跟踪信息直到事务结束或发生错误时才会共享。值得注意的是,跟踪标识符在应用程序的不同部分之间传递。随着 Kubernetes 和微服务策略的采用,跟踪变得更加重要,因为当正确使用时,它们可以使在分布式解决方案中跟踪发生的事情变得更加容易。
我们将在书中深入探讨事件数据的类型。处理各种事件的能力并不独特,但它确实使 Fluent Bit 区别于与之比较的技术,例如 Logstash(www.elastic.co/logstash)。
因为 Fluent Bit 响应并处理事件,通常是在接收或从文件等来源跟踪到事件时,接近实时地进行,因此它被描述为事件驱动的。为什么我们需要 Fluent Bit 是事件驱动的呢?毕竟,当出现问题时我们才会查看数据。虽然我们可能采用传统方法,在有人声明存在问题时查看日志,但人们仍然喜欢看到接近实时的统计信息和指标。我们还应该记住,我们可以从日志事件中推导出有意义的、时间敏感的指标。在我们的代码中,我们关注的是当软件做了一些可能引起兴趣的事情时的事件,以确认一切正常、理解所采取的决策分支,或者找到应用到数据的计算的答案。即使是由调度程序触发的监控解决方案,我们也希望日志、事件和跟踪能在仍然有意义时提供。
那么这只是一些聪明的词汇,针对一些普通的事情?看起来可能很容易这么想。可惜,这种思维方式可能会导致我们错过 Fluent Bit 提供的丰富可能性和机会,这些可能性能让我们的生活变得更加轻松。例如,如果我们把日志事件仅仅看作是代码中的一块文本,我们可能忽视了我们可以从中推导出含义,并判断是否需要立即采取其他措施。如果事件是一个健康检查,表明一切正常,我们可以将数据发送到操作仪表板,不做更多处理。但如果事件报告接收到一个大而格式错误的负载,它可能表明一个更严重的问题,需要在用户开始投诉之前立即干预。
1.1.1 事件分发的价值
解决识别(并可能需要解决)系统问题的痛点对我们每个人都有益,无论我们是团队的一部分,工作在实践某种变体的 DevOps 环境中,还是作为操作前线的多层支持系统的一部分,或是作为最后一环的开发人员处理测试问题。
当问题到达我们时,我们需要知道发生了什么,或者更好的是,能够在问题发生时与其互动。问题可能是一个严重的系统故障,或者是关于某些事物或某人如何与我们的系统交互的问题。为了应对这些问题,我们必须能够获取这些信息,并拥有适合我们需求的工具。
我们需要的信息可能像完整的日志消息一样简单。通常,我们需要了解在关心的事件发生前、发生时和之后发生了什么,以建立因果关系。(例如,数据库可能因为我们存储空间不足而产生错误。我们是不是因为清理过程失败而导致存储不足,还是忽视了监控存储容量的需求?)我们需要从许多不同来源捕获和聚合数据。日志、指标和跟踪是可观测性的构建块,而监控数据(日志、事件和跟踪)通常是瞬时的。使用 Fluent Bit 和类似的工具可以让我们从所有来源收集数据并将其存储在安全的地方。根据我的经验,当问题严重时,人们通常不会担心保存状态信息、日志等。他们关心的是恢复操作状态,这意味着生产环境中的日志和存储的指标可能很容易被丢弃。
聚合日志事件不仅仅是减轻数据丢失的风险,还帮助我们看到完整的画面。例如,COBOL 解决方案通常由多个按顺序运行的程序组成。处理过程是顺序的,但分布式过程已经是可能的。随着技术的发展,我们采用了并行运行的二级或三级解决方案(通常是应用程序和数据库服务器,具有独立的用户界面)。即使我们操作的是单体应用程序服务器,工作也可以分布到多个虚拟化负载均衡的服务器上,而微服务的采用进一步推动了分布式架构的爆发。为了理解发生了什么,我们需要将这些分布点上所有的事件汇集起来,才能准确了解发生了什么。
除了能够保存有助于诊断问题的信息外,我们还容易忽视一个挑战:我们从问题到诊断所花费的时间越长,可能发生的损害就越大,因此,恢复过程变得越痛苦。无论是修复失败的事务,还是解决安全漏洞的规模,通过实时处理指标和日志,我们可以自动评估它们是否指示当前发生的问题,或者更好的是,指示一个即将发生的问题。因此,我们可以减少痛苦,因为我们避免了问题的发生或将问题的影响降到最低。
轻松分发数据的能力还使我们能够为不同的任务采用不同的工具。如果数据难以分发,我们最终只能采用最低公分母的工具,或者采用那些支持使用数据的最强势团队的工具,而不是那些解决不同需求的工具。例如,PagerDuty(www.pagerduty.com)非常适合根据识别出的系统和一周中的时间来通知合适的人员。
1.1.2 Fluent 在 CNCF 中的位置
Fluent 工具,包括 Fluentd 和 Fluent Bit,是云原生计算基金会(CNCF;www.cncf.io)生态系统中的关键角色,帮助我们收集、保护并理想地分析日志和指标。这些解决方案使我们能够以另一种工具能够呈现并易于消化的格式获取可观测性数据(日志、跟踪和指标)。正如我们将看到的那样,Fluent]() Bit 在采用和支持最新可观测性标准和工具方面,比 Fluentd 产生了更大的影响。
在 CNCF 内,项目根据其流程、质量、成熟度、支持和采纳情况进行分类。像 Fluentd 和 Fluent Bit 这样的毕业项目需要来自多个组织的贡献者,并且其流程需要展示良好的项目治理和开发过程。最重要的是,这些项目需要有多个公开的采用者,以便更广泛的社区可以确信,采用的项目不太可能在一夜之间被放弃。
1.2 Fluent Bit 的核心概念
我们已经讨论了 Fluent Bit 的重要性。现在,让我们来看看一些核心概念,这些概念影响了 Fluent Bit 几乎每个方面。我们遇到的最关键的概念是事件。我们还应该考虑 Fluent Bit 做了什么和没做什么,以使事件更有用。
Fluent Bit 中的另一个关键概念是插件。随着书的深入,我们将更详细地探讨插件,但在这一阶段,我将它们描述为 Fluent Bit 功能能力的构建块。
1.2.1 载荷结构
为了与 Fluent Bit 的事件(无论是日志事件、跟踪还是指标)交互,我们需要理解每个事件在 Fluent Bit 中是如何表示的,这与 Fluentd 的方式相同,包含三个必需的元素。如图 1.1 所示,Fluent Bit 有三个核心元素,并且有一些目前对我们来说不透明的附加元素:
- 元数据 — 元数据是一个包含键值对的列表,其中包含一个名为 Tag 的必需键及其相关值。Tag 是与事件相关联的逻辑名称。我们使用 Tag 来将事件路由到正确的操作。随着书的推进,我们将介绍一些策略,使我们能够操作 Tag,并利用智能命名约定来帮助我们。在 Fluent Bit v1 和 Fluentd 中,元数据仅仅是 Tag。为了增加灵活性并允许 Fluent Bit 承载其他类型的事件(和跟踪),Fluent Bit v1.9 对元数据进行了修改,使其能够包含关于记录内容性质的额外键值对,例如事件类型。正如我们稍后在书中所看到的,我们可以访问 Tag 值,而无需提到它是元数据的一部分,就像 Fluent Bit v1 和 Fluentd 中那样。
- 时间戳 — 没有时间戳的事件价值有限。没有时间戳,我们无法判断问题是当前的问题还是新出现的问题,因为我们不知道事件发生的时间。我们也无法判断事件是原因还是结果,因为我们不知道事件发生的顺序。因此,许多输入插件提供了一种方式,用于找到事件中正确的时间戳位置,或者在接收到输入时将该时刻应用为时间戳。
- 记录 — 记录包含事件数据(日志、指标或跟踪)。在各种插件中访问和操作记录的能力取决于插件类型和描述记录的元数据。当记录包含日志时,Fluent Bit(取决于输入和解析)将记录的值视为键值对的列表或单个文本块。我们可以提取内容并将载荷转换为 JSON 等格式。当我们不处理事件时,记录会通过使用 MessagePack(msgpack.org)库进行序列化以高效存储。(附录 B 中有关于 MessagePack 的更多细节。)
元数据还可以表明记录表示指标或跟踪。在这种情况下,记录具有以下特点:
- 指标 — 当我们发送和接收指标时,数据遵循 Prometheus 格式(非 JSON 结构)。但是,Fluent Bit 提供了检索和操作指标数据的手段。在内部,指标由一个名为 CMetric 的库处理,其他项目也开始使用该库。
- 跟踪 — 跟踪也作为特殊的记录载荷进行处理,可以将其转换为记录并与之交互。
随着我们探索这些数据源,我们将更详细地讨论这些方面。虽然当前内容在可见记录和不透明结构之间的移动并不完全自由,但笔者认为,随着时间的推移,处理这一移动将变得更加容易。
图 1.1 显示了 Fluent Bit v1.9 及更高版本的数据结构,以及相应的 Fluent Bit v1 和 Fluentd 结构。尽管差异较为细微,但在处理非日志事件时是显而易见的。值得注意的是,在 Fluent Bit v1.9 之前的版本中缓存日志事件文件的特殊情况下,尝试使用 Fluent Bit v1.9 之后的版本读取这些缓存文件会导致错误。
1.2.2 逻辑架构
图 1.2 显示了 Fluent Bit 的架构。我们将在全书中使用这个图示,帮助我们了解在 Fluent Bit 中探索的各种功能。该图展示了以下逻辑组件:
-
输入插件(监听器),输入插件(拉取) — 许多 Fluent Bit 的表述没有区分输入插件的类型。尽管插件与 Fluent Bit 核心(管道处理)之间的契约没有改变,但插件实现方式的不同会影响配置和调优的考虑。面向网络的输入可以描述为监听器;我们连接到网络,当接收到数据时,我们必须处理它。这里的大量突然激增可能会导致背压;调用 Fluent Bit 的源系统无法继续,直到我们消费掉事件。
拉取事件,如捕获文件中写入的日志事件,要求我们定期轮询文件,以确定是否有新的内容被添加。输入插件的实现可以决定系统的吞吐量。
-
自定义输入插件 — 这一功能可以被描述为拉取或监听插件。由于我们支持通过 HTTP 获取网络源,除非我们有一些特定的编码,最好通过输入插件而不是解码器(解析器特性提供的功能)来处理,否则该功能可能采用拉取模型。自定义插件与其他插件的区别在于,它不是标准 Fluent Bit 版本的一部分——任何由第三方直接嵌入到二进制文件中的插件,或者通过扩展选项构建的插件,我们将在 1.3.3 节中讨论。
-
解析器 — 解析器提供了将接收到的内容转换为有意义数据的手段,例如从记录中提取重要的值或将其转换为 JSON。有许多预构建的解析器可供使用;这些解析器中的许多是正则表达式的专业化。解析器通常与过滤器结合使用,但一些输入插件也可以使用它们。
-
缓冲区 — 根据插件的不同,缓冲区可以在多个地方使用。从逻辑上讲,缓冲区非常适合此处,因为缓冲区的主要目标是让我们适应可能出现的输入和输出性能差异,例如源输出的激增或输出消费的减慢。因此,缓冲区防止了 Fluent Bit 成为潜在的吞吐量瓶颈或数据丢失点。如果你对数据丢失的风险比较敏感,你可以将缓冲区切换为使用文件存储,这样在 Fluent Bit 进程重启时可以读取文件。此方法确实有性能成本。缓冲区有一个存储接口层,用于管理进出缓冲区的数据及其物理实现(文件或内存);它还与任何相关的流处理器交互。
-
过滤器,自定义过滤器 — 过滤器是管道的重型工具,提供了与接收到的事件交互和操作的手段。过滤器获取并将它们处理的事件返回到缓冲区。普通过滤器完全由配置驱动,但自定义过滤器可以通过两种方式实现:
- 典型的方法是调用 Lua 脚本。
- 我们可以使用 C、Go 和 WebAssembly 实现更复杂或更有挑战性的过滤器,遵循自定义输入和输出插件的方式。
-
流处理 — 流处理表示我们如何配置新的高级分析功能。我们可以将来自此分析过程的数据重新输入,以便利用分析值来丰富处理,例如基于接收到的事件创建时间序列数据。
-
输出插件,自定义输出插件 — 与输入插件一样,我们将这些插件类型分开,以突出其可扩展性。输出插件的作用是从缓冲区获取事件,然后将其存储或传递给第三方解决方案进行后续处理(这可能是数据存储,但我们也可能输出到其他 Fluentd 或 Fluent Bit 实例,以委托或聚合工作),具体取决于插件的实现。
我们比官方文档更细致地定义了逻辑组件,以帮助你理解它们的行为特征。官方文档主要集中在输入、过滤器和输出——图 1.2 中的四个横向组中的三个。
1.3 Fluent Bit 采用的驱动因素
使 Fluent Bit 成为一个重要参与者的驱动因素归结为几个关键因素:
- Fluent Bit 的实现方式 完美地满足了云计算和云原生行业对于小体积、高效性和快速启动的需求,使其更容易利用容器化环境的弹性。
- Fluent Bit 能够满足 OpenTelemetry(通常称为 OTel) 的快速加速和采纳,将日志处理、指标和追踪结合在一起,协调了我们观察应用程序的不同方面。因此,像跨多个服务和服务器跟踪单个事务等任务可以实现标准化。
- Fluent Bit 提供了对其他主流云原生技术的开箱即用支持,特别是用于支持监控和可观测性的技术,如 Prometheus 和 Grafana 的 Loki。
还有一些其他因素也可能在发挥作用,但这些趋势较难明确区分:
- 对流处理和流分析方法的支持 在 Apache Kafka、Spark 和 Beam 等技术中有所体现。虽然 Fluent Bit 当前可能没有直接影响其采纳,但它未来可能会带来差异。流处理在云计算和云原生领域中更为显著,但根据如何解决这个问题,它可以为各个行业和技术领域带来监控和可观测性方面的收益,无论新旧。Fluent Bit 的流处理能力使其能够变得更加动态并适应实际发生的情况——这是我们将在第 8 章中进一步探讨的流处理概念。
- 监控领域的主导者之一是 Fluent Bit 的“前辈” Fluentd。我们可以将其主导地位归因于多个因素,例如早期进入市场、成为 CNCF 的一部分,或者通过其自定义集成轻松地将新的数据源和目标插件接入。Fluent Bit 拥有这些所有优势。此外,Fluent Bit 能够与 Fluentd 部署透明地进行通信,消除或最小化在 Fluentd 和 Fluent Bit 之间过渡时的干扰,并根据需要在整个组织中混合部署两者。
1.3.1 小体积、高效性和速度
Fluent Bit 可能最初是支持物联网(IoT)用例的,但物联网所需的特性与云原生,特别是容器和 Kubernetes,非常契合。首先,通过像 Kubernetes 这样的编排引擎最大化容器的动态扩展,使得应用程序设计为运行在小体积的环境中(通常在物联网设备上需要这种设计),从停机到快速运行变得异常简单。此外,考虑到容器本身的开销,任何能减少 CPU 和内存消耗的方法都是可取的。一种方法是使用预编译的本地二进制文件(有时称为预先编译 [AoT])。这种方法消除了运行解释器层的开销(例如,在加载任何应用逻辑之前启动解释器所需的时间,以及解释器的额外内存需求)。使用即时编译器(JIT)有助于性能,但仍然有编译开销,这在使用 JVM 等语言虚拟机时可以看到。由于 Fluent Bit 是用 C 语言编写的,它始终编译成二进制文件,因此没有任何开销。Fluent Bit 的快速扩展、资源高效和高性能意味着,它已经被包括 Amazon Web Services(AWS)、Azure、Google 和 Oracle 等云服务提供商采纳,也被 LinkedIn 和 Lyft 等云服务公司采纳,因为这些特性为他们节省了成千上万美元。
虽然 Fluent Bit 非常紧凑,但它能够扩展以处理工作负载,并提供控制选项,使输入和输出能够在不同的线程中运行。分离输入和输出操作减少了背压影响多个输入的机会。Fluent Bit 中的线程控制选项还可以增加吞吐量。然而,在容器化环境中工作时,我们需要小心使用线程;我们不再有保证的 CPU 核心分配,更多的线程可能会导致实际 CPU 执行更多的上下文切换,从而影响性能。
1.3.2 OpenTelemetry 的影响及 Fluent Bit 与 OpenTelemetry 的关系
在 OpenTelemetry(OTel)之前,影响指标、跟踪和日志的可观测性的主要规范来自于 CNCF 内部的几个标准化努力,这些规范以 OpenTracing(opentracing.io)、OpenCensus(opencensus.io) 的形式出现,另外,凭借其主导地位,Fluentd 及其关联的 Fluent Bit 在日志结构上也起到了重要作用。不同的标准通常需要不同的工具来捕获这些数据。Fluent Bit 一直以来都能捕获一些指标数据;物联网(IoT)生态系统需要保持软件体积小,因此一个服务捕获日志和指标是首选。由此,Fluent Bit 捕获不仅仅是日志,还包括本地指标(如 CPU、内存和存储使用)的做法是合乎逻辑的。将所有这些数据源汇聚到一起,推动了操作监控的简化,导致了其快速的采纳,并且证明了其具有颠覆性。
Fluent Bit 对 OpenTelemetry 标准的支持及其在 OTel 生态系统中的工作能力并没有要求进行激进的改变,尽管这推动了其实现部分的升级。从某些方面来看,这些升级只是将 Fluent Bit 原本已经在做的事情进行了正式化。通过这一对接,Fluent Bit 很好地支持了 OpenTelemetry 标准的采纳,而不是强制实施它们,使得其采纳过程更加渐进。
当我们深入探讨 Fluent Bit 的输入和输出能力时,我们将进一步研究 Fluent Bit 与 OpenTelemetry 以及观测领域领先产品的关系,如 Prometheus(prometheus.io),它帮助推动了 OTel 向前发展,以及 Grafana(grafana.com/grafana)。我们还将讨论一些商业供应商,他们致力于支持 OTel 标准,创造了一个快速增长的可连接监控工具生态系统。
注意:如果你需要快速查找缩略语和术语的参考,可以在 opentelemetry.io/docs/concep… 找到方便的术语表。附录 B 也列出了几项优秀的资源。
OTel 的核心是 OpenTelemetry 协议(OTLP),它详细描述了遥测数据的数据结构、编码和传输。目前,OTLP 支持使用 gRPC(远程过程调用)与 HTTP/2 配合使用,使用协议缓冲(Protobuf)和 JSON 来同步传输。OTLP 提倡使用 gRPC 作为首选通信方式,使用 JSON 作为降级或后备方式。
OTel 作为一个项目,远不止于定义 OTLP。它还提供了标准中描述的功能的实现(有时称为参考实现),以及工具和库。这些工具和库是用多种语言实现的;我们可以使用它们帮助将逻辑注入到应用程序中,并快速使数据应用程序生成跟踪。OTel 还具有诸如日志附加器的功能,允许日志框架使用 OTLP 规范发送日志。
为了理解 Fluent Bit 如何适应开放遥测解决方案,我们来看 Fluent Bit 在 OTel 术语下能够做什么(opentelemetry.io/docs/concep…)。鉴于其能够从不同来源收集监控和可观测性数据并将其转换为 OTLP 结构,Fluent Bit 可以充当 OpenTelemetry Collector 的角色。因为 Fluent Bit 是为分布式环境设计的,并且能够将数据以 OTLP 格式传递给任何其他符合 OpenTelemetry 的收集器(这可以是 Fluent Bit 节点或其他产品),我们可以将 Fluent Bit 描述为能够充当 OTLP Exporter 的角色。
图 1.3 显示了 Fluent Bit 如何适应 OpenTelemetry 环境,具备处理由应用程序生成的日志(L)、指标(M)和跟踪(T)的能力,无论是否借助 OTel 库或工具,以及它与 OpenTelemetry Collector 交互的能力。
由于 OTel 提供了收集器和导出器功能的实现,将 Fluent Bit 称为 OpenTelemetry 收集器或 OpenTelemetry 导出器可能会引起混淆。标准本身被称为 OTLP,因此称 Fluent Bit 为 OTLP 兼容的工具更为清晰,即使这并不直接表明我们可能部署 Fluent Bit 执行的任务。此外,在 OpenTelemetry 社区中,对该项目自己实现的收集器(称为 OpenTelemetry Collector)与其他实现该功能的工具之间的差异存在一些敏感性。我们倾向于将 Fluent Bit 描述为 OTLP 收集器(毕竟,协议兼容性是收集器功能的关键),以减少 CNCF 项目之间的歧义。
协议缓冲区(Protobuf)
协议缓冲区是 gRPC 的关键技术,而 OTel 使用了 gRPC。协议缓冲区有一个简洁定义的 schema,它与 Protobuf 工具一起使用,用于生成发送和接收载荷的代码。一个定义良好的 schema 使得工具能够创建生成压缩二进制载荷表示的代码。这个 schema 既是优点,也是潜在的限制。优点来自于高效的载荷传输。缺点是,schema 的变化会影响提供者和消费者,使得实现容错读取器集成模式变得更加具有挑战性。此外,由于 Protobuf 生成的载荷是压缩的二进制格式,它更难以注入到任何可以进行转换的通信中间件中。有关 OTel、Protobuf 和相关技术的链接请参见附录 B。
随着我们继续阅读本书,我们将更详细地研究 Fluent Bit 和 OpenTelemetry 如何执行不同的功能。请注意,Fluent Bit v3 之前,OpenTelemetry 协议的支持仅限于 HTTP 和 JSON。版本 3 带来了增强功能,支持 HTTP/2,使 Fluent Bit 能够使用 gRPC。这意味着 Fluent Bit 可以提供完全兼容的 OTLP 实现,而不需要依赖于降级到 HTTP 和 JSON。
1.3.3 使用 C、Go、WebAssembly 和 Lua 扩展 Fluent Bit
扩展 Fluent Bit 核心功能的能力非常重要。Fluentd 为此需求构建的第三方插件数量清楚地展示了这一点。除了源和目标,针对过滤等操作的小块自定义逻辑也是必需的。对于输入、输出和过滤器,我们可以通过 C、Go(也称为 Golang)和 WebAssembly(WASM)连接预编译的解决方案,这些可以进一步增加我们在实现中使用的语言选择,并提升解耦性。
由于过滤器通常需要更快捷、简便的方式来定义小段逻辑,使用 Lua 作为脚本语言是一个明智的选择。我们将在第 9 章中探讨这些技术以及不同方法的优缺点。
1.3.4 Fluent Bit 与流处理
实现处理逻辑,以便事件通过管道流动并进行处理,这一目标并不新鲜。随着软件框架的发展来支持这一目标,我们看到了现在称为流处理或流分析的复杂事件处理(CEP)。可以说,我们已经拥有了基本的流处理形式,例如服务总线(www.devx.com/terms/enter… Fluentd 和 Fluent Bit 也提供了基本的流处理能力。发展的是我们如何看待流处理和流分析。今天,我们可以识别流处理和分析的几个独特特征:
- 数据量大 — 我们试图推动通过管道的大量数据是流处理的一个关键特征。Fluent Bit 对这些数据量并不陌生,但我们希望处理的这些数据量要求服务总线具备巨大的规模来满足这些需求。此外,服务总线需要应对更高的复杂性,例如跨多个系统的数据完整性问题——这通常不是流处理的难题。
- 使用 SQL 来操作数据 — 当我们关注数据时,使用 SQL 是处理数据几乎通用的方法。如果我们能通过 SQL 来表达对日志事件的检查,那么数据会变得更加可访问。
1.3.5 OTel 与 Fluent Bit 和 Fluentd
我们应该强调的是,在考虑使用 Fluentd 或 Fluent Bit,甚至 Fluent Bit 或 OTel 时,答案不必非此即彼。从一开始,Fluent Bit 和 Fluentd 就被设计为可以轻松无缝地进行通信。由于 Fluent Bit 和 Fluentd 解决方案内部结构化其载荷的方式,我们可以将一个 OTel 载荷包裹在 Fluent 模型中,并再次解包。回答关于 Fluentd 的问题的关键在于 OpenTelemetry 的采纳,它不仅仅适用于微服务用例,还取决于额外适配器的开发速度。
在我看来,未来几年内,新的开发将基于 Fluent Bit,因为那些曾考虑过 Logstash 的开发者可能会转向 Elastic APM 代理(mng.bz/x6n6)。然而,在生… Fluent Bit 取代 Fluentd 的变革速度较慢。现有软件变化的最可能驱动力将是 OpenTelemetry 的采纳。即便是小的体积节省,经过高度扩展的 OTel 解决方案也将创造可衡量的成本节约,或者使解决方案达到可以替代或重大改造的地步。
通过 Fluent Bit 捕获的数据,我们可以解析半结构化内容,从事件中提取更多含义,从而允许下游执行更为有根据的操作。这个过程可以简单到从一些文本中提取一个值,例如是否日志条目包含错误,或者提取一个数值供 Prometheus 使用,或影响事件的路由。这个过程也可以复杂到将自定义格式转换为 JSON 表示。
自然的下一步是过滤事件,可能是在事件不重要时丢弃它们,或将其路由到一个或多个输出。我们可以将数据发送到中央日志仓库,并将事件的数值元素传递给 Prometheus 作为度量。
将数据以事件组的方式传输,比逐个传输事件更为高效。每个会话的开始和结束都会有一些小的开销,例如打开和关闭网络连接,或者打开和定位文件的结尾,然后关闭文件句柄。缓冲或分组事件有助于我们在这些活动中进行权衡,这是缓冲区的一个作用,无论它们位于何处。因为缓冲区可能不是简单的内存结构,所以最好在过滤之后进行缓冲,这样如果缓冲区涉及到管理我们内存中的数据以外的内容,我们就可以最小化工作量。
最后一步是将事件存储到某个地方。这可能是另一个 Fluent Bit(充当 OpenTelemetry 节点或简单的日志事件处理器)或 Fluentd(利用其更丰富的插件选项或现有部署的监控基础设施),也可能是已连接的支持数据存储或自定义输出之一。
图 1.4 展示了我们架构视图的扩展,添加了一些示例源、目标和技术,使我们能够增强 Fluent Bit。此图强调了 Fluentd 和符合 OpenTelemetry 的工具的灵活性与兼容性,以及与多种其他应用和技术的多样化兼容性。
你可能已经注意到,Fluent Bit 并不处理数据的展示或可视化。这归结于一种理念:应用程序有一个单一的责任:做好一件事。对于 Fluent Bit 来说,这件事就是从需要被观察的地方获取可观测性数据,并将其传输到允许我们可视化和分析数据的工具中。
如果你熟悉 Fluentd 的架构,你会发现,尽管它们使用了不同的技术,架构在这一层抽象层次上是相似的。这种相似性反映了这两个解决方案之间的关系,并且是事件处理的一个简单真理。
1.4 Fluent Bit 是 Fluentd 的子集还是继任者?
虽然 Fluent Bit 最初作为 Fluentd(www.fluentd.org)的兄弟产品出现,支持 OTel 和其他功能是在 1.x 版本末期和 2.0 版本中加入的,但可以公平地说,它已经成长为与 Fluentd 平起平坐的产品。这一事实引发了几个问题:
- 我是否需要学习 Fluentd 才能学习 Fluent Bit?
- Fluentd 是否已经成为过时的解决方案?
要掌握 Fluent Bit,你不需要了解 Fluentd 的任何内容。但如果你对 Fluentd 有一个高层次的了解,你会发现掌握 Fluent Bit 变得非常容易。两者之间没有依赖关系。在许多方面,尽管这两个产品有很多重叠,它们是互补的。
至于 Fluentd 是否是过时的技术,这是一个架构性的问题。答案总是:“这取决于。” Fluent Bit 中包含的驱动程序和功能意味着它非常适合现代的以 Kubernetes 为中心的云原生生态系统,具备解决该生态系统所有需求的能力,尽管一些功能当前在 Fluentd 中不可用。如前所述,Fluent Bit 的体积更小、更轻便,适用于容器化的用例。另一个因素是 OpenTelemetry 的支持。在撰写本文时,我们尚未看到 Fluentd 的路线图,来为其添加 OTel 支持,这使得 Fluent Bit 成为在容器编排环境(如 Kubernetes)中部署,并与诸如 Istio 等服务配合使用的最佳选择。我们并不排斥在非云原生环境中部署 Fluent Bit,这些环境通常有更多的技术组合可以使用。考虑到 Fluentd 可用的适配器数量,这种情况在可预见的未来更适合使用 Fluentd。创建自定义插件所需的技能也更容易获得,你只需要掌握 Ruby 或其他具有内存管理功能的面向对象语言,如 TIOBE 指数中列出的语言(www.tiobe.com/tiobe-index)。虽然 WASM 可以支持用 Java 和 Ruby 等语言扩展 Fluent Bit,但它要求掌握额外的技能,尤其是对于仍在向主流证明自己的技术而言。
至于 Fluentd 是否已经成为历史,答案是否定的。主要供应商长期以来一直在投资并使用 Fluentd,这种投资不是轻易放弃的。此外,Fluentd 和 Fluent Bit 使用不同的技术,尽管它们有一些共同的理念,但它们以不同的方式执行这些理念。许多 Fluentd 的关键贡献者也在 Fluent Bit 的开发中工作。这两个解决方案都在推动前进,以满足 CNCF 生态系统所需的需求和创新。云原生的理念和 CNCF 正在影响软件的世界;并非所有云软件部署都与 Kubernetes 紧密绑定。简而言之,Fluent Bit 可以做很多事情,并适用于许多用例,但今天,Fluentd 更适合某些用例,反之亦然。
注意:Fluent Bit 的名称拼写曾有过波动,有时写作 Fluentbit。两种拼写是可以互换的。fluent-bit 和 Fluentbit 也曾用于代码和可执行文件中。但是,官方正确的拼写是 Fluent Bit。
1.5 我们将如何探索 Fluent Bit
本书的章节顺序旨在帮助你快速入门,首先关注源和目标,然后逐步介绍更高级的功能,如过滤和创建插件。我们希望本书既能为 Fluent Bit 的新手提供一个指南,也能为新老用户提供一个参考资源。像一个好的导游一样,我们将在穿越 Fluent Bit 的功能时回顾 Fluent Bit 的历史,并探讨它如何影响今天的应用。我们将通过现实世界的应用案例来查看最常见的配置场景。这些场景不仅仅是点击这个、输入那个、然后看到结果;我们会解释发生了什么,以及为什么会发生。毕竟,了解事物的工作原理,能让你更容易推导出新的配置和其他用例。
每个场景都有一个工作解决方案,存储在 GitHub 仓库(mng.bz/vJKa)和 Manning 的书籍下载包(www.manning.com/downloads/2…)中,我们将在书中描述如何运行这些场景。随着示例的深入,我们可能不会在书中展示每一项配置——只会展示与当前主题相关的部分。完整的配置可以在 GitHub 仓库中引用的文件中找到。
就像导游不会在带你参观每个展品时解释每一个细节一样,我们也不会深入探讨 Fluent Bit 的每个边缘案例。作为导游,我们会提供让你在自己时间里深入探索不同方面的工具。为此,我们在附录中提供了几个资源。附录包括本书中使用的工具的设置说明,以及进一步阅读的参考资料、工具、查询信息和示例。
每一章中的场景有时会在逻辑上从前一章发展而来,随着内容的逐渐复杂化,我们会展示不同的可能性。但请放心——如果你需要跳回某一章,你不必从头开始。每个场景的配置都是独立的。我们还会给你一些额外的挑战;答案可以在可下载的内容中找到。这些挑战允许你在没有现成答案的情况下,尝试不同的 Fluent Bit 配置方式。
最大挑战可能是创建现实的日志行为。我们将通过使用一个 LogGenerator/LogSimulator 来解决这个问题,它可以创建不同的日志事件。有关该工具的更多信息,请参见附录 A。
1.5.1 本书将涉及多少 Kubernetes 内容?
行业对 Kubernetes 的引用方式可能会让新接触这项技术的人感到困惑。准确来说,Kubernetes 是一个编排器,用于一组符合其 API 的技术。我们在提到容器时常常谈到 Docker,但实际上指的是符合开放容器倡议(OCI)标准的容器及其相关容器引擎。像 Kubernetes 这样的产品名称是对更广泛生态系统的简称,而不是容器编排的具体细节。在本书中,我们致力于从更广泛的角度使用 Kubernetes,当我们谈到 Kubernetes 的特定部分时,我们尽量使用具体的组件名称。
许多人希望了解 Fluent Bit 在构建和操作容器化应用程序中的应用。使用 Fluent Bit 来监控容器化应用程序,只需要对容器如何被编排有一个基本的了解。同样,10 年前,监控运行在由 VMware 管理的环境中的应用程序只需要对虚拟机(VM)有一个基本的了解。例如,几乎没有人需要知道 VMware 如何在服务器集群内迁移虚拟机,或者 Kubernetes 如何在集群中迁移容器。除非你在创建 Kubernetes 控制器,否则应用程序不应该关注其容器或虚拟机外部的世界。
如果你想详细了解 Kubernetes 日志和可观测性,建议查看专门的 Kubernetes 书籍来理解其管理(附录 B 中提到了几个资源)。我们中的大多数人会从一个准备好的 Kubernetes 集群开始,这些 Kubernetes 环境通常是有观点的;比较 OpenShift、Tanzu、K3s、Minikube 和云服务商的设置,你就能看出不同之处。许多准备好的 Kubernetes 部署会告诉你它们是如何配置的,因此查看它们的文档是很值得的;有时会有预配置的 Fluent Bit 设置,来在最低层次上监控 Kubernetes,因此问题在于如何在此功能的基础上进行构建。考虑好这个问题后,可以回到本书,看看如何使用 Kubernetes 生成的事件,并应用 Fluent Bit。
我们在本书中使用容器,但为了简化内容并强调 Fluent Bit 不仅仅是 Kubernetes 的工具,我们将专注于在本地运行 Fluent Bit。这种方法意味着我们在掌握 Fluent Bit 配置时不必担心容器配置。它还帮助我们看到 Fluent Bit 可以与更传统的应用程序部署一起工作。
1.5.2 实际中的日志记录
本章的最后一个问题是,本书与《Logging in Action》(www.manning.com/books/loggi…)之间的关系。那本书提到了 Fluent Bit,但只是提供了足够的上下文。就像这两种技术一样,这本书和那本书可以一起使用,但并没有相互依赖。然而,不要忽视《Logging in Action》。那本书包含了与 Fluent Bit 相关的内容,特别是关于可观测性和监控理论的更深入探讨,例如部署策略和如何混合这两种技术的方式。
总结
我们快速浏览了 Fluent Bit 流行的原因以及它在微服务环境中的优势,特别是它的小体积和与其他技术,特别是 Fluentd 的兼容性。
我们了解了 Fluent Bit 的高层次理念、架构和组件,这使我们更好地理解 Fluent Bit 的应用,接下来的章节中我们将进一步探索这一点。
我们还研究了 Fluent Bit 与 OpenTelemetry 之间的关系,并发现它们可以共存并相互补充。
我们回顾了 Fluent Bit 的高层次理念和元素,帮助你开始提出有关 Fluent Bit 的问题,并了解我们将在接下来的章节中探讨的内容,首先从查看我们如何运行 Fluent Bit 以及实现一个“Hello, World”配置开始。