Thanos源码专题【左扬精讲】——Thanos Compact 组件(release-0.26)源码阅读和分析(详解 cmd/compact.go )
Thanos Compact 组件(release-0.26)源码阅读和分析(详解 cmd/compact.go )
https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/compact.go
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
package main
import (
"context"
"fmt"
"os"
"path"
"strconv"
"strings"
"sync"
"time"
"github.com/alecthomas/units"
extflag "github.com/efficientgo/tools/extkingpin"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/oklog/run"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/common/model"
"github.com/prometheus/common/route"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/tsdb"
blocksAPI "github.com/thanos-io/thanos/pkg/api/blocks"
"github.com/thanos-io/thanos/pkg/block"
"github.com/thanos-io/thanos/pkg/block/metadata"
"github.com/thanos-io/thanos/pkg/compact"
"github.com/thanos-io/thanos/pkg/compact/downsample"
"github.com/thanos-io/thanos/pkg/component"
"github.com/thanos-io/thanos/pkg/dedup"
"github.com/thanos-io/thanos/pkg/extkingpin"
"github.com/thanos-io/thanos/pkg/extprom"
extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http"
"github.com/thanos-io/thanos/pkg/logging"
"github.com/thanos-io/thanos/pkg/objstore/client"
"github.com/thanos-io/thanos/pkg/prober"
"github.com/thanos-io/thanos/pkg/runutil"
httpserver "github.com/thanos-io/thanos/pkg/server/http"
"github.com/thanos-io/thanos/pkg/store"
"github.com/thanos-io/thanos/pkg/tracing"
"github.com/thanos-io/thanos/pkg/ui"
)
var (
// 默认的compactions是:1小时,2小时,8小时,2天,14天。
compactions = compactionSet{
1 * time.Hour,
2 * time.Hour,
8 * time.Hour,
2 * 24 * time.Hour,
14 * 24 * time.Hour,
}
)
type compactionSet []time.Duration
// String 方法返回 compactionSet 的字符串表示形式。
// 该字符串是一个逗号分隔的字符串,每个元素都表示为 "i=ch" 的形式,
// 其中 i 是 compactionSet 的索引,ch 是 compactionSet 中对应元素的小时数。
func (cs compactionSet) String() string {
// 创建一个字符串切片,长度为 compactionSet 的长度
result := make([]string, len(cs))
// 遍历 compactionSet
for i, c := range cs {
// 将每个元素格式化为 "i=ch" 的形式,其中 c.Hours() 表示小时数。
result[i] = fmt.Sprintf("%d=%dh", i, int(c.Hours()))
}
// 使用逗号加空格将结果切片中的元素连接起来。返回结果:["0=1h", "1=2h", "2=8h", "3=48h", "4=336h"]
return strings.Join(result, ", ")
}
// levels returns set of compaction levels not higher than specified max compaction level.
// levels 函数接收一个 compactionSet 类型的参数 cs 和一个 int 类型的参数 maxLevel,
// 返回一个 []int64 类型的切片和一个 error 类型的错误。
// 该函数的功能是返回给定 compactionSet 集合中前 maxLevel 个级别的值,
// 每个级别的值以毫秒为单位转换为 int64 类型。
//
// 如果 maxLevel 大于等于 cs 的长度,则返回一个 nil 切片和一个错误信息,
// 错误信息为 "level is bigger then default set of %d",其中 %d 为 cs 的长度。
//
// 如果 maxLevel 小于 cs 的长度,则创建一个长度为 maxLevel+1 的切片 levels,
// 用于存储每个级别的值。然后遍历 cs[:maxLevel+1] 范围内的元素,
// 将每个元素除以 time.Millisecond,然后转换为 int64 类型后存储到 levels 中。
//
// 最后,返回存储级别值的切片 levels 和 nil 错误。
func (cs compactionSet) levels(maxLevel int) ([]int64, error) {
// 如果 maxLevel 大于等于 cs 的长度,则返回错误
if maxLevel >= len(cs) {
return nil, errors.Errorf("level is bigger then default set of %d", len(cs))
}
// 创建一个长度为 maxLevel+1 的切片,用于存储每个级别的值
levels := make([]int64, maxLevel+1)
// 遍历 cs[:maxLevel+1] 范围内的元素,并将每个元素转换为 int64 类型后存储到 levels 中
for i, c := range cs[:maxLevel+1] {
// 将每个元素除以 time.Millisecond,然后转换为 int64 类型
levels[i] = int64(c / time.Millisecond)
}
// 返回存储级别值的切片和 nil 错误
return levels, nil
}
// maxLevel returns max available compaction level.
// maxLevel 返回 compactionSet 的最大层级的索引。
//
// 该函数返回 compactionSet 的长度减一,即最大层级的索引。
func (cs compactionSet) maxLevel() int {
// 返回 compactionSet 的长度减一,即最大层级的索引
return len(cs) - 1
}
func registerCompact(app *extkingpin.App) {
// 创建一个命令对象 cmd,用于执行压缩操作
cmd := app.Command(component.Compact.String(), "Continuously compacts blocks in an object store bucket.")
// 创建一个压缩配置对象 conf
conf := &compactConfig{}
// 注册命令行参数到 conf 中,包括对象存储配置、压缩级别等参数
conf.registerFlag(cmd)
// 设置命令执行前的准备工作函数,该函数在命令执行前被调用,用于设置命令的参数和参数解析器
cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {
// 执行压缩操作
return runCompact(g, logger, tracer, reg, component.Compact, *conf, getFlagsMap(cmd.Flags()))
})
}
type compactMetrics struct {
halted prometheus.Gauge // halted 是一个 Gauge 类型的指标,用于表示压缩操作是否已停止
retried prometheus.Counter // retried 是一个 Counter 类型的指标,用于记录可重试的压缩器错误的总次数
iterations prometheus.Counter // iterations 是一个 Counter 类型的指标,用于记录压缩操作的总次数
cleanups prometheus.Counter // cleanups 是一个 Counter 类型的指标,用于记录并发清理循环的总次数
partialUploadDeleteAttempts prometheus.Counter // partialUploadDeleteAttempts 是一个 Counter 类型的指标,用于记录已尝试删除的假定中止且仅部分上传的块的总次数
blocksCleaned prometheus.Counter // blocksCleaned 是一个 Counter 类型的指标,用于记录已清理的块的总次数
blockCleanupFailures prometheus.Counter // blockCleanupFailures 是一个 Counter 类型的指标,用于记录块清理失败的次数
blocksMarked *prometheus.CounterVec // blocksMarked 是一个 CounterVec 类型的指标,用于记录标记的块的总次数
garbageCollectedBlocks prometheus.Counter // garbageCollectedBlocks 是一个 Counter 类型的指标,用于记录垃圾收集的块的总次数
}
// newCompactMetrics 创建一个新的compactMetrics对象,用于跟踪和记录Thanos Compactor 组件的性能指标。
// 参数:
// - reg: *prometheus.Registry,Prometheus注册器,用于注册指标。
// - deleteDelay: time.Duration,配置的删除延迟时间。
//
// 返回值:
// - *compactMetrics,包含多个Prometheus指标的compactMetrics对象。
func newCompactMetrics(reg *prometheus.Registry, deleteDelay time.Duration) *compactMetrics {
/*
这段代码创建并注册了一个名为"thanos_delete_delay_seconds"的Prometheus Gauge指标,该指标描述了配置的删除延迟(以秒为单位)。每次Prometheus抓取指标时,它都会调用提供的函数来获取当前的删除延迟值(以秒为单位)。这使得Prometheus能够监控和记录这个值的变化,进而用于监控和警报等目的。
promauto.With(reg).NewGaugeFunc:
promauto是Prometheus客户端库中的一个包,它提供了自动注册指标的便捷方法。With(reg)是一个方法调用,其中reg是一个prometheus.Registerer接口的实现,通常是一个prometheus.Registry实例。这个方法返回一个配置了对象,允许你创建并自动注册指标。
NewGaugeFunc是一个方法,用于创建一个新的Gauge类型的指标。Gauge指标用于表示可以任意上下浮动的数值,例如当前内存使用量、队列长度等。与普通的Gauge不同,NewGaugeFunc接受一个函数作为参数,这个函数在每次Prometheus抓取指标时被调用以获取当前的数值。
prometheus.GaugeOpts:
GaugeOpts是一个结构体,用于配置Gauge指标的名称、帮助信息等属性。它通常作为NewGaugeFunc方法的参数之一传入,以定义新创建的Gauge指标的具体行为和属性。
Name:指标的名称,这里设置为"thanos_delete_delay_seconds"。
Help:关于这个指标的描述,这里设置为"Configured delete delay in seconds."。
*/
_ = promauto.With(reg).NewGaugeFunc(prometheus.GaugeOpts{
Name: "thanos_delete_delay_seconds",
Help: "Configured delete delay in seconds.",
}, func() float64 { // func() float64 { return deleteDelay.Seconds() }是一个匿名函数,它不接受参数并返回一个float64类型的值。这个函数在每次Prometheus抓取指标时被调用。
return deleteDelay.Seconds() // Seconds()方法将这个持续时间转换为秒,返回的秒数作为指标的当前值。
})
m := &compactMetrics{}
/*
创建一个新的Gauge指标,用于表示Compactor是否因意外错误而停止。
使用promauto包(Prometheus自动注册工具)来创建一个新的Gauge指标。
promauto.With(reg).NewGauge函数接受一个prometheus.GaugeOpts结构体作为参数,该结构体定义了指标的名称(Name)和帮助信息(Help)。
在这个例子中,指标的名称是"thanos_compact_halted",帮助信息是"Set to 1 if the compactor halted due to an unexpected error.",意思是如果Compactor因意外错误而停止,则将该指标设置为1。
*/
m.halted = promauto.With(reg).NewGauge(prometheus.GaugeOpts{
Name: "thanos_compact_halted",
Help: "Set to 1 if the compactor halted due to an unexpected error.",
})
// 将新创建的Gauge指标的初始值设置为0。这意味着在 Compactor 正常运行时,该指标应该保持为0。
m.halted.Set(0)
// 创建一个新的Counter指标,用于表示Compactor在可重试错误后重试的总次数
m.retried = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_retries_total",
Help: "Total number of retries after retriable compactor error.",
})
// 创建一个新的Counter指标,用于表示成功执行的迭代次数
m.iterations = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_iterations_total",
Help: "Total number of iterations that were executed successfully.",
})
// 创建一个新的Counter指标,用于表示成功执行的并发清理循环次数
m.cleanups = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_block_cleanup_loops_total",
Help: "Total number of concurrent cleanup loops of partially uploaded blocks and marked blocks that were executed successfully.",
})
// 创建一个新的Counter指标,用于表示启动删除假设已中止且仅部分上传的块的总次数
m.partialUploadDeleteAttempts = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_aborted_partial_uploads_deletion_attempts_total",
Help: "Total number of started deletions of blocks that are assumed aborted and only partially uploaded.",
})
// 创建一个新的Counter指标,用于表示在Compactor中删除的块的总数
m.blocksCleaned = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_blocks_cleaned_total",
Help: "Total number of blocks deleted in compactor.",
})
// 创建一个新的Counter指标,用于表示在Compactor中删除块时遇到的失败次数
m.blockCleanupFailures = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_block_cleanup_failures_total",
Help: "Failures encountered while deleting blocks in compactor.",
})
// 创建一个新的CounterVec指标,用于表示在Compactor中标记的块的总数,带有标签"marker"和"reason"
m.blocksMarked = promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
Name: "thanos_compact_blocks_marked_total",
Help: "Total number of blocks marked in compactor.",
}, []string{"marker", "reason"})
// 设置标记的块标签值
m.blocksMarked.WithLabelValues(metadata.NoCompactMarkFilename, metadata.OutOfOrderChunksNoCompactReason)
m.blocksMarked.WithLabelValues(metadata.NoCompactMarkFilename, metadata.IndexSizeExceedingNoCompactReason)
m.blocksMarked.WithLabelValues(metadata.DeletionMarkFilename, "")
// 创建一个新的Counter指标,用于表示Compactor标记为删除的块的总数
m.garbageCollectedBlocks = promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "thanos_compact_garbage_collected_blocks_total",
Help: "Total number of blocks marked for deletion by compactor.",
})
return m
}
// runCompact 是启动和管理 Thanos 组件压缩过程的主要函数。
// 它配置压缩器,设置指标,初始化 HTTP 服务器,并管理压缩过程的生命周期。
//
// 参数:
// - g: 用于管理压缩过程生命周期的 run.Group。
// - logger: 用于记录信息和错误的日志记录器。
// - tracer: 用于跟踪操作的 opentracing.Tracer。
// - reg: 用于注册指标的 prometheus.Registry。
// - component: 此压缩器管理的组件。
// - conf: 包含压缩器配置的 compactConfig。
// - flagsMap: 包含附加配置的标志名称到其值的映射。
//
// 返回值:
// - rerr: 如果在设置或运行压缩器时出现问题,则返回一个错误,否则返回 nil。
func runCompact(
g *run.Group, // 用于管理压缩过程生命周期的 run.Group。
logger log.Logger, // 用于记录信息和错误的日志记录器。
tracer opentracing.Tracer, // 用于跟踪操作的 opentracing.Tracer。
reg *prometheus.Registry, // 用于注册指标的 prometheus.Registry。
component component.Component, // 此压缩器管理的组件。
conf compactConfig, // 包含压缩器配置的 compactConfig。
flagsMap map[string]string, // 包含附加配置的标志名称到其值的映射。
) (rerr error) {
deleteDelay := time.Duration(conf.deleteDelay) // 删除延迟时间
compactMetrics := newCompactMetrics(reg, deleteDelay) // 创建并初始化用于跟踪压缩性能指标的 compactMetrics 对象。
downsampleMetrics := newDownsampleMetrics(reg) // 创建并初始化用于跟踪下采样性能指标的 downsampleMetrics 对象。
// 创建一个用于管理压缩过程的压缩器对象。
httpProbe := prober.NewHTTP()
// Combine 方法用于组合多个探针为一个单一的探针。这里将 httpProbe 和一个用于监控指标注册表的探针组合在一起。
statusProber := prober.Combine(
httpProbe,
prober.NewInstrumentation(component, logger, extprom.WrapRegistererWithPrefix("thanos_", reg)),
)
// httpserver.New 创建一个新的 HTTP 服务器的实例。
srv := httpserver.New(
logger, // 用于记录 HTTP 服务器相关信息的日志记录器。
reg, // 用于注册 HTTP 服务器指标的 prometheus.Registry。
component, // 此 HTTP 服务器管理的组件。
httpProbe, // 用于监控 HTTP 请求的探针。
httpserver.WithListen(conf.http.bindAddress), // 配置 HTTP 服务器的监听地址。
httpserver.WithGracePeriod(time.Duration(conf.http.gracePeriod)), // 配置 HTTP 服务器的优雅关闭时间。
httpserver.WithTLSConfig(conf.http.tlsConfig), // 配置 HTTP 服务器的 TLS 配置。
)
g.Add(func() error {
// 启动 HTTP 服务器。
statusProber.Healthy()
return srv.ListenAndServe() // 返回 HTTP 服务器的错误。
}, func(err error) { // 当 HTTP 服务器启动失败或关闭时执行的回调函数。
// 当 HTTP 服务器启动失败时,将探针状态设置为不可用。
statusProber.NotReady(err)
// 当 HTTP 服务器关闭时,将探针状态设置为不可用。
defer statusProber.NotHealthy(err)
// 关闭 HTTP 服务器的优雅方式。
srv.Shutdown(err)
})
// confContentYaml 是一个包含对象存储配置的 YAML 字符串。 objStore 是一个包含对象存储配置的对象。
confContentYaml, err := conf.objStore.Content()
if err != nil {
return err
}
// client.NewBucket 创建一个新的对象存储客户端。
bkt, err := client.NewBucket(logger, confContentYaml, reg, component.String())
if err != nil {
return err
}
// selectorRelabelConf 是一个包含对象存储选择器重新标签配置的对象。
relabelContentYaml, err := conf.selectorRelabelConf.Content()
if err != nil {
return errors.Wrap(err, "get content of relabel configuration")
}
// ParseRelabelConfig 解析对象存储选择器重新标签配置。
relabelConfig, err := block.ParseRelabelConfig(relabelContentYaml, block.SelectorSupportedRelabelActions)
if err != nil {
return err
}
// Ensure we close up everything properly.
// 确保在发生错误时正确关闭对象存储客户端。
defer func() {
if err != nil {
runutil.CloseWithLogOnErr(logger, bkt, "bucket client")
}
}()
// While fetching blocks, we filter out blocks that were marked for deletion by using IgnoreDeletionMarkFilter.
// The delay of deleteDelay/2 is added to ensure we fetch blocks that are meant to be deleted but do not have a replacement yet.
// This is to make sure compactor will not accidentally perform compactions with gap instead.
// 当获取块时,我们使用 IgnoreDeletionMarkFilter 过滤掉被标记为删除的块。延迟删除延迟的一半是为了确保我们获取了将被删除但还没有替换的块。这是为了确保压缩器不会意外地执行带有间隙的压缩。
// ignoreDeletionMarkFilter 是一个用于过滤删除标记的对象。用于过滤删除标记的块。
ignoreDeletionMarkFilter := block.NewIgnoreDeletionMarkFilter(logger, bkt, deleteDelay/2, conf.blockMetaFetchConcurrency)
// duplicateBlocksFilter 是一个用于过滤重复块的对象。
duplicateBlocksFilter := block.NewDeduplicateFilter(conf.blockMetaFetchConcurrency)
// noCompactMarkerFilter 是一个用于过滤不需要压缩的块的对象。
noCompactMarkerFilter := compact.NewGatherNoCompactionMarkFilter(logger, bkt, conf.blockMetaFetchConcurrency)
// labelShardedMetaFilter 是一个用于过滤标签分片的元数据对象。
labelShardedMetaFilter := block.NewLabelShardedMetaFilter(relabelConfig)
// consistencyDelayMetaFilter 是一个用于过滤一致性延迟的元数据对象。
consistencyDelayMetaFilter := block.NewConsistencyDelayMetaFilter(logger, conf.consistencyDelay, extprom.WrapRegistererWithPrefix("thanos_", reg))
// timePartitionMetaFilter 是一个用于过滤时间分区的元数据对象。
timePartitionMetaFilter := block.NewTimePartitionMetaFilter(conf.filterConf.MinTime, conf.filterConf.MaxTime)
// baseMetaFetcher 是一个用于获取块元数据的对象。
baseMetaFetcher, err := block.NewBaseFetcher(logger, conf.blockMetaFetchConcurrency, bkt, "", extprom.WrapRegistererWithPrefix("thanos_", reg))
if err != nil {
// 如果创建 baseMetaFetcher 失败,则返回错误。
return errors.Wrap(err, "create meta fetcher")
}
// enableVerticalCompaction 是一个布尔值,表示是否启用垂直压缩。如果指定了 dedupReplicaLabels,则启用垂直压缩。
// 垂直压缩是什么?
// 垂直压缩是指将相同时间戳的相同标签的样本数据压缩在一起,这样可以减少存储空间和提高查询效率。在 Thanos 中,垂直压缩是通过将相同时间戳的样本数据合并到同一个块中来实现的。这样可以减少存储空间的使用,并提高查询效率,因为相同的标签只需要存储一次。
// 为什么不默认开启垂直压缩?
// 垂直压缩会增加压缩和解压缩的开销,因此默认情况下不启用。如果需要启用垂直压缩,可以通过配置文件或命令行参数来指定。如果不需要启用垂直压缩,可以省略配置项或将其设置为 false。
enableVerticalCompaction := conf.enableVerticalCompaction
// 如果指定了 dedupReplicaLabels,则启用垂直压缩。这是因为 dedupReplicaLabels 用于去重复制的标签,而垂直压缩可以将相同时间戳和标签的样本数据合并到同一个块中,从而减少存储空间的使用。因此,如果指定了 dedupReplicaLabels,则启用垂直压缩可以更好地利用 Thanos 的去重复制功能。
if len(conf.dedupReplicaLabels) > 0 {
enableVerticalCompaction = true
level.Info(logger).Log(
"msg", "deduplication.replica-label specified, enabling vertical compaction", "dedupReplicaLabels", strings.Join(conf.dedupReplicaLabels, ","),
)
}
if enableVerticalCompaction { // 如果启用了垂直压缩,则打印日志信息。
level.Info(logger).Log(
"msg", "vertical compaction is enabled", "compact.enable-vertical-compaction", fmt.Sprintf("%v", conf.enableVerticalCompaction),
)
}
var (
// bkt 是一个 Bucket 客户端,用于与对象存储交互。
// blocksAPI.NewBlocksAPI 创建一个新的 Blocks API,用于处理块相关的请求。
// conf.label 是一个字符串,表示要过滤的标签。
// api 是一个 BlocksAPI 客户端,用于处理块相关的请求。
api = blocksAPI.NewBlocksAPI(logger, conf.webConf.disableCORS, conf.label, flagsMap, bkt)
// sy 是一个 Syncer,用于同步块元数据。
sy *compact.Syncer
)
{
// Make sure all compactor meta syncs are done through Syncer.SyncMeta for readability.
// 确保 Syncer.SyncMeta 用于同步块元数据,以提高可读性。
// 创建一个新的 MetaFetcher,用于获取块元数据。
cf := baseMetaFetcher.NewMetaFetcher(
// 创建一个新的 BucketClient,用于与对象存储交互。
extprom.WrapRegistererWithPrefix("thanos_", reg), []block.MetadataFilter{
timePartitionMetaFilter, // 创建一个新的 TimePartitionMetaFilter,用于过滤块元数据。
labelShardedMetaFilter, // 创建一个新的 LabelShardedMetaFilter,用于过滤块元数据。
consistencyDelayMetaFilter, // 创建一个新的 ConsistencyDelayMetaFilter,用于过滤块元数据。
ignoreDeletionMarkFilter, // 创建一个新的 IgnoreDeletionMarkFilter,用于过滤块元数据。
block.NewReplicaLabelRemover(logger, conf.dedupReplicaLabels), // 创建一个新的 ReplicaLabelRemover,用于过滤块元数据。
duplicateBlocksFilter, // 创建一个新的 DuplicateBlocksFilter,用于过滤块元数据。
noCompactMarkerFilter, // 创建一个新的 NoCompactMarkerFilter,用于过滤块元数据。
},
)
// UpdateOnChange 更新块元数据。
cf.UpdateOnChange(
func(blocks []metadata.Meta, err error) /* 创建一个新的回调函数,用于处理块元数据。*/ {
api.SetLoaded(blocks, err) // api.SetLoaded 设置已加载的块元数据。
})
// compact.NewMetaSyncer 创建一个新的 MetaSyncer,用于同步块元数据。
sy, err = compact.NewMetaSyncer(
logger, // 日志记录器。
reg, // 注册器。
bkt, // 对象存储客户端。
cf, // 块元数据获取器。
duplicateBlocksFilter, // 块元数据过滤器。
ignoreDeletionMarkFilter, // 块元数据过滤器。
compactMetrics.blocksMarked.WithLabelValues(metadata.DeletionMarkFilename, ""), // 块元数据标记指标。
compactMetrics.garbageCollectedBlocks, // 垃圾收集块指标。
conf.blockSyncConcurrency) // 块同步并发数。
if err != nil {
// 如果创建 MetaSyncer 失败,则返回错误。
return errors.Wrap(err, "create syncer")
}
}
// 调用compactions.levels方法,传入配置文件中的最大压缩级别conf.maxCompactionLevel,来创建一个新的压缩级别对象levels。如果在这个过程中出现错误,代码会返回一个错误,并使用errors.Wrap函数包装错误信息,以便于调试和错误追踪。
levels, err := compactions.levels(conf.maxCompactionLevel)
if err != nil {
// 如果获取压缩级别失败,则返回错误。
return errors.Wrap(err, "get compaction levels")
}
// compact.NewCompactor 创建一个新的 Compactor,用于处理块压缩。
if conf.maxCompactionLevel < compactions.maxLevel() {
//Max compaction level 是指允许的最大压缩级别。如果配置文件中的最大压缩级别conf.maxCompactionLevel小于compactions.maxLevel(),则记录一条警告日志,指出当前的最大压缩级别低于应该的级别。在这种情况下,为了提高性能和准确性,应该将最大压缩级别设置为默认值。因此,这里记录一条警告日志,以便于开发者或管理员注意到这个问题,并采取相应的措施进行修复。
level.Warn(logger).Log("msg", "Max compaction level is lower than should be", "current", conf.maxCompactionLevel, "default", compactions.maxLevel())
}
ctx, cancel := context.WithCancel(context.Background())
ctx = tracing.ContextWithTracer(ctx, tracer)
defer func() {
if rerr != nil {
cancel()
}
}()
var mergeFunc storage.VerticalChunkSeriesMergeFunc
switch conf.dedupFunc {
case compact.DedupAlgorithmPenalty:
mergeFunc = dedup.NewChunkSeriesMerger()
if len(conf.dedupReplicaLabels) == 0 {
return errors.New("penalty based deduplication needs at least one replica label specified")
}
case "":
mergeFunc = storage.NewCompactingChunkSeriesMerger(storage.ChainedSeriesMerge)
default:
return errors.Errorf("unsupported deduplication func, got %s", conf.dedupFunc)
}
// Instantiate the compactor with different time slices. Timestamps in TSDB
// are in milliseconds.
comp, err := tsdb.NewLeveledCompactor(ctx, reg, logger, levels, downsample.NewPool(), mergeFunc)
if err != nil {
return errors.Wrap(err, "create compactor")
}
var (
compactDir = path.Join(conf.dataDir, "compact")
downsamplingDir = path.Join(conf.dataDir, "downsample")
)
if err := os.MkdirAll(compactDir, os.ModePerm); err != nil {
return errors.Wrap(err, "create working compact directory")
}
if err := os.MkdirAll(downsamplingDir, os.ModePerm); err != nil {
return errors.Wrap(err, "create working downsample directory")
}
grouper := compact.NewDefaultGrouper(
logger,
bkt,
conf.acceptMalformedIndex,
enableVerticalCompaction,
reg,
compactMetrics.blocksMarked.WithLabelValues(metadata.DeletionMarkFilename, ""),
compactMetrics.garbageCollectedBlocks,
compactMetrics.blocksMarked.WithLabelValues(metadata.NoCompactMarkFilename, metadata.OutOfOrderChunksNoCompactReason),
metadata.HashFunc(conf.hashFunc),
)
tsdbPlanner := compact.NewPlanner(logger, levels, noCompactMarkerFilter)
planner := compact.WithLargeTotalIndexSizeFilter(
tsdbPlanner,
bkt,
int64(conf.maxBlockIndexSize),
compactMetrics.blocksMarked.WithLabelValues(metadata.NoCompactMarkFilename, metadata.IndexSizeExceedingNoCompactReason),
)
blocksCleaner := compact.NewBlocksCleaner(logger, bkt, ignoreDeletionMarkFilter, deleteDelay, compactMetrics.blocksCleaned, compactMetrics.blockCleanupFailures)
compactor, err := compact.NewBucketCompactor(
logger,
sy,
grouper,
planner,
comp,
compactDir,
bkt,
conf.compactionConcurrency,
conf.skipBlockWithOutOfOrderChunks,
)
if err != nil {
return errors.Wrap(err, "create bucket compactor")
}
retentionByResolution := map[compact.ResolutionLevel]time.Duration{
compact.ResolutionLevelRaw: time.Duration(conf.retentionRaw),
compact.ResolutionLevel5m: time.Duration(conf.retentionFiveMin),
compact.ResolutionLevel1h: time.Duration(conf.retentionOneHr),
}
if retentionByResolution[compact.ResolutionLevelRaw].Milliseconds() != 0 {
// If downsampling is enabled, error if raw retention is not sufficient for downsampling to occur (upper bound 10 days for 1h resolution)
if !conf.disableDownsampling && retentionByResolution[compact.ResolutionLevelRaw].Milliseconds() < downsample.ResLevel1DownsampleRange {
return errors.New("raw resolution must be higher than the minimum block size after which 5m resolution downsampling will occur (40 hours)")
}
level.Info(logger).Log("msg", "retention policy of raw samples is enabled", "duration", retentionByResolution[compact.ResolutionLevelRaw])
}
if retentionByResolution[compact.ResolutionLevel5m].Milliseconds() != 0 {
// If retention is lower than minimum downsample range, then no downsampling at this resolution will be persisted
if !conf.disableDownsampling && retentionByResolution[compact.ResolutionLevel5m].Milliseconds() < downsample.ResLevel2DownsampleRange {
return errors.New("5m resolution retention must be higher than the minimum block size after which 1h resolution downsampling will occur (10 days)")
}
level.Info(logger).Log("msg", "retention policy of 5 min aggregated samples is enabled", "duration", retentionByResolution[compact.ResolutionLevel5m])
}
if retentionByResolution[compact.ResolutionLevel1h].Milliseconds() != 0 {
level.Info(logger).Log("msg", "retention policy of 1 hour aggregated samples is enabled", "duration", retentionByResolution[compact.ResolutionLevel1h])
}
var cleanMtx sync.Mutex
// TODO(GiedriusS): we could also apply retention policies here but the logic would be a bit more complex.
cleanPartialMarked := func() error {
cleanMtx.Lock()
defer cleanMtx.Unlock()
if err := sy.SyncMetas(ctx); err != nil {
cancel()
return errors.Wrap(err, "syncing metas")
}
compact.BestEffortCleanAbortedPartialUploads(ctx, logger, sy.Partial(), bkt, compactMetrics.partialUploadDeleteAttempts, compactMetrics.blocksCleaned, compactMetrics.blockCleanupFailures)
if err := blocksCleaner.DeleteMarkedBlocks(ctx); err != nil {
return errors.Wrap(err, "cleaning marked blocks")
}
compactMetrics.cleanups.Inc()
return nil
}
compactMainFn := func() error {
if err := compactor.Compact(ctx); err != nil {
return errors.Wrap(err, "compaction")
}
if !conf.disableDownsampling {
// After all compactions are done, work down the downsampling backlog.
// We run two passes of this to ensure that the 1h downsampling is generated
// for 5m downsamplings created in the first run.
level.Info(logger).Log("msg", "start first pass of downsampling")
if err := sy.SyncMetas(ctx); err != nil {
return errors.Wrap(err, "sync before first pass of downsampling")
}
for _, meta := range sy.Metas() {
groupKey := meta.Thanos.GroupKey()
downsampleMetrics.downsamples.WithLabelValues(groupKey)
downsampleMetrics.downsampleFailures.WithLabelValues(groupKey)
}
if err := downsampleBucket(ctx, logger, downsampleMetrics, bkt, sy.Metas(), downsamplingDir, conf.downsampleConcurrency, metadata.HashFunc(conf.hashFunc)); err != nil {
return errors.Wrap(err, "first pass of downsampling failed")
}
level.Info(logger).Log("msg", "start second pass of downsampling")
if err := sy.SyncMetas(ctx); err != nil {
return errors.Wrap(err, "sync before second pass of downsampling")
}
if err := downsampleBucket(ctx, logger, downsampleMetrics, bkt, sy.Metas(), downsamplingDir, conf.downsampleConcurrency, metadata.HashFunc(conf.hashFunc)); err != nil {
return errors.Wrap(err, "second pass of downsampling failed")
}
level.Info(logger).Log("msg", "downsampling iterations done")
} else {
level.Info(logger).Log("msg", "downsampling was explicitly disabled")
}
// TODO(bwplotka): Find a way to avoid syncing if no op was done.
if err := sy.SyncMetas(ctx); err != nil {
return errors.Wrap(err, "sync before retention")
}
if err := compact.ApplyRetentionPolicyByResolution(ctx, logger, bkt, sy.Metas(), retentionByResolution, compactMetrics.blocksMarked.WithLabelValues(metadata.DeletionMarkFilename, "")); err != nil {
return errors.Wrap(err, "retention failed")
}
return cleanPartialMarked()
}
// 启动并发任务: 使用 g.Add 启动一个新的并发任务,该任务在 ctx 上下文中运行。
g.Add(func() error {
defer runutil.CloseWithLogOnErr(logger, bkt, "bucket client")
if !conf.wait {
return compactMainFn()
}
// --wait=true is specified.
// runutil.Repeat 是一个无限循环,它会每隔一段时间执行一次给定的函数。如果函数返回一个错误,它会等待一段时间后再次尝试。
return runutil.Repeat(conf.waitInterval, ctx.Done(), func() error {
err := compactMainFn()
if err == nil {
compactMetrics.iterations.Inc()
return nil
}
// The HaltError type signals that we hit a critical bug and should block
// for investigation. You should alert on this being halted.
// compact.IsHaltError 是一个函数,用于检查给定的错误是否表示一个关键的、需要调查的错误。如果返回 true,则表明这是一个关键错误。如果返回 false,则表明这是一个普通的错误。
if compact.IsHaltError(err) {
if conf.haltOnError {
level.Error(logger).Log("msg", "critical error detected; halting", "err", err)
compactMetrics.halted.Set(1)
select {}
} else {
return errors.Wrap(err, "critical error detected")
}
}
// The RetryError signals that we hit an retriable error (transient error, no connection).
// You should alert on this being triggered too frequently.
if compact.IsRetryError(err) {
level.Error(logger).Log("msg", "retriable error", "err", err)
compactMetrics.retried.Inc()
// TODO(bplotka): use actual "retry()" here instead of waiting 5 minutes?
return nil
}
return errors.Wrap(err, "error executing compaction")
})
}, func(error) {
cancel()
})
if conf.wait {
r := route.New()
ins := extpromhttp.NewInstrumentationMiddleware(reg, nil)
global := ui.NewBucketUI(logger, conf.webConf.externalPrefix, conf.webConf.prefixHeaderName, component)
global.Register(r, ins)
// Configure Request Logging for HTTP calls.
opts := []logging.Option{logging.WithDecider(func(_ string, _ error) logging.Decision {
return logging.NoLogCall
})}
logMiddleware := logging.NewHTTPServerMiddleware(logger, opts...)
api.Register(r.WithPrefix("/api/v1"), tracer, logger, ins, logMiddleware)
// Separate fetcher for global view.
// TODO(bwplotka): Allow Bucket UI to visualize the state of the block as well.
f := baseMetaFetcher.NewMetaFetcher(extprom.WrapRegistererWithPrefix("thanos_bucket_ui", reg), nil, "component", "globalBucketUI")
f.UpdateOnChange(func(blocks []metadata.Meta, err error) {
api.SetGlobal(blocks, err)
})
srv.Handle("/", r)
// Periodically remove partial blocks and blocks marked for deletion
// since one iteration potentially could take a long time.
if conf.cleanupBlocksInterval > 0 {
g.Add(func() error {
return runutil.Repeat(conf.cleanupBlocksInterval, ctx.Done(), cleanPartialMarked)
}, func(error) {
cancel()
})
}
// Periodically calculate the progress of compaction, downsampling and retention.
if conf.progressCalculateInterval > 0 {
g.Add(func() error {
ps := compact.NewCompactionProgressCalculator(reg, tsdbPlanner)
rs := compact.NewRetentionProgressCalculator(reg, retentionByResolution)
var ds *compact.DownsampleProgressCalculator
if !conf.disableDownsampling {
ds = compact.NewDownsampleProgressCalculator(reg)
}
return runutil.Repeat(conf.progressCalculateInterval, ctx.Done(), func() error {
if err := sy.SyncMetas(ctx); err != nil {
return errors.Wrapf(err, "could not sync metas")
}
metas := sy.Metas()
groups, err := grouper.Groups(metas)
if err != nil {
return errors.Wrapf(err, "could not group metadata for compaction")
}
if err = ps.ProgressCalculate(ctx, groups); err != nil {
return errors.Wrapf(err, "could not calculate compaction progress")
}
retGroups, err := grouper.Groups(metas)
if err != nil {
return errors.Wrapf(err, "could not group metadata for retention")
}
if err = rs.ProgressCalculate(ctx, retGroups); err != nil {
return errors.Wrapf(err, "could not calculate retention progress")
}
if !conf.disableDownsampling {
groups, err = grouper.Groups(metas)
if err != nil {
return errors.Wrapf(err, "could not group metadata into downsample groups")
}
if err := ds.ProgressCalculate(ctx, groups); err != nil {
return errors.Wrapf(err, "could not calculate downsampling progress")
}
}
return nil
})
}, func(err error) {
cancel()
})
}
/*
g.Add(func() error { ... }, func(error) { ... }):
向一个goroutine管理器g中添加一个任务。这个管理器用于并发地执行任务,并在所有任务完成后进行清理或其他操作。这个任务有两个部分:一个是执行的任务本身(返回error),另一个是错误处理函数。
在第一个部分,我们看到它尝试同步元数据(为了获取最新的块信息),然后根据这些信息进行分组,并计算压缩进度、保留进度和下采样进度。如果在这个过程中出现错误,它会返回这个错误。
*/
g.Add(func() error {
// 这行代码创建了一个新的上下文iterCtx,它有一个超时时间conf.blockViewerSyncBlockTimeout。这个上下文用于控制f.Fetch(iterCtx)操作的超时。iterCancel是一个取消函数,用于在必要时取消这个上下文。
iterCtx, iterCancel := context.WithTimeout(ctx, conf.blockViewerSyncBlockTimeout)
// 调用iterCancel()取消iterCtx,这是因为在单次数据获取完成后,不需要保持这个上下文活跃。
_, _, _ = f.Fetch(iterCtx)
iterCancel()
// For /global state make sure to fetch periodically.
// 使用runutil.Repeat函数定期执行任务。它每隔conf.blockViewerSyncBlockInterval时间执行一次给定的函数,直到ctx.Done()通道被关闭(表示上下文ctx被取消或超时)。
return runutil.Repeat(conf.blockViewerSyncBlockInterval, ctx.Done(), func() error {
// 在runutil.Repeat的回调函数中,使用了runutil.RetryWithLog来尝试执行一个操作,如果失败则重试。这里,它最多等待time.Minute来等待操作成功,如果在ctx.Done()之前成功,则停止重试。
return runutil.RetryWithLog(logger, time.Minute, ctx.Done(), func() error {
// 这行代码再次创建了一个带有超时的上下文,用于f.Fetch(iterCtx)操作的这次尝试。iterCancel是一个取消函数,用于在必要时取消这个上下文。
iterCtx, iterCancel := context.WithTimeout(ctx, conf.blockViewerSyncBlockTimeout)
// 使用defer关键字确保在函数返回前调用iterCancel(),无论是因为成功返回还是因为遇到错误返回。
defer iterCancel()
// 尝试从数据源获取数据,这次错误err被捕获并返回,以便runutil.RetryWithLog可以根据这个错误决定是否重试。
_, _, err := f.Fetch(iterCtx)
return err
})
})
}, func(error) { // 如果主任务函数返回错误,这个错误处理函数会被调用。这里,它调用cancel()函数,可能是用来取消整个操作或通知其他等待这个操作的goroutine。
cancel()
})
}
level.Info(logger).Log("msg", "starting compact node") // 记录日志,表明正在启动压缩节点
statusProber.Ready() // 标记为就绪状态
return nil
}
type compactConfig struct {
haltOnError bool // 关键压缩错误检测时是否停止进程。默认是true。
acceptMalformedIndex bool // 是否接受损坏的索引文件。默认是false。
maxCompactionLevel int // 最大压缩级别。默认是2。
http httpConfig // HTTP配置
dataDir string // 数据目录
objStore extflag.PathOrContent // 对象存储配置
consistencyDelay time.Duration // 延迟一致性检查的时间。默认是0。
retentionRaw, retentionFiveMin, retentionOneHr model.Duration // 原始数据、5分钟数据、1小时数据的保留时间
wait bool // 是否等待压缩完成。默认是false。
waitInterval time.Duration // 等待压缩完成的时间间隔。默认是1分钟。
disableDownsampling bool // 是否禁用下采样。默认是false。
blockSyncConcurrency int // 同步块时的并发数。默认是20。
blockMetaFetchConcurrency int // 获取块元数据时的并发数。默认是20。
blockViewerSyncBlockInterval time.Duration // 同步块的时间间隔。默认是10分钟。
blockViewerSyncBlockTimeout time.Duration // 同步块的超时时间。默认是1分钟。
cleanupBlocksInterval time.Duration // 清理块的时间间隔。默认是1小时。
compactionConcurrency int // 压缩时的并发数。默认是1。
downsampleConcurrency int // 下采样时的并发数。默认是1。
deleteDelay model.Duration // 删除块的时间延迟。默认是1小时。
dedupReplicaLabels []string // 需要删除的副本标签。默认是["replica"]。
selectorRelabelConf extflag.PathOrContent // 选择器重新标签配置。默认是空字符串。
webConf webConfig // web配置。默认是空字符串。
label string // 标签。默认是空字符串。
maxBlockIndexSize units.Base2Bytes // 最大块索引大小。默认是512MB。
hashFunc string // 哈希函数。默认是fnv1a。
enableVerticalCompaction bool // 启用垂直压缩。默认是true。
dedupFunc string // 去重函数。默认是none。
skipBlockWithOutOfOrderChunks bool // 跳过包含乱序块的块。默认是true。
progressCalculateInterval time.Duration // 进度计算间隔。默认是5分钟。
filterConf *store.FilterConfig // 过滤器配置。默认是空字符串。
}
// registerFlag 方法用于注册各种配置标志到命令行参数中。
// 它主要用于配置Thanos Compactor组件的行为。
func (cc *compactConfig) registerFlag(cmd extkingpin.FlagClause) {
// 注册debug.halt-on-error标志
cmd.Flag("debug.halt-on-error", "Halt the process if a critical compaction error is detected.").
Hidden().Default("true").BoolVar(&cc.haltOnError)
// 注册debug.accept-malformed-index标志
cmd.Flag("debug.accept-malformed-index",
"Compaction index verification will ignore out of order label names.").
Hidden().Default("false").BoolVar(&cc.acceptMalformedIndex)
// 注册debug.max-compaction-level标志
cmd.Flag("debug.max-compaction-level", fmt.Sprintf("Maximum compaction level, default is %d: %s", compactions.maxLevel(), compactions.String())).
Hidden().Default(strconv.Itoa(compactions.maxLevel())).IntVar(&cc.maxCompactionLevel)
// 注册HTTP相关标志
cc.http.registerFlag(cmd)
// 注册data-dir标志
cmd.Flag("data-dir", "Data directory in which to cache blocks and process compactions.").
Default("./data").StringVar(&cc.dataDir)
// 注册对象存储标志
cc.objStore = *extkingpin.RegisterCommonObjStoreFlags(cmd, "", false)
// 注册consistency-delay标志
cmd.Flag("consistency-delay", fmt.Sprintf("Minimum age of fresh (non-compacted) blocks before they are being processed. Malformed blocks older than the maximum of consistency-delay and %v will be removed.", compact.PartialUploadThresholdAge)).
Default("30m").DurationVar(&cc.consistencyDelay)
// 注册retention相关标志
cmd.Flag("retention.resolution-raw",
"How long to retain raw samples in bucket. Setting this to 0d will retain samples of this resolution forever").
Default("0d").SetValue(&cc.retentionRaw)
// 注册retention.resolution-5m和retention.resolution-1h标志
cmd.Flag("retention.resolution-5m", "How long to retain samples of resolution 1 (5 minutes) in bucket. Setting this to 0d will retain samples of this resolution forever").
Default("0d").SetValue(&cc.retentionFiveMin)
// 注册retention.resolution-1h标志
cmd.Flag("retention.resolution-1h", "How long to retain samples of resolution 2 (1 hour) in bucket. Setting this to 0d will retain samples of this resolution forever").
Default("0d").SetValue(&cc.retentionOneHr)
// 注册wait标志
// TODO(kakkoyun, pgough): https://github.com/thanos-io/thanos/issues/2266.
cmd.Flag("wait", "Do not exit after all compactions have been processed and wait for new work.").
Short('w').BoolVar(&cc.wait)
// 注册wait-interval标志
cmd.Flag("wait-interval", "Wait interval between consecutive compaction runs and bucket refreshes. Only works when --wait flag specified.").
Default("5m").DurationVar(&cc.waitInterval)
// 注册downsampling相关标志
cmd.Flag("downsampling.disable", "Disables downsampling. This is not recommended "+
"as querying long time ranges without non-downsampled data is not efficient and useful e.g it is not possible to render all samples for a human eye anyway").
Default("false").BoolVar(&cc.disableDownsampling)
// 注册block-sync-concurrency标志
cmd.Flag("block-sync-concurrency", "Number of goroutines to use when syncing block metadata from object storage.").
Default("20").IntVar(&cc.blockSyncConcurrency)
// 注册block-meta-fetch-concurrency标志
cmd.Flag("block-meta-fetch-concurrency", "Number of goroutines to use when fetching block metadata from object storage.").
Default("32").IntVar(&cc.blockMetaFetchConcurrency)
// 注册block-viewer.global.sync-block-interval标志
cmd.Flag("block-viewer.global.sync-block-interval", "Repeat interval for syncing the blocks between local and remote view for /global Block Viewer UI.").
Default("1m").DurationVar(&cc.blockViewerSyncBlockInterval)
// 注册block-viewer.global.sync-block-timeout标志
cmd.Flag("block-viewer.global.sync-block-timeout", "Maximum time for syncing the blocks between local and remote view for /global Block Viewer UI.").
Default("5m").DurationVar(&cc.blockViewerSyncBlockTimeout)
// 注册compact.cleanup-interval标志
cmd.Flag("compact.cleanup-interval", "How often we should clean up partially uploaded blocks and blocks with deletion mark in the background when --wait has been enabled. Setting it to \"0s\" disables it - the cleaning will only happen at the end of an iteration.").
Default("5m").DurationVar(&cc.cleanupBlocksInterval)
// 注册compact.progress-interval标志
cmd.Flag("compact.progress-interval", "Frequency of calculating the compaction progress in the background when --wait has been enabled. Setting it to \"0s\" disables it. Now compaction, downsampling and retention progress are supported.").
Default("5m").DurationVar(&cc.progressCalculateInterval)
// 注册compact.concurrency标志
cmd.Flag("compact.concurrency", "Number of goroutines to use when compacting groups.").
Default("1").IntVar(&cc.compactionConcurrency)
// 注册downsample.concurrency标志
cmd.Flag("downsample.concurrency", "Number of goroutines to use when downsampling blocks.").
Default("1").IntVar(&cc.downsampleConcurrency)
// 注册delete-delay标志
cmd.Flag("delete-delay", "Time before a block marked for deletion is deleted from bucket. "+
"If delete-delay is non zero, blocks will be marked for deletion and compactor component will delete blocks marked for deletion from the bucket. "+
"If delete-delay is 0, blocks will be deleted straight away. "+
"Note that deleting blocks immediately can cause query failures, if store gateway still has the block loaded, "+
"or compactor is ignoring the deletion because it's compacting the block at the same time.").
Default("48h").SetValue(&cc.deleteDelay)
// 注册compact.enable-vertical-compaction标志
cmd.Flag("compact.enable-vertical-compaction", "Experimental. When set to true, compactor will allow overlaps and perform **irreversible** vertical compaction. See https://thanos.io/tip/components/compact.md/#vertical-compactions to read more. "+
"Please note that by default this uses a NAIVE algorithm for merging. If you need a different deduplication algorithm (e.g one that works well with Prometheus replicas), please set it via --deduplication.func."+
"NOTE: This flag is ignored and (enabled) when --deduplication.replica-label flag is set.").
Hidden().Default("false").BoolVar(&cc.enableVerticalCompaction)
// 注册deduplication.func标志
cmd.Flag("deduplication.func", "Experimental. Deduplication algorithm for merging overlapping blocks. "+
"Possible values are: \"\", \"penalty\". If no value is specified, the default compact deduplication merger is used, which performs 1:1 deduplication for samples. "+
"When set to penalty, penalty based deduplication algorithm will be used. At least one replica label has to be set via --deduplication.replica-label flag.").
Default("").EnumVar(&cc.dedupFunc, compact.DedupAlgorithmPenalty, "")
// 注册deduplication.replica-label标志
cmd.Flag("deduplication.replica-label", "Label to treat as a replica indicator of blocks that can be deduplicated (repeated flag). This will merge multiple replica blocks into one. This process is irreversible."+
"Experimental. When one or more labels are set, compactor will ignore the given labels so that vertical compaction can merge the blocks."+
"Please note that by default this uses a NAIVE algorithm for merging which works well for deduplication of blocks with **precisely the same samples** like produced by Receiver replication."+
"If you need a different deduplication algorithm (e.g one that works well with Prometheus replicas), please set it via --deduplication.func.").
StringsVar(&cc.dedupReplicaLabels)
// 注册compact.block-max-index-size标志
// TODO(bwplotka): This is short term fix for https://github.com/thanos-io/thanos/issues/1424, replace with vertical block sharding https://github.com/thanos-io/thanos/pull/3390.
cmd.Flag("compact.block-max-index-size", "Maximum index size for the resulted block during any compaction. Note that"+
"total size is approximated in worst case. If the block that would be resulted from compaction is estimated to exceed this number, biggest source"+
"block is marked for no compaction (no-compact-mark.json is uploaded) which causes this block to be excluded from any compaction. "+
"Default is due to https://github.com/thanos-io/thanos/issues/1424, but it's overall recommended to keeps block size to some reasonable size.").
Hidden().Default("64GB").BytesVar(&cc.maxBlockIndexSize)
// 注册compact.skip-block-with-out-of-order-chunks标志
cmd.Flag("compact.skip-block-with-out-of-order-chunks", "When set to true, mark blocks containing index with out-of-order chunks for no compact instead of halting the compaction").
Hidden().Default("false").BoolVar(&cc.skipBlockWithOutOfOrderChunks)
// 注册hash-func标志
cmd.Flag("hash-func", "Specify which hash function to use when calculating the hashes of produced files. If no function has been specified, it does not happen. This permits avoiding downloading some files twice albeit at some performance cost. Possible values are: \"\", \"SHA256\".").
Default("").EnumVar(&cc.hashFunc, "SHA256", "")
// 初始化filter配置
cc.filterConf = &store.FilterConfig{}
// 注册min-time标志
cmd.Flag("min-time", "Start of time range limit to compact. Thanos Compactor will compact only blocks, which happened later than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y.").
Default("0000-01-01T00:00:00Z").SetValue(&cc.filterConf.MinTime)
// 注册max-time标志
cmd.Flag("max-time", "End of time range limit to compact. Thanos Compactor will compact only blocks, which happened earlier than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y.").
Default("9999-12-31T23:59:59Z").SetValue(&cc.filterConf.MaxTime)
// 注册selector-relabel相关标志
cc.selectorRelabelConf = *extkingpin.RegisterSelectorRelabelFlags(cmd)
// 注册web相关标志
cc.webConf.registerFlag(cmd)
// 注册bucket-web-label标志
cmd.Flag("bucket-web-label", "Prometheus label to use as timeline title in the bucket web UI").StringVar(&cc.label)
}

浙公网安备 33010602011771号