:构建、查询与配置完全指南)
Loki Bloom Filter 查询加速实验特性构建、查询与配置完全指南【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki本文基于 bloom-filters.md 整理并深度扩充。Loki 使用布隆过滤器Bloom Filter加速大规模日志的检索通过预先为结构化元数据structured metadata构建紧凑的索引结构在查询阶段跳过绝大多数不可能命中的 chunk显著降低从对象存储加载与遍历的数据量。本文面向正在评估或计划接入该实验特性的开发者与 SRE读完你将掌握Bloom Planner / Builder / Gateway 三个组件的职责与部署方式、完整的启用配置与 per-tenant 限流参数、retention 与资源规划建议以及查询分片策略bounded的工作原理。什么是 Bloom Filter 查询加速Loki 常常被用来执行 大海捞针needle in a haystack类型的查询——在大量日志行中搜索但只有极少数日志行真正匹配。典型场景包括在全部日志中检索某个特定的 trace ID按客户 IDcustomer ID过滤出与某个业务请求相关的全部日志。例如在整集群范围内检索过去 24 小时内的某个 trace ID{clusterprod} | traceID3c0e3dcd33e7未启用加速过滤时Loki 需要下载匹配{clusterprod}的所有流stream在过去 24 小时内的全部 chunk并逐行遍历每个 chunk检查结构化元数据键traceID的值是否为3c0e3dcd33e7。日志量越大这种全量扫描的成本越高。启用加速过滤后Loki 借助布隆过滤器跳过绝大多数 chunk只处理那些统计意义上可能包含该结构化元数据键值对的 chunk从而大幅缩短查询时间。布隆过滤器Bloom Filter是一种概率型数据结构用于快速判断某个元素一定不存在或可能存在于集合中。Loki 正是利用这一特性以极小的内存/磁盘代价换取跳过无关数据的能力。⚠️ 实验特性警告 在 Loki 与 Grafana Enterprise LogsGEL中基于布隆过滤器的查询加速属于实验特性不提供工程与值班支持、不提供 SLA。该特性主要面向每月日志摄入量超过 75TB的大规模用户因为其构建与查询本身也有较高的成本只有在足够大的规模下才划算。 在 Grafana Cloud 中该功能以 public preview 形式对部分符合条件的超大客户开放同样仅提供有限支持、无 SLA。关于如何编写使用布隆过滤器的查询可进一步阅读 Query acceleration结构化元数据的概念与写入方式见 structured-metadata。启用 Bloom Filter部署前提{{ admonition typewarning }} 布隆过滤器的构建与查询在设计上不支持单二进制single binary部署只能在分布式微服务模式下使用。原因是构建与查询布隆过滤器本身成本较高只有在大型分布式部署中才能体现出收益。 {{ /admonition }}要开始构建与使用 bloom你需要完成以下三步部署Bloom Planner 和 Builder组件作为微服务运行或通过简单可扩展部署模式 SSD 的backendtarget 运行并在 Bloom Build 配置 中启用部署Bloom Gateway组件同样作为微服务或 SSDbackendtarget 运行并在 Bloom Gateway 配置 中启用为每个租户单独启用 bloom 构建与过滤或为所有租户统一启用通过 limits 配置。最小启用配置示例以下 YAML 片段来自 bloom-filters.md给出了完整的启用配置# Configuration block for the bloom creation. bloom_build: enabled: true planner: planning_interval: 8h builder: planner_address: bloom-planner.namespace.svc.cluster.local:9095 # Configuration block for bloom filtering. bloom_gateway: enabled: true client: addresses: dnssrvnoa_bloom-gateway-grpc._tcp.bloom-gateway-headless.namespace.svc.cluster.local # Enable blooms creation and filtering for all tenants by default # or do it on a per-tenant basis. limits_config: bloom_creation_enabled: true bloom_split_series_keyspace_by: 1024 bloom_gateway_enable_filtering: true各配置块的要点bloom_build.enabled全局开关控制是否启用 bloom-planner 与 bloom-builder 组件对应命令行参数-bloom-build.enabled默认false。bloom_build.planner.planning_intervalplanner 重新执行 bloom 创建规划的间隔对应-bloom-build.planner.interval默认 8h见 pkg/bloombuild/planner/config.go。bloom_build.builder.planner_addressbuilder 连接 planner 的地址hostname 与端口对应-bloom-build.builder.planner-address必填项——在 pkg/bloombuild/builder/config.go 的Validate()中若该项为空会直接报错planner address is required。bloom_gateway.client.addressesBloom Gateway 客户端用于服务发现的地址采用 DNS Service Discovery 格式。示例中的dnssrvnoa前缀表示按 SRV 记录的noaNo A record模式解析。地址为空时同样会在Validate()中报错见 pkg/bloomgateway/client.go。此外bloom planner 还有两个与构建时间窗口相关的参数见 pkg/bloombuild/planner/config.go-bloom-build.planner.min-table-offset从今天开始含当天构建 bloom 的最新日表偏移默认0即从今天开始构建。调大可降低频繁重写近期数据带来的对象存储写入成本代价是 bloom 不会那么快可用。-bloom-build.planner.max-table-offset构建 bloom 的最老日表偏移含当天默认1即到昨天为止。可用于不为几乎不再变化的旧数据构建 bloom 以降低成本建议与租户的reject_old_samples_max_age设置对齐。更多配置项请参考 Bloom Gateway 配置、Bloom Build 配置 与 per-tenant limits 定义。官方强烈建议在使用该实验特性前通读完整文档。Bloom Planner 与 Builder从对象存储中的 chunk 构建布隆过滤器由两个组件协作完成Bloom Planner为 bloom 构建创建任务task并将任务派发给 builder 执行。Bloom Builder从 planner 拉取任务处理任务中引用的流与 chunk并将构建结果bloom block上传到对象存储。布隆过滤器被组织成bloom block一个 block 可横跨多个流series与多个属于同一天的 chunk。Planner单实例运行Bloom Planner 以单实例方式运行负责为某个租户在某个时间周期内计算指纹区间fingerprint range中的构建缺口gaps并把这些缺口转化为任务分发给可用的 builder。Planner 同时负责应用bloom retention见下文。{{ admonition typewarning }}不要运行超过一个 Bloom Planner 实例。Do not run more than one instance of the Bloom Planner. {{ /admonition }}从 pkg/bloombuild/planner/config.go 的源码可以看到planner 内部还包含一个任务队列配置queue.Config以及 min/max table offset 约束并通过Limits接口读取租户级参数如BloomCreationEnabled、BloomBuildMaxBuilders、BuilderResponseTimeout、BloomTaskMaxRetries。Builder无状态水平扩展Bloom Builder 是无状态、可水平扩展的组件可以独立于 planner 进行扩缩容以匹配任务处理需求。其配置pkg/bloombuild/builder/config.go包括planner_addressplanner 地址必填grpc_config连接 planner 的 gRPC 配置backoff_config任务拉取/重试的退避策略working_directoryblock 临时写入的工作目录-bloom-build.builder.working-directory为空时使用操作系统临时目录。Retentionbloom 块保留Bloom Planner 会在对象存储上应用 bloom block 的保留策略默认关闭开启后对所有租户生效。每个租户的 bloom 保留期取以下两者中的较长者通用保留期retention_period流级保留期retention_stream按 selector 匹配。例如下面这个 overrides 示例中租户 A 的 bloom 保留期为 30 天租户 B 的通用保留期为 30 天但{namespaceprod}流被retention_stream覆盖为 40 天因此 B 的 bloom 保留期为 40 天overrides: A: retention_period: 30d B: retention_period: 30d retention_stream: - selector: {namespaceprod} priority: 1 period: 40dretention_period与retention_stream字段在 pkg/validation/limits.go 中有对应定义流级保留规则支持priority字段多规则匹配时取优先级最高者无匹配规则时回退到retention_period。Planner / Builder 的规模与配置单个 planner 实例会在给定间隔内为每个租户的 bloom block 执行规划阶段并将产生的任务放入内部任务队列。Builder顺序地从队列中拉取任务并处理。要在下一次规划迭代前完成全部待处理任务所需的 builder 副本数量取决于-bloom-build.split-keyspace-by、租户数量以及流的日志量。最大块大小通过-bloom-build.max-block-size按租户配置。由于构建器会持续向 block 追加流的 bloom直到 block 超过配置的最大值因此实际块大小可能超过该上限。单个流 bloom 的最大大小通过-bloom-build.max-bloom-size按租户配置。bloom 超过该值的流会被丢弃而不是加入 block。Block 在内存中创建一旦写入对象存储即被释放chunk 与 TSDB 文件会从对象存储下载到本地文件系统。官方估算每个核心每秒大约可以处理 4MB 的数据We estimate that builders are able to process 4MB worth of data per second per core.。规划策略Planning strategiesBloom Planner 支持两种将 bloom 构建工作拆分为任务的策略通过 per-tenant 配置bloom_planning_strategy选择默认值见 pkg/validation/limits.go 中-bloom-build.planning-strategy默认split_keyspace_by_factor策略说明相关配置split_keyspace_by_factor默认将 series keyspace 拆分为固定数量的部分并行度由bloom_split_series_keyspace_by控制bloom_split_series_keyspace_by对应-bloom-build.split-keyspace-by默认256split_by_series_chunks_size按目标 chunk 数据量来划分任务大小而非固定拆分数量bloom_task_target_series_chunk_size对应-bloom-build.split-target-series-chunk-size此外还有若干 per-tenant 限制用于微调任务调度、块编码与 gateway 预取这些字段均标记为category:experimental见 pkg/validation/limits.gobloom_build_max_builders限制可同时处理某个租户任务的 builder 数量0表示不限制默认0。对应 flag-bloom-build.max-builders。bloom_build_builder_response_timeoutplanner 等待 builder 完成任务的超时时间超时后任务会重新入队0表示禁用超时。对应 flag-bloom-build.builder-response-timeout。bloom_build_task_max_retries失败任务在放弃前的最大重试次数默认30表示不限制。对应 flag-bloom-build.task-max-retries。bloom_block_encodingbloom block 页面使用的压缩算法对应-bloom-build.block-encoding默认none。该值会通过compression.ParseCodec校验合法性。bloom_prefetch_blocksbloom block 构建完成后是否立即在 Bloom Gateway 上预取对应-bloom-build.prefetch-blocks默认false。关于任务派发的一个实现细节在 pkg/bloombuild/planner/config.go 的QueueLimits.MaxConsumers()中bloom_build_max_builders会被用于计算某个租户最多允许占用多少 builder 并发处理任务——当限制为0时返回0表示所有 builder 均可为该租户服务。Bloom GatewayBloom Gateway 负责处理来自index gateway的 chunk 过滤请求服务接收一组 chunk 引用列表和一个过滤表达式将其与 bloom 块进行匹配过滤掉不匹配该过滤表达式的 chunk。该组件可水平扩展每个实例只拥有流指纹区间的一个子集并仅对这部分区间执行过滤。数据分片在客户端侧完成通过 DNS 服务发现获取服务端实例列表并使用jumphash算法对流的指纹做一致性哈希实现均匀分布。从源码看pkg/bloomgateway/client.go客户端核心逻辑FilterChunks会根据每个 block 的标识通过jumphash.Selector计算出目标 gateway 地址pkg/bloomgateway/client_pool.go 中的JumpHashClientPool将请求分组发送单个 gateway 实例失败不会导致整个查询失败——此时该实例对应的 chunk 会原样返回不做过滤实现降级不过滤同时通过指标clientRequestsroutefilterChunks, typeerror/success进行监控。多实例返回的结果还会经过按 fingerprint 排序合并与去重mergeSeries。Bloom Gateway 的配置见 pkg/bloomgateway/config.go启用开关为bloom_gateway.enabled对应-bloom-gateway.enabled默认false。Gateway 规模与配置Bloom Gateway 使用本地文件系统作为从对象存储下载的 bloom 块的LRU最近最少使用缓存。bloom 的大小取决于摄入量ingest volume唯一结构化元数据键值对的数量bloom 的构建参数尤其是误报率false-positive-rate。官方文档指出在默认设置下bloom 过滤器约占原始结构化元数据大小的 1% 以下With default settings, bloom filters make up 1% of the raw structured metadata size.。由于读取 bloom 高度依赖磁盘 IOPSBloom Gateway应使用多块本地直连 SSD 磁盘NVMe以提升 I/O 吞吐。可通过-bloom.shipper.working-directory指定多个挂载点逗号分隔例如-bloom.shipper.working-directory/mnt/data0,/mnt/data1,/mnt/data2,/mnt/data3内存占用估算Bloom Gateway 需要处理相对较大的文件——bloom block。虽然 bloom block 的二进制格式允许以更小的页面page为单位读入内存但内存消耗取决于并发加载到内存中处理的页面数量。以下三个配置项的乘积决定了任意时刻 bloom 数据在内存中的最大占用-bloom-gateway.worker-concurrency默认4通常设为 1 倍 CPU 核数-bloom-gateway.block-query-concurrency默认8通常设为 2 倍 CPU 核数-bloom.max-query-page-size假设 4 个 CPU 核-bloom-gateway.worker-concurrency4 // 1x NUM_CORES -bloom-gateway.block-query-concurrency8 // 2x NUM_CORES -bloom.max-query-page-size64MiB 4 x 8 x 64MiB 2048MiB此例中block 处理的内存需求为 2GiB。要得到 Bloom Gateway 的最低内存需求需要将该值翻倍即约 4GiB为页缓存、解码缓冲等留出余量。Building bloomsbloom 是如何构建的布隆过滤器按流stream构建并聚合到 block 文件中。流按照其fingerprint被分配到各 block排列顺序与 Loki 的 TSDB 及分片计算一致——这带来数据局部性收益同一分片中的流大概率位于同一 block 中查询时可减少跨 block 的随机读取。除 block 外builder 还会维护一份元数据文件列表其中包含对 bloom block 的引用以及这些 block 所基于的TSDB 索引文件的引用。Gateway 与 planner 通过元数据文件发现已存在的 block。构建流程如下每隔-bloom-build.planner.interval默认 8hplanner 会加载所有已启用 bloom 构建的租户的最新 TSDB 文件并将其与最新 bloom 元数据文件对比如果存在新的 TSDB 文件或某些 TSDB 文件发生了变化planner 就会为这些 TSDB 文件所引用的流与 chunk 创建构建任务Builder 从 planner 的队列中拉取任务处理其中包含的流与 chunk对于某个流builder 会遍历其新 chunk 内的全部日志行为该流构建 bloom如果此前已处理过的 TSDB 文件发生了变化builder 会优先复用已有 block 中的 bloom而不是从零重建。哈希的追加方式builder 将每条日志行中的结构化元数据转换为一组哈希并追加到 bloom 中每个key的哈希每个key-value 对的哈希以上哈希与 chunk 标识符拼接后的组合哈希。第一组哈希key 与 key-value 对的哈希让 gateway 能够跳过整个流第二组哈希与 chunk 标识符组合用于跳过单个 chunk。例如对于 chunkc6dj8g中的结构化元数据foobar会向流的 bloom 中追加以下 4 个哈希hash(foo) hash(foobar) hash(c6dj8g foo) hash(c6dj8g foobar)这与源码中 bloom v1 使用的哈希实现基于 FNV-1a 64 位哈希见 pkg/storage/bloom/v1/filter/boom_test.go 与 pkg/storage/bloom/v1/filter/partitioned.go相辅相成FNV 哈希被用于 bloom 位数组的写入与查询。Query shardingbounded分片策略查询加速不仅发生在 chunk 处理阶段也发生在查询规划阶段query frontend 会应用查询分片query sharding。Loki 3.0 引入了一个新的 per-tenant 配置项tsdb_sharding_strategy旧策略默认基于索引统计信息计算分片数取最接近的 2 的幂期望将待处理数据乐观地均分为大小相近的若干片。但流之间的数据量往往并不均衡导致某些分片处理的数据量远大于其他分片形成长尾。新策略bounded在查询前端的规划阶段就使用 bloom 立即减少需要处理的 chunk 数量并让每个分片查询需要处理的 chunk 数量尽可能均匀分布从而缓解数据倾斜带来的分片不均问题。从源码看pkg/logql/shards.gobounded策略对应BoundedVersion由DynamicBoundsStrategy实现它通过ShardingRanges在解析阶段直接获取每个分片预计算好的 chunk 引用组ChunkRefGroup配合目标每分片字节数target bytes per shard做动态分片而power_of_two策略PowerOfTwoVersion则使用传统的基于统计的分片方式。tsdb_sharding_strategy的取值定义同样位于 pkg/validation/limits.go字段TSDBShardingStrategy支持power_of_two与bounded两个合法值。总结与使用建议Bloom Filter 查询加速是 Loki 面向超大规模日志检索场景月摄入量 75TB 以上提供的实验性能力通过为结构化元数据建索引、查询时按统计置信度跳过无关数据来缩短端到端查询时间。启用它需要按序完成三件事在微服务或 SSDbackendtarget模式下部署并启用Bloom Planner Builder部署并启用Bloom Gateway并通过 DNS 服务发现 jumphash 实现均匀分片通过limits_config为租户开启bloom_creation_enabled与bloom_gateway_enable_filtering并按需调整bloom_split_series_keyspace_by、规划策略、任务重试、block 编码、内存占用等参数。该特性仍处于实验阶段无 SLA、无工程支持且单二进制部署不受支持在投入生产前建议在符合规模的测试环境中验证构建吞吐每核每秒约 4MB 数据的估算、Gateway 的磁盘 IOPS 与内存预算并发度乘积 × 2并关注 per-tenant 限流参数对构建/查询并行度的影响。更深入的内容可继续阅读Query acceleration 查询编写指南结构化元数据structured metadata说明Bloom Build 配置源码Bloom Gateway 配置源码per-tenant limits 定义与默认值查询分片策略实现bounded【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考