菜单
文档breadcrumb arrow Grafana Mimirbreadcrumb arrow 设置breadcrumb arrow 迁移breadcrumb arrow 从 Thanos 或 Prometheus 迁移
开源

从 Thanos 或 Prometheus 迁移到 Grafana Mimir

本文档指导操作员将 Thanos 或 Prometheus 部署迁移到 Grafana Mimir。

概览

Grafana Mimir 将时间序列存储在上传到对象存储桶的 TSDB 块中。这些块与 Prometheus 和 Thanos 使用的块相同。每个项目将块存储在不同的位置,并使用略微不同的块元数据文件。

配置远程写入到 Grafana Mimir

有关配置远程写入到 Grafana Mimir 的信息,请参阅配置 Prometheus 远程写入

将历史 TSDB 块上传到 Grafana Mimir

Grafana Mimir 支持上传历史 TSDB 块,特别是来自 Prometheus 的块。要为所有租户或特定租户启用此功能,请参阅配置 TSDB 块上传

Prometheus 将 TSDB 块存储在 `--storage.tsdb.path` 标志指定的路径中。

要在 TSDB `` 中查找所有块目录,请运行以下命令

bash
find <STORAGE TSDB PATH> -name chunks -exec dirname {} \;

Grafana Mimir 支持多个租户,并按租户存储块。在禁用多租户的情况下,存在一个名为 `anonymous` 的单租户。

使用 Grafana mimirtool 将每个块(例如通过上一个命令识别的块)上传到 Grafana Mimir

bash
mimirtool backfill --address=http://<mimir-hostname> --id=<tenant> <block1> <block2>...

注意

如果你需要对 Grafana Mimir 进行身份验证,可以通过 `--key` 标志提供 API 密钥,例如 `--key=$(cat token.txt)`。

Grafana Mimir 对每个块的元数据执行一些净化和验证。因此,由于不支持的标签,它会拒绝 Thanos 块。作为一种变通方法,如果需要上传 Thanos 块,请将块直接上传到 Grafana Mimir 块桶中,前缀为 `//`。

块元数据

每个块都有一个 `meta.json` 元数据文件,Grafana Mimir、Prometheus 和 Thanos 使用该文件来识别块内容。每个项目都有自己的元数据约定。

在 Grafana Mimir 2.1(或更早)版本中,摄取器在 `meta.json` 文件中添加了一个外部标签,用于标识拥有该块的租户。

在 Grafana Mimir 2.2(或更高)版本中,块不再包含标识租户的标签。

注意

来自 Prometheus 的块不包含存储在其中的任何外部标签。只有来自 Thanos 的块使用标签。

注意

如果你使用 mimirtool 上传块时遇到 HTTP 错误 413 “Request Entity Too Large”,并且正在使用 Nginx 作为反向代理,则上传的块大小可能超出了 Nginx 默认允许的最大请求体大小。要解决此问题

通过运行以下命令确定你尝试上传的块的当前大小(默认情况下,块大小约为 500MB,但可能会因 Prometheus 或 Thanos 的配置而异。)

bash
find <path/to/blocks> -name 'chunks' -printf '%s\n' | numfmt --to=iec-i

这以人类可读的格式显示了每个块的 chunks 目录大小。增加 Nginx 配置中的 `client_max_body_size` 指令

对于手动 Nginx 部署,打开 Nginx 配置文件(例如,`/etc/nginx/nginx.conf`),并在 Mimir 端点的服务器块内将 `client_max_body_size` 指令设置为比你正在上传的块的最大大小大约 5% 的值。例如

server {
    ...
    client_max_body_size 540M;
    ...
}
location / {
    ...
    client_max_body_size 540M;
    ...
}

对于 Mimir 的 Helm 部署,你可以在 Helm values 文件中将 `gateway.nginx.config.clientMaxBodySize` 值设置为更高的值,例如

yaml
gateway:
  nginx:
    config:
      clientMaxBodySize: 540M

应用配置更改

对于手动 Nginx 部署,保存配置文件并重新加载 Nginx

bash
sudo nginx -s reload

对于 Helm 部署,使用更新后的 values 文件升级你的 Mimir 版本

bash
helm upgrade <release-name> <chart-name> -f values.yaml

增加 `client_max_body_size` 设置后,你就可以上传块而不会遇到 413 错误。

Thanos 特定功能的注意事项

Thanos 要求 Prometheus 配置外部标签。当 Thanos sidecar 上传块时,它会将 Prometheus 的外部标签包含在块内的 `meta.json` 文件中。当你查询块时,Thanos 会在查询结果返回的时间序列中注入 Prometheus 的外部标签。Thanos 还使用标签对复制数据进行去重。

如果你想通过 Grafana Mimir 使用 Thanos 中的现有块,需要考虑一些事项

Grafana Mimir 不会在查询结果中注入外部标签。这意味着,在使用 Grafana Mimir 查询时,原本由 Thanos 创建的块不会在结果中包含其外部标签。如果你的查询结果需要包含外部标签,目前在 Grafana Mimir 中无法实现。

Grafana Mimir 在查询块时不会遵循 Thanos 中配置的去重标签。为了获得最佳查询性能,对于每对 HA Prometheus 副本,只需上传其中一个副本的 Thanos 块。如果你上传两个副本的块,Mimir 返回的查询结果将包含来自两个副本的样本。

Grafana Mimir 不支持 Thanos 的下采样功能。为确保查询结果的正确性,请仅将原始(原始)Thanos 块上传到 Mimir 的存储中。如果你同时上传包含下采样数据的块(即 `meta.json` 文件中 `Resolution` 字段非零的块),Grafana Mimir 将在查询时将原始样本和下采样样本合并在一起。这可能会导致查询返回不正确的结果。

将历史 TSDB 块从 Thanos 迁移到 Grafana Mimir

  1. 将块从 Thanos 的桶复制到中间桶。

    在你的云提供商中创建一个中间对象存储桶(例如 Amazon S3 或 GCS),你可以在将历史块上传到 Mimir 桶之前将它们复制到其中并进行处理。

    提示

    在 `screen` 或 `tmux` 会话中运行命令,以避免任何中断,因为这些步骤可能需要一些时间,具体取决于数据量。

    对于 Amazon S3,使用 `aws` 工具

    bash
    aws s3 cp --recursive s3://<THANOS-BUCKET> s3://<INTERMEDIATE-MIMIR-BUCKET>/

    对于 Google Cloud Storage (GCS),使用 `gsutil` 工具

    bash
    gsutil -m cp -r gs://<THANOS-BUCKET>/* gs://<INTERMEDIATE-MIMIR-BUCKET>/

    复制过程完成后,检查桶中的块,确保它们从 Thanos 的角度来看是有效的。

    bash
    thanos tools bucket inspect \
        --objstore.config-file bucket.yaml
  2. 删除下采样的块。

    Mimir 不理解来自 Thanos 的下采样块,例如 `meta.json` 文件中 `Resolution` 字段非零的块。因此,你需要从此桶中移除 5m 和 1h 的下采样块。

    将下采样的块标记为删除

    bash
    thanos tools bucket retention \
        --objstore.config-file bucket.yaml \
        --retention.resolution-1h=1s \
        --retention.resolution-5m=1s \
        --retention.resolution-raw=0s

    清理标记为删除的块。

    bash
    thanos tools bucket cleanup \
        --objstore.config-file bucket.yaml \
        --delete-delay=0
  3. 删除重复的块。

    如果部署了两个 Prometheus 实例副本以实现高可用性,则仅上传其中一个副本的块,并丢弃另一个副本的块。

    bash
    # Get list of all blocks in the bucket
    thanos tools bucket inspect \
        --objstore.config-file bucket.yaml \
        --output=tsv > blocks.tsv
    
    # Find blocks from replica that we will drop
    cat blocks.tsv| grep prometheus_replica=<PROMETHEUS-REPLICA-TO-DROP> \
        | awk '{print $1}' > blocks_to_drop.tsv
    
    # Mark found blocks for deletion
    for ID in $(cat blocks_to_drop.tsv)
    do
        thanos tools bucket mark \
           --marker="deletion-mark.json" \
           --objstore.config-file bucket.yaml \
           --details="Removed as duplicate" \
           --id $ID
    done

    注意

    你必须将 `prometheus_replica` 替换为你设置中区分 Prometheus 副本的唯一标签。

    再次清理标记为删除的重复块

    bash
    thanos tools bucket cleanup \
        --objstore.config-file bucket.yaml \
        --delete-delay=0

    提示

    如果你想准确地可视化块中发生的情况,包括块来源、外部标签、压缩级别等,可以使用以下命令将输出导出为 CSV 并导入到电子表格中

    bash
    thanos tools bucket inspect \
        --objstore.config-file bucket-prod.yaml \
        --output=csv > thanos-blocks.csv
  4. 使用外部标签重新标记块。

    Mimir 不会将 `meta.json` 文件中的外部标签注入到查询结果中。因此,你需要使用所需的外部标签重新标记 `meta.json` 文件中的块。

    提示

    你可以从导入的 CSV 文件中获取每个块的 `meta.json` 文件中的外部标签,并据此构建重写配置。

    创建一个类似于以下的重写配置

    bash
    # relabel-config.yaml
    - action: replace
      target_label: "<LABEL-KEY>"
      replacement: "<LABEL-VALUE>"

    执行重写干运行,确认一切正常。

    bash
    # Get list of all blocks in the bucket after removing the depuplicate and downsampled blocks.
    thanos tools bucket inspect \
        --objstore.config-file bucket.yaml \
        --output=tsv > blocks-to-rewrite.tsv
    
    # Check if rewrite of the blocks with external labels is working as expected.
    for ID in $(cat blocks-to-rewrite.tsv)
    do
        thanos tools bucket rewrite \
            --objstore.config-file bucket.yaml \
            --rewrite.to-relabel-config-file relabel-config.yaml \
            --dry-run \
            --id $ID
    done

    通过 `--dry-run` 确认重写按预期工作后,使用 `--no-dry-run` 标志应用更改。请记住包含 `--delete-blocks`,否则原始块将不会标记为删除。

    bash
    # Rewrite the blocks with external labels and mark the original blocks for deletion.
    for ID in $(cat blocks-to-rewrite.tsv)
    do
        thanos tools bucket rewrite  \
            --objstore.config-file bucket.yaml \
            --rewrite.to-relabel-config-file relabel-config.yaml \
            --no-dry-run \
            --delete-blocks \
            --id $ID
    done

    每个块的重新标记输出将如下所示。

    console
    level=info ts=2022-10-10T13:03:32.032820262Z caller=factory.go:50 msg="loading bucket configuration"
    level=info ts=2022-10-10T13:03:32.516953867Z caller=tools_bucket.go:1160 msg="downloading block" source=01GEGWPME2187SVFH63G8DH7KH
    level=info ts=2022-10-10T13:03:35.825009556Z caller=tools_bucket.go:1197 msg="changelog will be available" file=/tmp/thanos-  rewrite/01GF0ZWPWGEPHG5NV79NH9KMPV/change.log
    level=info ts=2022-10-10T13:03:35.836953593Z caller=tools_bucket.go:1212 msg="starting rewrite for block" source=01GEGWPME2187SVFH63G8DH7KH  new=01GF0ZWPWGEPHG5NV79NH9KMPV toDelete= toRelabel="- action: replace\n  target_label: \"cluster\"\n  replacement: \"prod-cluster\"\n"
    level=info ts=2022-10-10T13:04:47.57624244Z caller=compactor.go:42 msg="processed 10.00% of 701243 series"
    level=info ts=2022-10-10T13:04:53.4046885Z caller=compactor.go:42 msg="processed 20.00% of 701243 series"
    level=info ts=2022-10-10T13:04:59.649337602Z caller=compactor.go:42 msg="processed 30.00% of 701243 series"
    level=info ts=2022-10-10T13:05:02.986219042Z caller=compactor.go:42 msg="processed 40.00% of 701243 series"
    level=info ts=2022-10-10T13:05:05.990498497Z caller=compactor.go:42 msg="processed 50.00% of 701243 series"
    level=info ts=2022-10-10T13:05:09.349918024Z caller=compactor.go:42 msg="processed 60.00% of 701243 series"
    level=info ts=2022-10-10T13:05:12.040895624Z caller=compactor.go:42 msg="processed 70.00% of 701243 series"
    level=info ts=2022-10-10T13:05:15.253899238Z caller=compactor.go:42 msg="processed 80.00% of 701243 series"
    level=info ts=2022-10-10T13:05:18.471471014Z caller=compactor.go:42 msg="processed 90.00% of 701243 series"
    level=info ts=2022-10-10T13:05:21.536267363Z caller=compactor.go:42 msg="processed 100.00% of 701243 series"
    level=info ts=2022-10-10T13:05:21.536466158Z caller=tools_bucket.go:1222 msg="wrote new block after modifications; flushing" source=01GEGWPME2187SVFH63G8DH7KH new=01GF0ZWPWGEPHG5NV79NH9KMPV
    level=info ts=2022-10-10T13:05:28.675240198Z caller=tools_bucket.go:1231 msg="uploading new block" source=01GEGWPME2187SVFH63G8DH7KH new=01GF0ZWPWGEPHG5NV79NH9KMPV
    level=info ts=2022-10-10T13:05:38.922348564Z caller=tools_bucket.go:1241 msg=uploaded source=01GEGWPME2187SVFH63G8DH7KH new=01GF0ZWPWGEPHG5NV79NH9KMPV
    level=info ts=2022-10-10T13:05:38.979696873Z caller=block.go:203 msg="block has been marked for deletion" block=01GEGWPME2187SVFH63G8DH7KH
    level=info ts=2022-10-10T13:05:38.979832767Z caller=tools_bucket.go:1249 msg="rewrite done" IDs=01GEGWPME2187SVFH63G8DH7KH
    level=info ts=2022-10-10T13:05:38.980197796Z caller=main.go:161 msg=exiting

    清理标记为删除的原始块。

    bash
    thanos tools bucket cleanup \
        --objstore.config-file bucket.yaml \
        --delete-delay=0

    注意

    如果有多个 Prometheus 集群,并行重新标记每个集群可能会加快整个过程。

    获取每个集群的块列表,并分别处理。

    bash
    thanos tools bucket inspect \
        --objstore.config-file bucket.yaml \
        --output=tsv \
        | grep <PROMETHEUS-CLUSTER-NAME> \
        | awk '{print $1}' > prod-blocks.tsv
    bash
    for ID in `cat prod-blocks.tsv`
    do
        thanos tools bucket rewrite  \
           --objstore.config-file bucket.yaml \
           --rewrite.to-relabel-config-file relabel-config.yaml \
           --delete-blocks \
           --no-dry-run \
           --id $ID
    done
  5. 从 `meta.json` 中删除外部标签。

    Mimir 的 Compactor 将无法将带有外部标签的块与自身 `meta.json` 中没有此类标签的 Mimir 块进行压缩。因此,在将这些块复制到 Mimir 桶之前,必须删除这些外部标签。

    使用以下脚本从 `meta.json` 中删除标签。

    对于 Amazon S3,使用 `aws` 工具

    bash
    #!/bin/bash
    
    BUCKET="XXX"
    
    echo "Fetching list of meta.json files (this can take a while if there are many blocks)"
    aws s3 ls $BUCKET --recursive | awk '{print $4}' | grep meta.json | grep -v meta.json.orig > meta-files.txt
    
    echo "Processing meta.json files"
    for FILE in $(cat meta-files.txt); do
       echo "Removing Thanos labels from $FILE"
       ORIG_META_JSON=$(aws s3 cp s3://$BUCKET/$FILE -)
       UPDATED_META_JSON=$(echo "$ORIG_META_JSON" | jq "del(.thanos.labels)")
    
       if ! diff -u <( echo "$ORIG_META_JSON" | jq . ) <( echo "$UPDATED_META_JSON" | jq .) > /dev/null; then
         echo "Backing up $FILE to $FILE.orig"
         aws s3 cp "s3://$BUCKET/$FILE" "s3://$BUCKET/$FILE.orig"
         echo "Uploading modified $FILE"
         echo "$UPDATED_META_JSON" | aws s3 cp - "s3://$BUCKET/$FILE"
       else
         echo "No diff for $FILE"
       fi
    done

    对于 Google Cloud Storage (GCS),使用 `gsutil` 工具

    bash
    #!/bin/bash
    
    BUCKET="GCS Bucket name"
    
    echo "Fetching list of meta.json files (this can take a while if there are many blocks)"
    gsutil ls "gs://$BUCKET/*/meta.json" > meta-files.txt
    
    echo "Processing meta.json files"
    for FILE in $(cat meta-files.txt); do
       echo "Removing Thanos labels from $FILE"
       ORIG_META_JSON=$(gsutil cat "$FILE")
       UPDATED_META_JSON=$(echo "$ORIG_META_JSON" | jq "del(.thanos.labels)")
    
       if ! diff -u <( echo "$ORIG_META_JSON" | jq . ) <( echo "$UPDATED_META_JSON" | jq .) > /dev/null; then
          echo "Backing up $FILE to $FILE.orig"
          gsutil cp "$FILE" "$FILE.orig"
          echo "Uploading modified $FILE"
          echo "$UPDATED_META_JSON" | gsutil cp - "$FILE"
       else
          echo "No diff for $FILE"
       fi
    done
  6. 将块从中间桶复制到 Mimir 桶。

    对于 Amazon S3,使用 `aws` 工具

    bash
    aws s3 cp --recursive s3://<INTERMEDIATE-MIMIR-BUCKET> s3://<MIMIR-AWS-BUCKET>/<TENANT>/

    对于 Google Cloud Storage (GCS),使用 `gsutil` 工具

    bash
    gsutil -m cp -r gs://<INTERMEDIATE-MIMIR-BUCKET> gs://<MIMIR-GCS-BUCKET>/<TENANT>/

    历史块在上传后不会立即用于查询,因为包含所有可用块列表的桶索引首先需要由 Compactor 更新。Compactor 通常每 15 分钟执行一次更新。更新完成后,其他组件(例如 Querier 或 Store-gateway)才能处理历史块,并且可以通过 Grafana 查询这些块。

  7. 检查 `store-gateway` HTTP 端点 `http:///store-gateway/tenant//blocks`,验证上传的块是否存在。