「Grafana Loki」- 概念术语

问题描述

该笔记将记录:与 Grafana Loki 相关的内容,以及相关问题的解决方案。

解决方案

下面的内容是快速阅读官方文档而摘录的关键信息,至少对于我们来说是重要的,以形成对 Grafana Loki 的整体认识,并不具备参考价值,详细内容建议阅读官方文档;

如果有必要,子章节将对我们关心的特定概念进行进一步的讨论和描述;

仅索引元数据;日志以块的形式压缩存储;数据保存在对象存储中;

=> Fundamentals

Overview

Grafana Loki 是整个日志栈的核心组件,除此之外还有其他组件;
日志仅索引元数据,是根据标签;原始日志内容保持不变;
Agent 收集日志,转为流,并写入 Loki 中;Promtail Agent 专为 Loki 安装而设计,其他 Agent 也可无缝对接 Loki 服务;
App -> Agent -> Loki
Loki 索引的是流(流是关联到具有唯一标签集的日志集合),高质量的标签集是关键;

特新特征:
1)在索引时,高效的内存使用:仅索引标签是其优势;
2)多租户(Multi-tenancy):多租户可共享 Loki 实例,日志将以 Tenancy ID 进行区分;
3)LogQL:类似于 PromQL,用于日志查询;
4)可扩展性:所有组件可运行在同个进程中,但又可以微服务的形式独立运行,以支持扩展;
5)灵活性:许多代理(客户端)都有插件支持,这可将现有的可观察性堆栈加入 Loki,使得 Loki 成为其日志聚合工具,而无需切换现有的可观察性堆栈;
6)Grafana 集成:Loki 与 Grafana 无缝集成,提供完整的可观察性堆栈;

关于 EFK 与 Grafana Loki 的对比(官方肯定会列举自生的优势,所以我们也更加关注这些优势):
1)单进程模式,将数据保存在本地;水平扩展模式,则将数据保存在对象存储中;日志直接存储,其仅索引标签;比完整索引的运行成本更低,并允许开发人员积极地从他们的应用程序中进行日志;缺点就是 如果要查询内容,则需要加载所有与标签匹配的块;
2)Promtail 为 Loki 量身定制:主模式发现日志并转发到 Loki 中(附带标签);并能 K8S 服务发现 Pod,或作为 Docker Log Dirver,也能处理 systemd 日志;
3)与 Prometheus 一起,配合服务发现(相同机制),使得 日志 与 Metric 具有相同的标签,使得问题定问和分析更加容易;
4)Grafana 专门针对来自 Prometheus 和 Loki 等来源的时间序列数据量身定制。可以设置仪表板来可视化指标(即将提供日志支持),并且可以使用探索视图对您的数据进行临时查询。与 Kibana 一样,Grafana 支持基于您的指标的警报。

Architecture

Grafana Loki 在多租户模式时,将从 HTTP Header X-Scope-OrgID 获得 Tenant ID
如果不是多租户模式,将忽略该头部字段,并设为 fake 保存在索引及块中;

Chunk Format

-------------------------------------------------------------------
|                               |                                 |
|        MagicNumber(4b)        |           version(1b)           |
|                               |                                 |
-------------------------------------------------------------------
|         block-1 bytes         |          checksum (4b)          |
-------------------------------------------------------------------
|         block-2 bytes         |          checksum (4b)          |
-------------------------------------------------------------------
|         block-n bytes         |          checksum (4b)          |
-------------------------------------------------------------------
|                        #blocks (uvarint)                        |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
| #entries(uvarint) | mint, maxt (varint) | offset, len (uvarint) |
-------------------------------------------------------------------
|                      checksum(from #blocks)                     |
-------------------------------------------------------------------
|                    #blocks section byte offset                  |
-------------------------------------------------------------------

mint and maxt describe the minimum and maximum Unix nanosecond timestamp, respectively.

Block Format,一个块由一系列条目组成,每个条目都是一个单独的日志行。请注意,块的字节数是使用 Gzip 压缩存储的。以下是它们未压缩时的形式:

存储:
1)单存储:Loki 将所有数据保存在单个存储后端,Loki 2.0 开始可用,快速、经济、简单,也是未来的趋势;使用 boltdb_shipper 来将索引保存在对象存储中(就像存储 Chunk 一样);
2)多存储:chunk store 是长期存储,用于交互式查询和持续的数据写入(无需后台维护任务来处理),包括 Chunk 的索引以及 Chunk 数据本身;注意 chunk store 并非独立的服务,而是嵌入到程序(Ingester、Querier)里的类库,用于访问 Loki 数据;chunk store 依赖于后端存储提供的接口,以保存 chunk store 索引,接口假定索引是条目的集合,由 Hash Key 和 Rnage Key 索引; 对于不同的后端,接口工作方式也略有差异;系列的 Schema 用于映射到对索引的合理操作,Schema 在升级,主要是为了更好的负载均衡和提升查询性能;

Read Path:
The querier receives an HTTP/1 request for data.
The querier passes the query to all ingesters for in-memory data.
The ingesters receive the read request and return data matching the query, if any.(若如数据,然后 Querier 将在存储中查询)
The querier lazily loads data from the backing store and runs the query against it if no ingesters returned data.
The querier iterates over all received data and deduplicates, returning a final set of data over the HTTP/1 connection.

Write Path(Label Set 为 hash;日志条目为 Chunk,相同 Label Set 为同个 Chunk,并压缩)
The distributor receives an HTTP/1 request to store data for streams.
Each stream is hashed using the hash ring.
The distributor sends each stream to the appropriate ingesters and their replicas (based on the configured replication factor).
Each ingester will create a chunk or append to an existing chunk for the stream’s data. A chunk is unique per tenant and per labelset.
The distributor responds with a success code over the HTTP/1 connection.

Consistent Hash Rings

Loki Cluster 架构使用一致性哈希:协助日志行分片;实现高科用;简化集群的扩展和缩小(减少重新平衡数据时的性能损失);
Hash-Ring 连接(单一组件类型的实例):以 monolithic deployment mode 模式部署的多个 Loki 实例;以 simple scalable deployment mode 部署中的多个读组件或写组件;微服务模式下一种组件有多个实例;
使用 Hash-Ring 组件有:distributors、ingesters、query schedulers、compactors、rulers

同类型的组件才会创建 Hash-Ring:
1)Ring 内的每个 Node 代表组件的一个实例;
2)每 Node 都由 KV-Store 已保存其他 Node 的通信信息;
3)Node 周期更新 KV-Store 以保证所有节点内容一致性;
4)每个节点的 KV-Store 保存:Node ID,组件地址(所谓其他 Node 使用的通信信道),节点健康的指示器;

Configuring rings
1)common.ring_config 的 ring configuration
2)默认 memberlist KV-Store(除非由必要修改为其他类新),其使用 gossip protocol 实现一致性;
3)附加选项用于设置 distributor.ring ingester.lifecycler.ring ruler.ring

distributor ring:用于统计 Distributor 数量。计数进一步通知集群限制。
ingester ring:被 Distributor 使用,用于日志分片,决定接收日志的 Ingester 是谁;
query scheduler ring:用于 Scheduler 的服务发现。这使得 Querier 能够连接所有 Scheduler,并允许 Scheduler 连接 Query-Frontend,高效常见查询及平衡查询负载;
compactor ring:用于识别负责压缩的示例,虽然有多个压缩实例,但仅有一个负责压缩任务;
ruler ring:用于确定哪个 Ruler 来执行 Rule-Group;

Labels

是键值对,在 Loki 中被成为 Metadata 用以描述日志流,类似 Prometheus 的形式;如果在 Promethesu 和 Loki 中使用相同的 Lable 能够将指标与日志关联起来;

Loki 是如何使用 Lable 的:
1)Loki 使用 LabelSet 来标识日志流,如果 Label 发生变化,将成为新的日志流;
2)Prometheus 使用 Series 术语,还有附加的 Metric Name;而 Loki 没有 Metric name 只有 Lable,并且使用 Stream 而非 Series 概念;

Lable 示例:
1)官方文档提供示例,解释了 Label 的简单示例;
2)以及通过 Lable 搜索日志的方法;
3)Loki 索引 label,而日志内容则以 Chunk 存储;

Cardinality(基数)
1)这里的基数是指过多不同的 LabelSet 导致 Loki 创建过多的日志流,这些日志流里又没有什么日志数据;
2)比如以用户 IP 地址来创建日志流,将导致大量的小块;
3)这会影响 Loki 性能,所以尽量不要这么做;

那么如何解决基数的问题:
1)既然不建议通过创建过多的日志流,那如何进行搜索?
2)Loki 使用 filter expression 来进行内容搜索,背后 Loki 将在各个分片中并行搜索内容;
3)并行搜索是能够进行配置的;
4)这种做法是出于性能和成本考虑(传统的全索引日志系统的索引占用极大的空间);

Configuration

有关于命令的选项;

Examples

配置示例

Query Frontend

查询前端

LogQL

日志查询语言

Tools

LogCLI,是 Loki 的命令行接口

Community(=> Governance)

关于 Loki 团队、参与项目的方法、社区治理 等等

Maintaining(=> Maintaining)

关于 Loki 项目的维护及镜像构建相关的内容;

Design documents

Labels
Promtail Push API
Write-Ahead Logs
Ordering Constraint Removal