Loki 知识点回顾
作者: Ryan 发布于: 2024/2/29 更新于: 2025/8/15 字数: 0 字 阅读: 0 分钟
1.Loki 的由来
Loki 是由 Grafana Labs 开发的一个水平可扩展、按标签划分的日志聚合系统。它与 Prometheus 的设计理念类似,但专门用于日志数据的管理。
2.核心理念
标签化日志系统: Loki 采用类似 Prometheus 的标签(labels)来管理和查询日志数据。每条日志都可以通过一组标签进行标识,这使得 Loki 能够高效地查询和聚合日志。
轻量级索引: Loki 的一个核心特点是它不对日志内容进行全文索引,而是仅对标签进行索引。这种设计显著降低了存储成本和索引复杂性,同时保留了快速查询的能力。
与 Prometheus 紧密集成: Loki 的标签和 Prometheus 的标签体系相互兼容,这使得用户可以在 Grafana 中轻松地将指标数据(metrics)和日志数据(logs)关联起来,从而更好地分析和诊断系统问题。
3.loki的各个组件及其作用
1. Promtail
- 作用:
Promtail
是 Loki 的日志收集器,类似于 Prometheus 的node_exporter
。它负责从日志文件、系统日志(如journalctl
)、Kubernetes 日志等来源收集日志数据。 - 功能: Promtail 会将日志数据解析成包含标签(labels)的日志条目,然后将这些数据推送到 Loki 集群的
Distributor
。
2. Distributor
- 作用:
Distributor
负责接收来自Promtail
或其他客户端的日志数据。 - 功能: 它通过一致性哈希算法计算日志数据的标签哈希值,并将数据分发到对应的
Ingester
节点。同时,Distributor
也负责在接收数据前验证标签和处理数据的负载均衡。
3. Ingester
- 作用:
Ingester
是处理和暂存日志数据的组件。 - 功能:
Ingester
节点接收到Distributor
分发的数据后,会将数据暂时存储在内存中,并定期将数据批量持久化到后端存储中。Ingester
还在查询过程中提供从内存中提取未持久化数据的功能。
4. Querier
- 作用:
Querier
负责处理用户的日志查询请求。 - 功能: 它接收查询请求后,确定需要从哪些
Ingester
节点或后端存储中提取数据,然后进行数据聚合、过滤和处理,最终将结果返回给用户。
5. Ruler
- 作用:
Ruler
是 Loki 中用于支持日志驱动报警的组件。 - 功能: 它基于用户定义的规则定期执行查询,并根据查询结果触发报警或生成相应的时间序列数据。这使得 Loki 可以结合 Grafana 或其他工具进行日志监控和报警。
6. Compactor
- 作用:
Compactor
是 Loki 中用于优化和压缩持久化日志数据的组件。 - 功能:
Compactor
定期对持久化存储中的日志块进行合并和压缩,以减少存储占用和提高查询效率。
7. Storage Backend
- 作用: 这是 Loki 的持久化存储系统,Loki 可以配置多种存储后端,如对象存储(S3 兼容)、文件系统、Google Cloud Storage(GCS)等。
- 功能: 负责存储经过
Ingester
压缩和持久化的日志数据,以及在查询时提供数据访问。
8. Table Manager
作用:
Table Manager
是 Loki 中管理表结构的组件,通常与 DynamoDB 或 Bigtable 一起使用。功能: 它管理 Loki 中存储数据的表的生命周期,包括创建、调整和删除表。
Promtail: 日志收集器,负责收集和推送日志数据。
Distributor: 接收并分发日志数据,进行负载均衡和标签验证。
Ingester: 处理和暂存日志数据,并将其持久化到存储中。
Querier: 处理查询请求,从
Ingester
和存储中提取数据并返回结果。Ruler: 支持基于日志数据的报警,定期执行查询。
Compactor: 压缩和优化持久化存储中的日志数据。
Storage Backend: 持久化存储系统,保存日志数据。
Table Manager: 管理存储表的生命周期,通常用于特定的存储后端。
4. 日志处理过程
- 首先日志数据通常由客户端(例如 Promtail)通过 HTTP 或 GRPC 协议发送到 Loki 的
Distributor
。 Distributor
接收到日志数据后,会对数据进行初步处理。- 标签提取:每条日志数据通常与一组标签(labels)关联。标签是键值对,用于描述日志的来源、类型、服务等信息。例如,一个日志流可能具有如下标签:
{app="nginx", env="production"}
。 - 通过一致性哈希计算进行数据分片:
Distributor
使用一致性哈希(consistent hashing)算法对这组标签进行哈希计算,将数据分片,Distributor
使用预定义的分片映射,将每个分片与特定的Ingester
节点相关联。哈希值落在某个分片中的日志数据会被分发到对应的Ingester
节点。 - 副本策略:为了提高数据的可靠性和容错能力,
Distributor
会将日志数据的副本发送到多个Ingester
节点。Distributor
并行地将日志数据发送到多个Ingester
节点,以确保快速的写入操作。每个Ingester
节点接收到数据后,会将其存储在内存中,并在适当的时候持久化到存储后端。 - 内存缓存:
Ingester
首先将接收到的日志数据保存在内存中,并进行短期缓存,以提高查询的响应速度。 - 数据压缩与持久化:当内存缓存达到一定的容量或时间阈值时,
Ingester
会将日志数据压缩并持久化到后端存储(如对象存储或文件系统)中。 - 数据副本的一致性:
Ingester
节点之间会通过协议确保数据副本的一致性。例如,当一个Ingester
节点崩溃时,其他副本节点可以恢复数据,保持系统的高可用性。 - 查询处理: 当用户或系统发起查询请求时,查询首先到达
Distributor
。Distributor
会根据标签和时间范围将查询路由到相关的Ingester
节点。 - 数据整合:
Ingester
返回查询结果后,Distributor
会将这些结果整合,并返回给查询请求者。对于尚未持久化的数据,查询可以直接从Ingester
的内存缓存中获取。 - 数据重建: 如果某个
Ingester
节点丢失了数据,可以通过其他副本节点来重建丢失的数据,确保系统的数据完整性和可用性。
5.Loki 的日志写入流程
- 日志收集: 日志数据通常由
Promtail
或其他客户端工具收集。Promtail
读取日志文件或其他日志源,将日志数据转化为包含标签(labels)的日志条目。 - 数据发送到 Distributor:
Promtail
将日志数据通过 HTTP/GRPC 请求发送到 Loki 集群中的Distributor
组件。 - 标签哈希计算:
Distributor
对日志条目的标签进行哈希计算,并根据一致性哈希算法确定数据应该分配到哪个Ingester
节点。 - 数据分发到 Ingester:
Distributor
将日志数据分发到一个或多个Ingester
节点。Ingester
节点接收到数据后,将其存储在内存中,并定期将数据批量持久化到后端存储(如对象存储、文件系统等)。 - 数据副本写入: 为了确保数据的高可用性,日志数据通常会被写入多个
Ingester
节点,形成多个副本。
6.Loki 的日志查询流程
- 用户发起查询请求: 用户通过 Grafana 或其他工具向 Loki 发起查询请求。查询请求包含了查询时间范围和标签过滤条件。
- 查询请求到 Querier: 查询请求首先到达 Loki 集群中的
Querier
组件。Querier
负责处理和协调查询请求。 - Querier 与 Ingester 交互:
- 从内存中查询:
Querier
会根据查询请求的标签和时间范围,确定哪些Ingester
节点可能存储了相关日志数据,并向这些Ingester
节点发出查询请求。 - 从存储中查询: 如果相关日志数据已经被持久化到后端存储(如对象存储或文件系统),
Querier
会直接从存储系统中提取数据。
- 从内存中查询:
- 数据聚合与过滤:
Ingester
节点和持久化存储返回的数据会被Querier
聚合、过滤和处理,以满足查询请求的条件。 - 结果整合与返回:
Querier
收集所有相关数据并进行最终的整合后,将完整的查询结果返回给用户。
7.Distributor 如何知道有多少个 Ingester 节点?
Loki 系统的 Distributor
通过服务发现机制(Service Discovery)来动态了解集群中有多少个 Ingester
节点。
- 服务发现:
Distributor
通常通过服务发现机制(例如基于 Kubernetes 的服务发现)来动态获取Ingester
节点的信息。每个Ingester
节点在启动时会向集群中的某个服务注册自己,Distributor
会周期性地查询这个服务来获取最新的Ingester
节点列表。 - 节点状态维护:
Distributor
会维护一个当前可用的Ingester
节点的列表,并跟踪每个节点的状态。这意味着Distributor
总是知道有多少个Ingester
节点在线,并可以根据这些信息来分配数据。
8. 一致性哈希算法如何决定数据分配到哪个 Ingester 节点?
一致性哈希算法在分布式系统中用于解决如何将数据分配到不同节点的问题。它具有很好的扩展性和动态性,特别适合节点数目动态变化的场景。
一致性哈希的基本原理:
- 哈希环(Hash Ring): 一致性哈希将整个哈希空间(例如
0
到2^32-1
的整数空间)组织成一个环形结构,称为哈希环(Hash Ring)。每个Ingester
节点会通过哈希函数映射到哈希环的某个位置。 - 节点分布:
Ingester
节点被映射到哈希环上的某些位置。这些位置是根据节点的标识符(例如节点名称或 IP 地址)通过哈希函数计算得出的。每个节点在哈希环上会有一个或多个虚拟节点(Virtual Nodes),以提高数据分布的均匀性。 - 数据分配: 当
Distributor
需要将一条日志数据分配到某个Ingester
节点时,它会首先计算出该日志数据的标签哈希值(基于 Tenant ID 和标签)。然后,Distributor
在哈希环上找到第一个大于或等于该哈希值的Ingester
节点,并将数据分配给这个节点。如果哈希值超过了哈希环的最大值,那么数据会被分配到环的起始位置(即第一个节点)。
数据分配的细节
- 分片与虚拟节点: 为了进一步优化数据分布,一致性哈希算法通常会在每个
Ingester
节点上创建多个虚拟节点。每个虚拟节点都映射到哈希环上的不同位置。这种方式使得即使在节点数量变化时,数据的重新分布也是局部的,只有少部分数据需要迁移,而不是全局的数据重分布。 - 负载均衡: 由于数据是按照哈希值分布的,并且每个节点可以有多个虚拟节点,数据在各个
Ingester
节点之间的分布通常是比较均匀的。这种均匀分布有助于避免单点过载,确保负载均衡。
节点数量变化时的处理
- 节点增加: 当有新的
Ingester
节点加入时,新的节点会在哈希环上占据新的位置。这会导致一些数据从邻近的老节点迁移到新节点上,但大部分数据仍然保持在原来的位置。 - 节点减少: 当某个
Ingester
节点离开时(例如因故障或缩容),哈希环上由该节点负责的哈希范围将被邻近的节点接管。这同样是局部的迁移,减少了数据重新分布的开销。
1. 一致性哈希算法的核心目的
- 数据分片: 一致性哈希算法的一个关键作用就是实现数据分片。通过计算日志流的哈希值,一致性哈希算法将这些哈希值映射到一个环形的哈希空间中。这个环形空间实际上是被虚拟划分成多个片段,每个片段(或者说“分片”)对应于某一个或多个
Ingester
节点。 - 节点映射: 在这个哈希环上,
Ingester
节点本身也被映射到环的某些位置。这些位置决定了该节点负责处理哪些范围的哈希值(即哪些数据分片)。
2. 最终的目标是数据分配
- 数据映射到节点: 当
Distributor
计算出某一条日志数据的哈希值后,它会在哈希环上找到第一个顺时针方向的Ingester
节点,并将该日志数据分配给这个节点。 - 分片决定了节点分配: 可以说,这个过程实际上就是将数据映射到特定的分片上,而这个分片对应着某个
Ingester
节点。因此,哈希值确定了数据被分配到哪个分片,而分片最终决定了数据被分配到哪个Ingester
节点。
3. 为什么使用一致性哈希
- 负载均衡与扩展性: 一致性哈希的优势在于,它能够在节点数量变化(增加或减少)时,仅重新分配受影响的分片数据。这种局部调整减少了大规模的数据迁移,确保系统的稳定性和负载均衡。
- 高效的资源利用: 通过这种方式,Loki 能够确保不同
Ingester
节点之间的数据负载大致均衡,不会因为某些节点被过度利用而导致系统瓶颈。
9. 什么是 Chunks?
- 定义: Chunks 是一段时间内收集的日志数据的集合。Loki 将这些日志数据压缩并存储为二进制格式,每个 Chunk 通常包含特定时间范围内的一部分日志数据。
- 作用: Chunks 用于在内存和持久化存储之间高效地管理日志数据。它们能够支持高效的数据写入和查询,同时优化存储空间的使用。
2. Chunks 的生成过程
- 数据收集: 当日志数据通过
Distributor
被发送到Ingester
时,Ingester
会将这些数据暂时存储在内存中。 - 数据分块:
Ingester
会根据配置的时间范围或数据量,将日志数据分成多个块,每个块就是一个 Chunk。例如,一个 Chunk 可能包含一分钟内的所有日志条目,或者达到一定大小的数据后形成一个 Chunk。 - 压缩与存储: 在 Chunk 生成后,
Ingester
会对其进行压缩,以减少存储空间占用。然后,压缩后的 Chunk 会被写入持久化存储(如 S3 兼容的对象存储、文件系统等)。
3. Chunks 的存储
- 内存缓存: 在数据生成后的初始阶段,Chunks 保存在
Ingester
的内存中,便于快速访问和查询。 - 持久化存储: 当 Chunk 的数据达到一定时间或容量时,
Ingester
会将其持久化到后端存储系统中。这保证了数据的长期保存和高可用性。
4. Chunks 在查询中的作用
- 查询优化: 当用户通过
Querier
发起查询请求时,Loki 会根据时间范围和标签过滤条件定位到相关的 Chunks。由于 Chunk 是按时间和标签划分的,因此可以快速缩小查询范围,提升查询效率。 - 并行处理: 多个 Chunks 可以同时被读取和处理,这使得 Loki 在处理大规模日志查询时具有较高的并行性和性能。
5. Chunks 的管理
- 压缩与合并:
Compactor
组件会定期对存储中的 Chunks 进行压缩和合并,以减少存储开销并优化查询性能。 - 生命周期管理: 根据 Loki 的配置,旧的 Chunks 可以被自动删除或归档,以确保存储资源的合理使用。
10. 什么是Compactor?
**Compactor
是 Loki 系统中的一个关键组件,负责对存储在后端的日志数据进行压缩和优化处理。它的主要作用是定期对已经持久化的日志数据进行整理和优化,以减少存储空间占用并提高查询性能。
1. Compactor 的作用
- 压缩日志数据:
Compactor
会定期对持久化存储中的日志 Chunks 进行压缩处理。压缩可以显著减少日志数据的存储空间占用,从而降低存储成本。 - 数据合并:
Compactor
还会将多个小的 Chunks 合并成更大的 Chunks。这有助于减少查询时需要访问的 Chunks 数量,从而提高查询性能。 - 删除过期数据: 根据配置的保留策略(Retention Policy),
Compactor
还可以自动删除过期的日志数据,确保系统不会因为旧数据的积累而导致存储资源耗尽。
2. Compactor 的工作流程
- 识别需要压缩和合并的 Chunks:
Compactor
会定期扫描存储中的日志数据,识别哪些 Chunks 可以被压缩或合并。这通常基于时间范围或存储策略。 - 数据压缩与合并:
Compactor
将这些 Chunks 压缩成更小的体积,并将多个小的 Chunks 合并成更大的 Chunks。这一过程在后台进行,确保不会影响系统的正常写入和查询操作。 - 写回存储: 压缩和合并后的数据会被写回到持久化存储系统中,以替换旧的 Chunks。旧的 Chunks 在确认新数据写入成功后会被删除。
3. Compactor 的优势
- 降低存储成本: 通过有效地压缩数据,
Compactor
可以显著减少日志数据的存储需求,特别是在长期存储大量日志数据的场景中。 - 提高查询性能: 合并后的大 Chunk 可以减少查询时需要访问的文件数量,从而提高查询速度和效率。
- 自动化数据管理:
Compactor
的自动化操作减少了手动管理存储数据的负担,使系统更加高效和自适应。
4. Compactor 的配置
- 调度频率:
Compactor
的运行频率可以在 Loki 的配置中进行调整。用户可以根据日志数据的增长速度和查询性能的需求来配置合适的运行频率。 - 存储策略:
Compactor
的操作受制于存储策略和数据保留策略,确保压缩和合并操作符合系统的整体存储规划。
11.Compactor 是依据什么标准合并Chunks的?
1. 时间范围
- 时间段相邻:
Compactor
会优先合并时间范围相邻的 Chunks。通常,Loki 会根据配置将相同时间段内的多个小 Chunks 合并为一个较大的 Chunk。这有助于减少查询时需要访问的 Chunks 数量,从而提高查询性能。 - 时间段重叠: 如果两个或多个 Chunks 的时间范围有重叠,
Compactor
也会尝试将它们合并。这可以帮助简化数据管理,并减少重复数据的存储。
2. Chunk 大小
- 目标大小:
Compactor
会将小于目标大小的 Chunks 合并为更大的 Chunk。目标大小通常是在系统配置中定义的,比如 Loki 会设置一个理想的 Chunk 大小,Compactor
会尝试将多个小 Chunk 合并到接近这个目标大小。 - 最小 Chunk 数量:
Compactor
可能会在某些条件下(例如在一定时间范围内)合并小于一定数量的 Chunks,以减少文件数量,提高查询效率。
3. 相同的标签集合
- 标签一致性:
Compactor
只会合并具有相同标签集合的 Chunks。这是因为 Loki 使用标签来进行查询过滤,合并不同标签集合的 Chunks 会导致查询逻辑复杂化甚至错误。 - 标签组合理化: 在某些情况下,
Compactor
也可能通过合并相同标签集合的 Chunks 来优化查询性能,确保标签在数据查询时的高效索引。
4. 系统资源限制
- 资源使用优化:
Compactor
的操作会受到系统资源的限制,比如内存、CPU 使用情况等。如果系统资源紧张,Compactor
可能会延迟合并操作,或者只进行最基本的合并操作以避免影响其他系统功能。 - 批量处理:
Compactor
通常会以批量方式处理 Chunks,以提高效率并最小化对系统性能的影响。批量合并可以减少多次 I/O 操作,从而提高整体系统的吞吐量。
5. 数据保留策略
- 数据保留期:
Compactor
会遵循 Loki 的数据保留策略,只对符合保留期的数据进行合并。如果数据接近保留期结束,Compactor
可能不会对这些数据进行合并,以避免浪费资源。 - 过期数据清理: 在合并过程中,
Compactor
还可能会识别并清理过期的 Chunks,确保系统不会存储超过保留期限的数据。