ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Loki 2.8 版本深度解读:TSDB 索引转正、查询拦截器(Query Blocker)与 backend 目标

Loki 2.8 版本深度解读:TSDB 索引转正、查询拦截器(Query Blocker)与 backend 目标 Loki 2.8 版本深度解读TSDB 索引转正、查询拦截器Query Blocker与 backend 目标【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki本篇技术指南围绕 Grafana Loki 2.8 版本发布说明展开聚焦该版本三大核心变化TSDB 索引正式脱离实验状态成为推荐索引存储、新增 Query Blocker 查询拦截能力按租户运行时配置拦截高风险查询以及新增backend目标配合read/write形成三目标可扩展部署令 read 目标彻底无状态化。同时完整梳理 2.8 系列的升级注意事项与各补丁版本的安全修复。读完本文你将能独立完成 TSDB 索引的迁移配置、通过blocked_queries保护集群免受昂贵查询冲击并理解简单可扩展部署Simple Scalable Deployment中 read/write/backend 三目标的分工与组件归属。一、版本概览Loki 2.8 由 Grafana Labs 发布是 2.x 生命周期中承上启下的一个重要版本。它既承载了此前数个版本积累的 TSDB 索引成熟度该索引已在 Grafana Cloud Logs 产品中经受大规模生产验证又为运维侧引入了两项直接影响日常使用体验的能力按租户粒度的查询拦截以及更合理的水平扩展目标划分。除功能增强外2.8 还包含一批针对依赖链的修复与安全加固后续发布的 2.8.1 至 2.8.6 六个补丁版本均以升级 Go 版本、更新基础镜像、修复特定缺陷为主详情可查阅仓库根目录的 CHANGELOG。二、核心特性一TSDB 索引不再实验发布说明的第一条即为 TSDB 索引 no longer experimental。在经历 Grafana Cloud Logs 中大量生产环境的验证后Loki 团队确认新 TSDB 索引已足够稳定鼓励所有 Loki 部署迁移使用。2.1 什么是单存储 TSDB 索引Loki 的存储层由对象存储中的块数据 索引两部分组成。TSDB 索引Single Store TSDB将原本 Prometheus 生态的 TSDB 索引格式用于 Loki 的日志索引索引文件随块数据一同存放在对象存储中由 ingester 生成、compactor 压缩合并、querier/index gateway 读取。仓库文档 operations/storage/_index.md 明确说明Single Store TSDB 是Loki 2.8 及更新版本的推荐索引存储用于替代已进入淘汰流程的 BoltDB Shipperlogs-deletion.md 亦指出 BoltDB Shipper 将在 Loki 4.0 移除新部署应直接使用 TSDB。与旧的 BoltDB Shipper 相比TSDB 索引带来几个显著优势文件系统也可作为对象存储使用由于索引文件随块数据托运到对象存储querier 在独立进程中也能读取同一份数据只要所有进程能访问同一目录见 filesystem.md。旧 BoltDB 索引一次仅允许一个进程持有数据库文件锁无法做到这一点。支持动态分片dynamic shardingTSDB 可以按查询负载动态计算分片数量这也是 2.8 将metrics.go日志中subqueries字段拆分为splits与shards的原因之一详见第五节。日志删除logs deletion基于 TSDB 的索引结构可实现精确的日志条目删除。2.2 TSDB 索引配置示例仓库 examples/getting-started/loki-config.yaml 给出了一个完整的最小 TSDB 配置schema_config: configs: - from: 2023-01-01 store: tsdb object_store: s3 schema: v13 index: prefix: index_ period: 24h关键字段说明store: tsdb指定索引存储类型为 TSDBobject_store: s3块数据与索引均存放在 S3也支持 GCS、Azure Blob 等对象存储以及filesystemschema: v132.8 时代的 schema 版本index.period: 24h索引按天切分配合 compactor 将同一天、同一租户的多个索引文件合并为单个文件提升查询时的索引查找效率见 components.md 中 Compactor 一节。2.3 TSDB 生态组件TSDB 索引启用后集群中与之紧密协作的组件包括Index Gateway专门处理元数据查询如查询日志量、定位 chunk 引用仅在单存储 TSDB 模式下启用支持simple与ring两种运行模式。Compactor将 ingester 上传的多个索引文件按天 租户合并为单一索引文件同时承担日志保留retention与日志删除deletion职责通常以单实例运行。Querier / Query Frontend查询路径上通过 Index Gateway 获取 chunk 引用后再拉取数据。三、核心特性二Query Blocker 查询拦截器在无法控制客户端查询行为的环境中某些查询可能无意或有意地代价高昂例如无过滤的大范围聚合进而影响整个集群的稳定性与成本。2.8 引入的Query Blocker允许在 Querier / Ruler 中通过每租户的运行时配置runtime configuration file直接拦截这类查询且配置变更无需重启进程。3.1 配置方式与完整示例拦截规则定义在 runtime 配置文件的overrides.tenant-id.blocked_queries中。仓库中的权威操作文档 operations/blocking-queries.md 给出了完整示例overrides: tenant-id: blocked_queries: # 精确拦截这一条查询 - pattern: sum(rate({envprod}[1m])) # 拦截任何匹配该正则的查询 - pattern: .*prod.* regex: true # 拦截所有 metric 类型查询pattern/regex 省略时默认匹配全部 - types: metric # 仅拦截 filter 与 limited 类型中匹配正则的查询 - pattern: .*prod.* regex: true types: filter,limited # 按查询哈希精确拦截32 位 FNV-1 哈希 - hash: 2943214005 # {streamstdout,podloki-canary-9w49x} 的哈希 types: filter,limited # 通过 X-Query-Tags 请求头按来源拦截键值均不区分大小写 - pattern: .* # 省略 pattern/regex 时默认分别为 .* 与 true regex: true query_tags: source: grafana feature: beta3.2 规则字段与匹配语义每条blocked_queries规则支持以下字段字段含义说明pattern查询文本匹配串省略时默认为.*匹配所有查询regex是否将 pattern 视为正则省略时默认为truetypes仅拦截指定查询类型可多值见下hash查询文本的 32 位 FNV-1 哈希避免长查询字符串的转义麻烦query_tags仅拦截携带指定X-Query-Tags键值对的请求所有指定键值都必须匹配三种查询类型types定义如下metric带聚合函数的查询如sum(rate({envprod}[1m]))filter带日志过滤器的查询如{envprod} | errorlimited既无过滤器也无聚合的查询。hash字段使用查询字符串的 32 位 FNV-1 哈希32 位无符号整数。实际使用中无需自行计算——query-frontend 与 querier 会在每次请求的日志中输出query_hash字段例如levelinfo ts2023-03-30T09:08:15.2614555Z callermetrics.go:152 componentfrontend org_id29 latencyfast query{stream\stdout\,pod\loki-canary-9w49x\} query_hash2943214005 query_typelimited range_typerange ...3.3 源码实现剖析Query Blocker 的核心逻辑位于 pkg/logql/blocker.go。从源码结构看其实现要点如下规则读取isBlocked方法通过qb.q.limits.BlockedQueries(ctx, tenant)获取当前租户的拦截规则该接口由 pkg/validation/limits.go 中的Overrides.BlockedQueries实现从每租户覆盖配置中读取blocked_queries字段配置声明见同文件 L190。匹配优先级先比较hashb.Hash 0时精确比对util.HashedQuery(query)否则依次处理 pattern空 pattern 视为匹配全部、regex: true时编译正则匹配、否则做去除空白的精确字符串比较。类型与标签双重校验block方法先校验查询类型是否命中types列表命中后再由tagsMatch校验请求上下文中的X-Query-Tags通过httpreq.ExtractQueryTagsFromContext提取要求规则中声明的所有键值对全部匹配才真正拦截。首个命中即停注释明确写道 The order of patterns is preserved, so the first matching pattern will be used——规则的顺序被保留Loki 在第一条 pattern 或 hash 命中的规则处停止。若该规则的types或query_tags约束不满足则查询不会被拦截且不再继续检查后续规则即使后续规则本可拦截。因此文档建议多条规则共享同一 pattern 时应合并约束到单条规则而非依赖后面的规则兜底。并发安全对共享配置对象采用局部副本处理使isBlocked可被并发安全调用。3.4 观测拦截结果被拦截的查询会记录到日志并累计到按租户统计的loki_blocked_queries指标。当 pattern/hash/regex 命中时日志会输出类型与标签是否匹配levelwarn msgquery blocker matched with regex policy user29 typemetric pattern.*rate\\(.*\\).* querysum(rate({app\foo\}[5m])) typesMatchedtrue tagsMatchedfalse blockedfalse标签约束未命中时输出 debug 级日志指明缺失的键与收到的原始头leveldebug msgquery blocker tags mismatch: missing or mismatched key keyfeature tagsRawSourcegrafana,Featurealpha3.5 拦截范围与限制Query Blocker 由 LogQL 查询引擎在求值阶段强制执行覆盖/loki/api/v1/query即时查询与/loki/api/v1/query_range范围查询API告警与记录规则Alerting / Recording Rules本地与远程评估模式均覆盖——远程评估模式下规则查询会经 query-frontend 与 querier 回传与普通 API 查询同等拦截。不适用的场景包括日志 tail/loki/api/v1/tail端点tail 直接读取 ingester 与存储不经过查询引擎元数据端点如labels、series、index/stats、index/volume、detected_fields等不执行 LogQL 表达式无对象可供匹配。此外仓库文档特别警告实验性的下一代查询引擎query_engine.enable: true面向 dataobj/columnar 存储的查询完全不检查blocked_queries策略这是一项已知限制而非延迟检查拦截策略对其静默失效。3.6 基于 X-Query-Tags 的定向拦截除按查询文本拦截外还可将规则限定到携带特定X-Query-Tags请求头的请求头格式逗号分隔的keyvalue对例如Sourcegrafana,Featurebeta允许字符为字母数字加空格、逗号、等号、、.、-其他字符替换为_仅保留规范的keyvalue标记畸形标记被忽略匹配规则键与值均不区分大小写服务端将键转为小写规则中声明的所有query_tags键值对必须全部出现在请求中才生效。一个典型场景是仅拦截来自测试特性开关的查询overrides: tenant-a: blocked_queries: - types: metric query_tags: feature: beta - pattern: .*rate\\(.*\\).* regex: true query_tags: source: grafanaRuler 查询标签当 ruler 以远程评估模式-ruler.evaluation.moderemote运行时会自动在查询上附带sourceruler,rule_namerule name,rule_typerule type标签因此可以针对规则评估定向配置策略例如拦截所有来自规则评估的查询overrides: tenant-id: blocked_queries: - query_tags: source: ruler注意本地评估模式下 ruler 不设置X-Query-Tags无法按此匹配且规则名若含逗号或等号会被标签解析截断或丢弃匹配rule_name时需谨慎。四、核心特性三新增backend目标2.8 为 Loki 的scalable 配置即 Loki helm chart 的默认部署方式Simple Scalable Deployment / SSD新增了第三个目标backend。至此 Loki 可以按read、write、backend三个目标分组运行read目标因此变为无状态可作为 Kubernetes Deployment 运行并自动水平扩缩容。4.1 三目标模式下的组件归属仓库文档 get-started/components.md 以表格形式明确了各组件在三目标模式下的归属x表示该目标包含此组件组件allreadwritebackendDistributorxxIngesterxxQuery FrontendxxQuery SchedulerxxQuerierxxIndex GatewayxxCompactorxxRulerxxPattern IngesterxxBloom Planner / Builder / Gateway实验性xx可以看到read由 Query Frontend 与 Querier 组成两者均为无状态组件天然适合 Kubernetes Deployment HPA 自动扩缩write由 Distributor、Ingester、Pattern Ingester 组成ingester 依赖 WAL 与对象存储保持有状态backend收纳 Query Scheduler、Index Gateway、Compactor、Ruler 等既不参与写入、也不直接处理用户查询的组件通常以 StatefulSet 或固定副本数部署。4.2 目标机制与配置示例Loki 的单二进制内聚了所有微服务组件通过-target命令行参数或target配置项指定启动哪些模块。从 pkg/loki/loki.go 的源码可见target默认值为all单二进制模式并支持-list-targets标志打印全部可用目标。仓库 examples/getting-started/loki-config.yaml 展示了一个三目标部署共享的配置骨架memberlist: join_members: [read, write, backend] dead_node_reclaim_time: 30s gossip_to_dead_nodes_time: 15s left_ingesters_timeout: 30s bind_addr: [0.0.0.0] bind_port: 7946 gossip_interval: 2s common: path_prefix: /loki replication_factor: 1 compactor_address: http://backend:3100 storage: s3: endpoint: minio:9000 insecure: true bucketnames: loki-data access_key_id: loki secret_access_key: supersecret s3forcepathstyle: true ring: kvstore: store: memberlist要点解读memberlist.join_members列出 read/write/backend 三个目标的服务名使所有实例通过 memberlist 协议共享集群状态common.compactor_address指向 backend 目标的 compactor 地址供需要对接 compactor 的组件如查询删除相关流程使用common.ring.kvstore.store: memberlist让所有内部 ringingester、distributor 等共用 memberlist 集群。运维上三个目标各部署一个 Kubernetes Service分别暴露端口供对应的客户端/组件访问read与write可按需横向扩容backend保持较小规模即可。4.3 与部署模式的衔接从 get-started/deployment-modes.md 看当前仓库的部署模式体系已演化为三种Monolithic单二进制-targetall、HA Monolithic高可用单二进制与Microservices微服务。其中 HA Monolithic 模式已取代旧 SSDSimple Scalable Deployment成为推荐的折中方案但 2.8 引入的backend目标仍是理解 SSD / helm chart 默认部署形态的关键它将原本挤在read中的无状态查询组件与有状态/后台组件分离为 read 路径的弹性伸缩扫清了障碍。五、升级注意事项2.8.0原发布说明强调升级前务必阅读 upgrade guide。结合仓库升级文档2.8.0 的关键变更整理如下5.1retention_period默认值改为 0s这是最具破坏性的一项变更。此前compactor.retention_enabled: true且未在limits_config中定义retention_period时默认保留 744h31 天2.8 起默认改为0s语义为永久保留 / 禁用保留。注意旧版本中0或0s会触发立即删除全部日志仅在 2.8 及之后的版本零值才表示禁用保留。若希望维持旧行为需显式配置limits_config: retention_period: 744h5.2 LogQL 重复标签行为变化当日志行中出现重复标签时Loki 2.8 改为只保留第一个值此前保留的是最后一个值。使用重复标签的查询结果可能因此变化。5.3metrics.go日志字段subqueries拆分为splits与shards旧版metrics.go每行日志中的subqueries仅反映按时间拆分产生的子查询数未包含分片数。2.8 起不再输出subqueries统计 API 中为向后兼容仍返回该字段但恒为 0改为splits按时间间隔拆分产生的查询段数量shards为查询创建的总分片数值为 0 通常表示该查询无法分片。这尤其适用于 TSDB 的动态分片能力便于区分时间拆分与分片两种并行化来源。同时 2.8 在metrics.go中新增了 Store 与 Cache 统计记录从存储下载 chunk、以及从缓存下载 chunk / 索引查询结果 / 结果缓存所耗费的时间*_download_time字段这些统计也可通过 LogCLI 的--stats标志查看。5.4 Promtailpromtail_journal_enabled构建标签Promtail 引入 Go 构建标签promtail_journal_enabled只有传入该标签才启用 Journal 支持go build --tagspromtail_journal_enabled ./clients/cmd/promtail此举旨在让无需 Journal 支持的 Linux/CentOS 用户CGO 启用时免于安装libsystemd-dev/systemd-devel依赖。5.5 Rulerruler.wal-cleaer.period废弃CLI 标志ruler.wal-cleaer.period拼写有误2.8 废弃并以修正后的ruler.wal-cleaner.period取代YAML 配置不变ruler: wal_cleaner: period: 5s5.6 Querierquery-frontend Kubernetes 服务类型调整此项仅影响使用 jsonnet 部署 Loki 到 Kubernetes 的用户。原query-frontendheadless 服务被拆分为两个服务query-frontend改为负载均衡服务公平分发查询请求新增query-frontend-headless供 querier 发现前端 Pod IP 建立 worker 连接。使用 Query Schedulerquery_scheduler_enabled: true的部署无需处理未使用 Scheduler 时建议按先建 headless 服务 → 滚动更新 querier → 再应用其余变更的顺序灰度。六、补丁版本与安全修复2.8 系列共发布 2.8.1 至 2.8.6 六个补丁主要内容为安全加固与缺陷修复完整清单见仓库根目录 CHANGELOG版本日期要点2.8.62023-10-17升级 Go 至 v1.20.10、golang.org/x/net 至 v0.17.0、grpc-go 至 v1.56.3修复 CVE-2023-39325 / CVE-2023-444872.8.52023-09-14更新 Docker 基础镜像缓解安全漏洞 CVE-2022-481742.8.22023-05-03升级 Go 至 1.20.4 修复安全漏洞Promtail 新增decompression配置以自定义解压器行为2.8.12023-04-21修复索引周期为零值时索引被丢弃的问题修复 redis 客户端在本地地址下错误选择集群模式的问题升级 Go 至 1.20.3alpine 镜像更新至 3.16.5修复 Promtail 在 amd64 二进制构建中的 journald 支持这些补丁提醒生产用户若运行 2.8 早期版本应至少升级至 2.8.6以规避 Go 依赖链与基础镜像层的历史 CVE。七、总结Loki 2.8 是 2.x 系列中转正与治理并重的一个版本TSDB 索引经生产验证后成为官方推荐索引方案配合 schema v13 与 compactor/index gateway 组件使用Query Blocker 借助每租户运行时配置为集群提供了按文本、哈希、类型、请求来源多维度的查询治理手段backend目标的加入则完善了三目标可扩展部署的组件划分让 read 路径可以无状态弹性伸缩。升级侧最需要留意的是retention_period默认值变更与 LogQL 重复标签语义调整。对于 2.7 及更早版本的用户建议结合升级指南与本文第六节制定配置核对 → 灰度升级 → 安全补丁到位的完整升级路径。【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进