Querier

简要概述

组件 Querier 使用 PromQL 语法查询处理操作。

查询服务从 Ingester 和 Store-Gateway 中获取时间序列样本数据,Ingester 保存了尚未刷新到后端存储的内存中的时间序列样本,由于副本因子的存在,查询服务有可能接收到重复的样本数据,为了解决这个问题,在处理同一时间序列时,查询服务会对具有完全相同时间戳的样本进行内部去重操作。

查询服务是无状态的,并且可以根据需要进行扩展和缩减规模。但是这个注意,如果未开启 “bucket index” 功能,则每个副本启用后不会立刻加入工作。

如何工作

为了能在查询数据的时候找到正确的数据块,组件 Querier 需要知道最新的数据块在对象列表中,通过以下两个方案实现:

  1. 定期扫描对象列表(默认行为);
  2. 定期下载对象索引(bucket index 需要开启);

定期扫描

在启动 Querier 组件时会从所有租户对象存储中的数据块遍历下载 meta.json 文件,在这个阶段组件是不可用的也就是 “/ready” 接口处于不可用,如果在 k8s 中编排则服务是处理非健康状态,不会加入到 Service 中不接收流量。

在运行时,查询器会定期迭代存储桶,以发现新的租户和最近上传的块。查询者不会从块中下载任何内容,除了一个包含块元数据的 meta.json 文件。

当客户端通过 PromQL 语句查询数据时,组件 Querier 根据已下载的元数据计算出需要哪些数据块,然后通过与组件 Store-Gateway 获取实际数据。

开启存储桶索引

开启 “bucket index” 之后,组件 Querier 会在收到给定租户的第一个查询时延迟下载 “bucket-index.json” 索引,将其缓存在内存中并定期更新。“bucket index” 包含租户的块列表和块删除标记,稍后在查询执行过程中使用这些标记来查找给定查询需要查询的块集。

使用 “bucket index” 主要有以下优势:

  1. 组件 Querier 在启动后无需等待即可使用;
  2. 降低对对象存储的 API 调用量。

查询请求的剖析

当组件 Querier 接收到一个 PromQL 语句时:

{
    "end": "1737950063.305",
    "query": "rate(node_cpu_seconds_total[1m])",
    "start": "1737946463.305",
    "step": "14"
}

将会分析 “start” 至 “end” 时间范围内包含至少一个样本的所有数据块,然后计算包含这些块的数据在哪些 Store-Gateway 实例上,并获取相应序列数据。

从存储网关收到的响应进行一致性检查,以确保所有预期的块都已被查询,如果没有,查询器将重试从不同存储网关的缺失块中获取样本(-store-gateway.sharding-ring.replomation > 1 时),如果所有重试后一致性检查都失败,则查询执行也会失败

如果 “start” 至 “end” 涵盖了持续时间 querier.query-ingesters-within 所配置的值内,则 Querier 组件也会发送请求至所有 Ingester 实例,以防部分数据没有发送至后端对象存储。

当所有需要的数据从 Ingester 与 Store-Gateway 获取到后,Querier 使用 PromQL 引擎计算结果并返回给用户。

如何发现 Store-Gateway 服务:

  1. 当开启 store-gateway.sharding-ring.* 时,使用相同的配置共享哈希环;
  2. 未开启 store-gateway.sharding-ring.* 时,需配置 querier.store-gateway-addresses 地址用 DNS 轮询。

元数据缓存

组件 Querier 支持 metadata cache 包含内容:

  1. 租户列表;
  2. 每租户数据库列表;
  3. 数据块元数据 meta.json 内容;
  4. 数据块标记删除 deletion-mark.json 内容;
  5. 租户数据块索引 bucket-index.json.gz 内容;

在通过 blocks-storage.bucket-store.* 开启配置。

配置示例

官方文档

querier:
  max_concurrent: 20
  timeout: 2m0s
  iterators: false
  batch_iterators: true
  ingester_streaming: true
  ingester_metadata_streaming: false
  max_samples: 50000000
  query_ingesters_within: 0s
  query_store_for_labels_enabled: false
  at_modifier_enabled: false
  per_step_stats_enabled: false
  query_store_after: 0s
  max_query_into_future: 10m0s
  default_evaluation_interval: 1m0s
  active_query_tracker_dir: ./active-query-tracker
  lookback_delta: 5m0s
  store_gateway_addresses: ""
  store_gateway_client:
    tls_enabled: false
    tls_cert_path: ""
    tls_key_path: ""
    tls_ca_path: ""
    tls_server_name: ""
    tls_insecure_skip_verify: false
    grpc_compression: ""
  shuffle_sharding_ingesters_lookback_period: 0s

数据结构

querier.Config

github.com/cortexproject/cortex/pkg/querier/querier.go

// Config contains the configuration require to create a querier
type Config struct {
    MaxConcurrent             int           `yaml:"max_concurrent"`
    Timeout                   time.Duration `yaml:"timeout"`
    Iterators                 bool          `yaml:"iterators"`
    BatchIterators            bool          `yaml:"batch_iterators"`
    IngesterStreaming         bool          `yaml:"ingester_streaming"`
    IngesterMetadataStreaming bool          `yaml:"ingester_metadata_streaming"`
    MaxSamples                int           `yaml:"max_samples"`
    QueryIngestersWithin      time.Duration `yaml:"query_ingesters_within"`
    QueryStoreForLabels       bool          `yaml:"query_store_for_labels_enabled"`
    AtModifierEnabled         bool          `yaml:"at_modifier_enabled" doc:"hidden"`
    EnablePerStepStats        bool          `yaml:"per_step_stats_enabled"`

    // QueryStoreAfter the time after which queries should also be sent to the store and not just ingesters.
    QueryStoreAfter    time.Duration `yaml:"query_store_after"`
    MaxQueryIntoFuture time.Duration `yaml:"max_query_into_future"`

    // The default evaluation interval for the promql engine.
    // Needs to be configured for subqueries to work as it is the default
    // step if not specified.
    DefaultEvaluationInterval time.Duration `yaml:"default_evaluation_interval"`

    // Directory for ActiveQueryTracker. If empty, ActiveQueryTracker will be disabled and MaxConcurrent will not be applied (!).
    // ActiveQueryTracker logs queries that were active during the last crash, but logs them on the next startup.
    // However, we need to use active query tracker, otherwise we cannot limit Max Concurrent queries in the PromQL
    // engine.
    ActiveQueryTrackerDir string `yaml:"active_query_tracker_dir"`
    // LookbackDelta determines the time since the last sample after which a time
    // series is considered stale.
    LookbackDelta time.Duration `yaml:"lookback_delta"`

    // Blocks storage only.
    StoreGatewayAddresses string       `yaml:"store_gateway_addresses"`
    StoreGatewayClient    ClientConfig `yaml:"store_gateway_client"`

    ShuffleShardingIngestersLookbackPeriod time.Duration `yaml:"shuffle_sharding_ingesters_lookback_period"`

    // Experimental. Use https://github.com/thanos-community/promql-engine rather than
    // the Prometheus query engine.
    ThanosEngine bool `yaml:"thanos_engine"`
}

ClientConfig

type ClientConfig struct {
    TLSEnabled      bool             `yaml:"tls_enabled"`
    TLS             tls.ClientConfig `yaml:",inline"`
    GRPCCompression string           `yaml:"grpc_compression"`
}



最后修改 2025.01.27: chore: update xx (7761ee3)