跳转至

第五节(2022)使用Thanos查询前端优化查询性能

Thanos 中的 Query 组件可以提供一个统一的查询入口,但是当查询的数据规模较大的时候,对 querier 组件也会有很大的压力,为此 Thanos 也提供了一个 Query Frontend 的组件来提升性能。

Thanos Query Frontend 是 Thanos Query 的前端,它的目标是将大型查询拆分为多个较小的查询,并缓存查询结果来提升性能

1 概述

Thanos Query Frontend 组件通过 thanos query-frontend 命令实现了一个放在 querier 前面的服务,以改进读取路径。

它基于 Cortex Query Frontend 组件,所以你可以找到一些 Cortex 常见的特性,如查询拆分和结果缓存。

Thanos Query Frontend 是无状态和水平扩展的,可以使用下列命令来启动 Thanos Query Frontend:

thanos query-frontend \
    --http-address     "0.0.0.0:9090" \
    --query-frontend.downstream-url="<thanos-querier>:<querier-http-port>"

在接收到查询请求后 query frontend 不会立即响应,而是将查询请求放入一个查询队列中,querier 会连接到 query frontend 并消费这个队列,执行从队列中获取的查询请求并响应给 query frontend,query frontend 会对这些响应的结果进行聚合。

2 特性

2-1 查询队列

query frontend 的队列机制有以下用途。

  • 确保可能导致 OOM 的大型查询在发生错误时能够得到重试。
  • 防止多个大的查询请求打在单个 querier 上。
  • 可以分配租户所对应的 querier,避免单个租户使用 DOS 拒绝服务攻击其他租户

2-2 查询拆分

query frontend 会将多天的的查询拆分为多个单天的查询,游下游的 querier 去并行处理这些已拆分的查询。

返回的查询结果由 query frontend 进行汇聚。这样可以防止大时间跨度的查询导致 queier 发生 OOM,并且能够更快的执行查询以及更好的查询负载均衡。

查询前端根据配置的 --query-range.split-interval 标志将长查询拆分为多个短查询,--query-range.split-interval 的默认值为 24 小时,启用缓存时,它应该大于 0。

2-3 重试机制

query frontend 支持在 HTTP 请求失败时重试查询的重试机制,有一个 --query-range.max-retries-per-request 标志来限制最大重试次数。

2-4 查询缓存

query frontend 支持将查询结果进行缓存用以加速后续的查询。

当缓存的结果不够完整时,query frontend 会计算出所需要的子查询并分配给下游的 querier 并行执行,子查询的步长会对齐以提升查询结果的可缓存性。当前支持的缓存后端有:memcachedredis 和内存,下面是这些缓存后端的一些配置。

内存缓存

type: IN-MEMORY
config:
  max_size: ""
  max_size_items: 0
  validity: 0s

max_size表示在内存中缓存的最大尺寸,单位可以是 KB、MB、GB。如果 max_size 和 max_size_items 都没有设置,就不会创建缓存。如果只设置 max_sizemax_size_items 中的任意一个,则对其他字段没有限制。

memcached

type: MEMCACHED
config:
  addresses: [your-memcached-addresses]
  timeout: 500ms
  max_idle_connections: 100
  max_item_size: 1MiB
  max_async_concurrency: 10
  max_async_buffer_size: 10000
  max_get_multi_concurrency: 100
  max_get_multi_batch_size: 0
  dns_provider_update_interval: 10s
  expiration: 24h

expiration 表示指定 memcached 缓存有效时间,如果设置为 0,则使用默认的 24 小时过期时间,上面的配置是默认的 memcached 配置。

Redis

type: REDIS
config:
  addr: ""
  username: ""
  password: ""
  db: 0
  dial_timeout: 5s
  read_timeout: 3s
  write_timeout: 3s
  pool_size: 100
  min_idle_conns: 10
  idle_timeout: 5m0s
  max_conn_age: 0s
  max_get_multi_concurrency: 100
  get_multi_batch_size: 100
  max_set_multi_concurrency: 100
  set_multi_batch_size: 100
  expiration: 24h0m0s

expiration 表示指定 Redis 缓存有效时间,如果设置为 0,则使用默认的 24 小时过期时间。

2-5 慢查询日志

query frontend 还支持通过配置 --query-frontend.log-queries-longer-than 标志来记录运行时间超过某个持续时间的查询。

安装

安装 query frontend 最重要的就是通过 -query-frontend.downstream-url 指定下游的 querier,如下所示:

# thanos-query-frontend.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: thanos-query-frontend
  namespace: kube-mon
  labels:
    app: thanos-query-frontend
spec:
  selector:
    matchLabels:
      app: thanos-query-frontend
  template:
    metadata:
      labels:
        app: thanos-query-frontend
    spec:
      containers:
        - name: thanos
          image: thanosio/thanos:v0.25.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9090
              name: http
          args:
            - query-frontend
            - --log.level=info
            - --log.format=logfmt
            - --query-frontend.compress-responses
            - --http-address=0.0.0.0:9090
            - --query-frontend.downstream-url=http://thanos-querier.kube-mon.svc.cluster.local:9090
            - --query-range.split-interval=12h
            - --query-range.max-retries-per-request=10
            - --query-frontend.log-queries-longer-than=10s
            - --labels.split-interval=12h
            - --labels.max-retries-per-request=10
            - |-
              --query-range.response-cache-config="config":
                max_size: "200MB"
                max_size_items: 0
                validity: 0s
              type: IN-MEMORY
            - |-
              --labels.response-cache-config="config":
                max_size: "200MB"
                max_size_items: 0
                validity: 0s
              type: IN-MEMORY
          env:
            - name: HOST_IP_ADDRESS
              valueFrom:
                fieldRef:
                  fieldPath: status.hostIP
          livenessProbe:
            failureThreshold: 4
            httpGet:
              path: /-/healthy
              port: 9090
              scheme: HTTP
            periodSeconds: 30
          readinessProbe:
            failureThreshold: 20
            httpGet:
              path: /-/ready
              port: 9090
              scheme: HTTP
            periodSeconds: 5
          resources:
            requests:
              memory: 512Mi
              cpu: 500m
            limits:
              memory: 512Mi
              cpu: 500m
---
apiVersion: v1
kind: Service
metadata:
  name: thanos-query-frontend
  namespace: kube-mon
  labels:
    app: thanos-query-frontend
spec:
  ports:
    - name: http
      port: 9090
      targetPort: 9090
  selector:
    app: thanos-query-frontend
  type: NodePort

这里我们开启了缓存,使用内存缓存,直接通过 -query-range.response-cache-config 参数来配置缓存配置,也可以通过 -query-range.response-cache-config-file指定缓存配置文件,两种方式均可,为了验证结果,这里创建了一个 NodePort 类型的 Service,直接创建上面的资源对象即可:


☸ ➜ kubectl apply -f https://p8s.io/docs/thanos/manifests/thanos-query-frontend.yaml
☸ ➜ kubectl get pods -n kube-mon -l app=thanos-query-frontend
NAME                                     READY   STATUS    RESTARTS   AGE
thanos-query-frontend-78954bc857-nkxkk   1/1     Running   0          151m
☸ ➜ kubectl get svc -n kube-mon -l app=thanos-query-frontend
NAME                    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
thanos-query-frontend   NodePort   10.97.182.150   <none>        9090:30514/TCP   152m

然后可以通过任意节点的 30514 端口访问到查询前端:

该前端页面和 Query 组件是一致的,但是在 Query 前面缓存包装了一层。

Alt Image Text