Skip to content

Commit

Permalink
fix typo
Browse files Browse the repository at this point in the history
  • Loading branch information
isno committed Jan 24, 2025
1 parent 3e246f3 commit ea184dc
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 43 deletions.
71 changes: 30 additions & 41 deletions Observability/logging.md
Original file line number Diff line number Diff line change
@@ -1,87 +1,77 @@
# 9.3.2 日志的存储与索引

处理日志本来是件稀松平常的事情,但数据规模的影响下,量变引发质变,日志处理成为典型的大数据场景之一:高吞吐写入(GB/s)、低成本海量存储(PB 级别)、亿级数据量实时检索(1s 内)
处理日志本来是件稀松平常的事情,但随着数据规模的增长,量变引发质变,高吞吐写入(GB/s)、低成本海量存储(PB 级别)以及亿级数据的实时检索(1 秒内),已成为软件工程领域最具挑战性的难题之一

本节,笔者将从日志存储与分析的角度,介绍三种各具特色的日志系统方案:Elastic Stack(全文索引)、Loki(仅索引元数据)和 ClickHouse(列式数据库)。

## 1. 全文索引方案 Elastic Stack
本节将从日志存储与分析的角度出发,介绍业内三种主流的日志处理解决方案。

讨论如何实现一套完整的日志系统时,工程师们或多或少都听说过这几个名词:ELK、ELKB 或 Elastic Stack
## 1. 全文索引方案 Elastic Stack

实际上,它们指向的是同一套用于日志处理的开源组件。Elastic Stack(为明确统一,本文统称 Elastic Stack)是由 Elastic 公司开发的一组开源工具,专门用于数据海量的收集、搜索、分析和可视化处理。
在讨论如何实现完整的日志系统时,ELK、ELKB 或 Elastic Stack 是工程师们耳熟能详的名词。它们实际上指代同一套由 Elastic 公司[^1]开发的开源工具,用于海量数据的收集、搜索、分析和可视化处理。

图 9-6 展示了一套基于 Elastic Stack 的日志处理方案:

- **数据收集**:Beats 组件部署在日志生成节点,负责收集原始数据
- **数据缓冲**使用消息队列(RabbitMQ)缓冲数据,以提高数据吞吐量
- **数据清洗**数据发送到 Logstash 清洗
- **数据存储**:清洗后的数据存储在 Elasticsearch 集群,并生成索引
- **数据可视化**:Kibana 负责数据检索、分析、可视化处理。如果需要,还可以再部署一套 Nginx 实现访问控制。
- **数据收集**:Beats 组件部署在业务所在节点,负责收集原始的日志数据
- **数据缓冲**使用 RabbitMQ 消息队列缓冲数据,提高数据吞吐量
- **数据清洗**数据通过 Logstash 进行清洗
- **数据存储**:清洗后的数据存储在 Elasticsearch 集群中,它负责索引日志数据、查询聚合等核心功能
- **数据可视化**:Kibana 负责数据检索、分析与可视化,必要时可部署 Nginx 实现访问控制。

:::center
![](../assets/ELK.png)<br/>
图 9-6 整合了消息队列和 Nginx 的 Elastic 日志系统
图 9-6 整合了消息队列、Nginx 的 Elastic Stack 日志系统
:::

:::tip 额外知识
Elastic 公司的发展始于创始人 Shay Banon 的个人兴趣,从开源、聚人、成立公司,到走向纽交所,再到股价一路狂飙(截止 2024 年 7 月 11 日,最新市值 $107 亿),几乎是最理想的工程师创业故事。
:::
Elastic Stack 中最核心的组件是 Elasticsearch —— 基于 Apache Lucene 构建的开源的搜索与分析引擎。值得一提的是,Lucene 的作者就是大名鼎鼎的 Doug Cutting,如果你不知道他是谁是?那你一定听过他儿子玩具的名字 —— Hadoop。

Elastic Stack 套件中,最核心的组件是 Elasticsearch —— 一个基于 Apache Lucene 构建的开源的搜索与分析引擎。值得一提的是,Lucene 的作者就是大名鼎鼎的 Doug Cutting,如果你不知道他是谁是?那你一定听过他儿子玩具的名字 —— Hadoop。
Elasticsearch 能够在海量数据中迅速检索关键词,其关键技术之一就是 Lucene 提供的“反向索引”(Inverted Index)。与反向索引相对的是正向索引,二者的区别如下:

Elasticsearch 能够在海量数据中快速检索关键词,其关键技术之一是 Lucene 中的“反向索引”(Inverted Index)。与反向索引相对的是正向索引,两者的区别是:
- **正向索引**(Forward Index):传统的索引方法,将文档集合中的每个单词作为键,值为包含该单词的文档列表。正向索引适用于快速检索特定标识符的文档,常见于数据库中的主键索引。
- **反向索引**(Inverted Index):反向索引通过将文本分割成词条并构建“<词条->文档编号>”的映射,快速定位某个词出现在什么文档中。值得注意的是,反向索引常被译为“倒排索引”,但“倒排”容易让人误以为与排序有关,实际上它与排序无关。

- **正向索引(Forward Index)**:正向索引是一种传统的索引方法,它将文档集合中的每个单词作为键,将包含该单词的文档列表作为值。正向索引适用于快速检索特定标识符的文档,常用于数据库管理系统中的主键索引。
- **反向索引(Inverted Index)**:反向索引通常被译为“倒排索引”,但“倒排”容易让人误以为与排序有关,实际上它与排序无关。反向索引的工作原理是将文本分割成词条,并构建“<词条->文档编号>”的索引,以便快速定位某个词出现在哪些文档中。

以下面三段要被索引的英文为例:
举一个具体的例子,以下是三个待索引的英文句子:

- T~0~ = "it is what it is"
- T~1~ = "what is it"
- T~2~ = "it is a banana"

通过反向索引,得到下面的匹配关系。
通过反向索引,可以得到以下匹配关系:

```
"a": {2}
"banana": {2}
"is": {0, 1, 2}
"it": {0, 1, 2}
"what": {0, 1}
```
检索时,条件“what”, “is” 和 “it” 将对应这个集合:$\{0, 1\}\cap\{0,1,2\}\cap\{0,1,2\} = \{0,1\}$。可以看出,反向索引使得搜索操作能够快速定位包含特定关键词的文档,而无需逐一扫描所有文档
在检索时,条件“what”“is” 和 “it” 将对应集合:$\{0, 1\}\cap\{0,1,2\}\cap\{0,1,2\} = \{0,1\}$。可以看出,反向索引能够快速定位包含特定关键词的文档,而无需逐个扫描所有文档

Elasticsearch 另一项关键技术是“分片”(sharding)每个分片相当于一个独立的 Lucene 实例,类似于一个完整的数据库。
Elasticsearch 的另一项关键技术是“分片”(sharding)每个分片相当于一个独立的 Lucene 实例,类似于一个完整的数据库。在文档写入时,Elasticsearch 会根据哈希函数(通常基于文档 ID)计算出文档所属的分片,从而将文档均匀分配到不同的分片;查询时,Elasticsearch 会并行地在多个分片上执行计算,并将结果聚合后返回给客户端,从而提高查询吞吐量

- 文档写入时,Elasticsearch 通过哈希函数(通常基于文档 ID)计算该文档应存储的分片,从而将文档有序地分配到不同的分片中。
- 查询文档时,查询请求并行地在多个分片上执行计算,最终将结果聚合后返回给客户端,这显著提升了查询的吞吐量。

追求极致查询性能的背后,Elasticsearch 也付出了相应的代价:

- **写入吞吐量下降**:文档写入过程中需要进行分词和构建排序表等 CPU 和内存密集型操作,导致写入性能下降。
- **存储空间占用高**:Elasticsearch 存储原始数据和反向索引,为了加速分析,可能还需要额外存储一份列式数据。
- **冗余副本**:为避免分片的单点故障,Elasticsearch 默认为每个分片提供一个冗余副本。
为了追求极致的查询性能,Elasticsearch 也付出了以下代价:
- **写入吞吐量下降**:文档写入需要进行分词和构建排序表等操作,这些都是 CPU 和内存密集型的,会导致写入性能下降。
- **存储空间占用高**:Elasticsearch 不仅存储原始数据和反向索引,为了加速分析能力,可能还额外存储一份列式数据(Column-oriented Data);其次,为了避免单点故障,Elasticsearch 会为每个分片创建一个或多个副本副本(Replica),这导致 Elasticsearch 会占用极大的存储空间。


## 2. 轻量化处理方案 Loki

Grafana Loki(简称 Loki)是由 Grafana Labs 开发的一款日志聚合系统其设计灵感来源于 Prometheus,旨在成为“日志领域的 Prometheus”,并具有轻量、低成本以及与 Kubernetes 高度集成的特点
Grafana Loki 是由 Grafana Labs 开发的一款日志聚合系统其设计灵感来源于 Prometheus,目标是成为“日志领域的 Prometheus”。与 Elastic Stack 相比,Loki 具有轻量、低成本和与 Kubernetes 高度集成等特点

Loki 的主要组件包括 Promtail(日志代理)、Distributor(分发器)、Ingester(写入器)、Querier(查询器)、Query Frontend(查询前端)和 Ruler(规则处理器)。其中,Promtail 负责从各种来源收集日志,Distributor 验证并分发日志Ingester 负责存储和索引日志Querier 用于执行日志查询,Query Frontend 优化查询请求,而 Ruler 负责监控和告警规则的执行
Loki 的架构如图 9-7所示,主要组件有 Promtail(日志代理)、Distributor(分发器)、Ingester(写入器)、Querier(查询器)、Query Frontend(查询前端)和 Ruler(规则处理器)。其中,Promtail 负责从多种来源收集日志;Distributor 验证并分发日志Ingester 负责存储和索引日志Querier 执行日志查询;Query Frontend 优化查询请求Ruler 处理监控和告警规则的执行

:::center
![](../assets/loki_architecture_components.svg)<br/>
图 9-7 Loki 架构
:::

Loki 最大的特点是,不对原始日志数据、仅对日志的元数据(如标签和时间戳)建立索引。在 Loki 的存储模型中,有两种数据类型:块(Chunks)和索引(Indexes)。

- **索引(Indexes)**:索引存储每个日志流的标签集,并将其与相应的块关联。索引的作用是快速定位到特定的日志块,从而提高查询效率。索引通常存储在高读写性能的数据库中,如 Amazon DynamoDB、Google Bigtable 或 Apache Cassandra。
- **块(Chunks)**:块是 Loki 存储日志数据的主要方式,包含原始日志内容。当日志条目到达 Loki 时,它们被压缩并存储为块,保存在对象存储(如 Amazon S3 或 Google Cloud Storage)或本地文件系统中。
Loki 的主要特点是,只对日志的元数据(如标签、时间戳)建立索引,而不对原始日志数据进行索引。在 Loki 的存储模型中,数据有以下两种类型:

用户发起日志查询时,查询请求根据“时间范围”和“标签”在索引中查找对应的块。然后,Loki 根据索引返回的块元数据,从块存储中读取并解压缩原始日志数据,返回给用户。
- **索引**(Indexes):Loki 的索引仅包含日志流的标签(如日志的来源、应用名、主机名等)和时间戳,并将其与相应的块关联。
- ****(Chunks):块是 Loki 用来存储实际日志数据的基本单元。每个日志条目都会被压缩成一个块,并存储在持久化存储介质中,如对象存储(例如 Amazon S3、GCP、MinIO)或本地文件系统。

仅索引元数据、索引和块的分离存储的设计,让 Loki 处理大规模日志数据时具有明显的成本优势
当用户发起日志查询时,Loki 根据时间范围和标签等查询条件,首先在索引中查找与条件匹配的块。然后,Loki 使用这些索引信息找到对应的日志块,从块存储中读取日志数据,并将其解压缩后返回给用户

不难看出,Loki 通过仅索引元数据、以及索引和块的分离存储设计,让其在处理大规模日志数据时具有明显的成本优势。

## 3. 列式存储数据库 ClickHouse

Expand Down Expand Up @@ -158,7 +148,6 @@ ClickHouse 支持“分片”(Sharding)技术,也就是支持分布式并
图 9-9 ClickHouse 性能测试 [图片来源](http://clickhouse.yandex/benchmark.html)
:::



[^1]: Elastic 公司的发展始于创始人 Shay Banon 的个人兴趣,从开源、聚人、成立公司,到走向纽交所,再到股价一路狂飙(截止 2024 年 7 月 11 日,最新市值 $107 亿),几乎是最理想的工程师创业故事。
[^1]: 以运营俄罗斯最受欢迎的搜索引擎闻名,被称为俄罗斯的 Google
[^2]: 参见 https://mp.weixin.qq.com/s/dUs7WUKUDOf9lLG6tzdk0g
4 changes: 2 additions & 2 deletions Observability/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ Dapper 论文的发布,让治理复杂分布式系统迎来了转机,链路
以 SkyWalking 的 Java 追踪探针为例,它实现的原理是将需要注入的类文件(追踪逻辑代码)转换成字节码,然后通过拦截器注入到正在运行的应用程序中。比起基于日志实现的追踪,基于服务的追踪在资源消耗和侵入性(但对业务工程师基本无感知)上有所增加,但其精确性和稳定性更高。现在,基于服务的追踪是目前最为常见的实现方式,被 Zipkin、Pinpoint、SkyWalking 等主流链路追踪系统广泛采用。

- **基于边车代理的追踪**:这是服务网格中的专属方案,基于边车代理的模式无需修改业务代码,也没有额外的开销,是最理想的分布式追踪模型。总结它的特点如下:
- **对应用完全透明**:有自己独立数据通道,追踪数据通过控制平面上报,不会有任何依赖或干扰;
- **与编程语言无关**:无论应用采用什么编程语言,只要它通过网络(如 HTTP 或 gRPC)访问服务,就可以被追踪到。
- 对应用完全透明:有自己独立数据通道,追踪数据通过控制平面上报,不会有任何依赖或干扰;
- 与编程语言无关:无论应用采用什么编程语言,只要它通过网络(如 HTTP 或 gRPC)访问服务,就可以被追踪到。

目前,市场占有率最高的边车代理 Envoy 就提供了链路追踪数据采集功能,但 Envoy 没有自己的界面端和存储端,需要配合专门的 UI 与存储系统来使用。不过,Zipkin、SkyWalking、Jaeger 和 LightStep Tracing 等等系统都能够接收来自 Envoy 的链路追踪数据,充当其界面和存储端。

Expand Down

0 comments on commit ea184dc

Please sign in to comment.