github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/storage/tsdb/config.go (about)

     1  package tsdb
     2  
     3  import (
     4  	"flag"
     5  	"path/filepath"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/alecthomas/units"
    10  	"github.com/pkg/errors"
    11  	"github.com/prometheus/prometheus/tsdb/chunks"
    12  	"github.com/prometheus/prometheus/tsdb/wal"
    13  	"github.com/thanos-io/thanos/pkg/store"
    14  
    15  	"github.com/cortexproject/cortex/pkg/storage/bucket"
    16  )
    17  
    18  const (
    19  	// TenantIDExternalLabel is the external label containing the tenant ID,
    20  	// set when shipping blocks to the storage.
    21  	TenantIDExternalLabel = "__org_id__"
    22  
    23  	// IngesterIDExternalLabel is the external label containing the ingester ID,
    24  	// set when shipping blocks to the storage.
    25  	IngesterIDExternalLabel = "__ingester_id__"
    26  
    27  	// ShardIDExternalLabel is the external label containing the shard ID
    28  	// and can be used to shard blocks.
    29  	ShardIDExternalLabel = "__shard_id__"
    30  
    31  	// How often are open TSDBs checked for being idle and closed.
    32  	DefaultCloseIdleTSDBInterval = 5 * time.Minute
    33  
    34  	// How often to check for tenant deletion mark.
    35  	DeletionMarkCheckInterval = 1 * time.Hour
    36  
    37  	// Default minimum bucket size (bytes) of the chunk pool.
    38  	ChunkPoolDefaultMinBucketSize = store.EstimatedMaxChunkSize
    39  
    40  	// Default maximum bucket size (bytes) of the chunk pool.
    41  	ChunkPoolDefaultMaxBucketSize = 50e6
    42  )
    43  
    44  // Validation errors
    45  var (
    46  	errInvalidShipConcurrency       = errors.New("invalid TSDB ship concurrency")
    47  	errInvalidOpeningConcurrency    = errors.New("invalid TSDB opening concurrency")
    48  	errInvalidCompactionInterval    = errors.New("invalid TSDB compaction interval")
    49  	errInvalidCompactionConcurrency = errors.New("invalid TSDB compaction concurrency")
    50  	errInvalidWALSegmentSizeBytes   = errors.New("invalid TSDB WAL segment size bytes")
    51  	errInvalidStripeSize            = errors.New("invalid TSDB stripe size")
    52  	errEmptyBlockranges             = errors.New("empty block ranges for TSDB")
    53  )
    54  
    55  // BlocksStorageConfig holds the config information for the blocks storage.
    56  //nolint:golint
    57  type BlocksStorageConfig struct {
    58  	Bucket      bucket.Config     `yaml:",inline"`
    59  	BucketStore BucketStoreConfig `yaml:"bucket_store" doc:"description=This configures how the querier and store-gateway discover and synchronize blocks stored in the bucket."`
    60  	TSDB        TSDBConfig        `yaml:"tsdb"`
    61  }
    62  
    63  // DurationList is the block ranges for a tsdb
    64  type DurationList []time.Duration
    65  
    66  // String implements the flag.Value interface
    67  func (d *DurationList) String() string {
    68  	values := make([]string, 0, len(*d))
    69  	for _, v := range *d {
    70  		values = append(values, v.String())
    71  	}
    72  
    73  	return strings.Join(values, ",")
    74  }
    75  
    76  // Set implements the flag.Value interface
    77  func (d *DurationList) Set(s string) error {
    78  	values := strings.Split(s, ",")
    79  	*d = make([]time.Duration, 0, len(values)) // flag.Parse may be called twice, so overwrite instead of append
    80  	for _, v := range values {
    81  		t, err := time.ParseDuration(v)
    82  		if err != nil {
    83  			return err
    84  		}
    85  		*d = append(*d, t)
    86  	}
    87  	return nil
    88  }
    89  
    90  // ToMilliseconds returns the duration list in milliseconds
    91  func (d *DurationList) ToMilliseconds() []int64 {
    92  	values := make([]int64, 0, len(*d))
    93  	for _, t := range *d {
    94  		values = append(values, t.Milliseconds())
    95  	}
    96  
    97  	return values
    98  }
    99  
   100  // RegisterFlags registers the TSDB flags
   101  func (cfg *BlocksStorageConfig) RegisterFlags(f *flag.FlagSet) {
   102  	cfg.Bucket.RegisterFlagsWithPrefix("blocks-storage.", f)
   103  	cfg.BucketStore.RegisterFlags(f)
   104  	cfg.TSDB.RegisterFlags(f)
   105  }
   106  
   107  // Validate the config.
   108  func (cfg *BlocksStorageConfig) Validate() error {
   109  	if err := cfg.Bucket.Validate(); err != nil {
   110  		return err
   111  	}
   112  
   113  	if err := cfg.TSDB.Validate(); err != nil {
   114  		return err
   115  	}
   116  
   117  	return cfg.BucketStore.Validate()
   118  }
   119  
   120  // TSDBConfig holds the config for TSDB opened in the ingesters.
   121  //nolint:golint
   122  type TSDBConfig struct {
   123  	Dir                       string        `yaml:"dir"`
   124  	BlockRanges               DurationList  `yaml:"block_ranges_period"`
   125  	Retention                 time.Duration `yaml:"retention_period"`
   126  	ShipInterval              time.Duration `yaml:"ship_interval"`
   127  	ShipConcurrency           int           `yaml:"ship_concurrency"`
   128  	HeadCompactionInterval    time.Duration `yaml:"head_compaction_interval"`
   129  	HeadCompactionConcurrency int           `yaml:"head_compaction_concurrency"`
   130  	HeadCompactionIdleTimeout time.Duration `yaml:"head_compaction_idle_timeout"`
   131  	HeadChunksWriteBufferSize int           `yaml:"head_chunks_write_buffer_size_bytes"`
   132  	StripeSize                int           `yaml:"stripe_size"`
   133  	WALCompressionEnabled     bool          `yaml:"wal_compression_enabled"`
   134  	WALSegmentSizeBytes       int           `yaml:"wal_segment_size_bytes"`
   135  	FlushBlocksOnShutdown     bool          `yaml:"flush_blocks_on_shutdown"`
   136  	CloseIdleTSDBTimeout      time.Duration `yaml:"close_idle_tsdb_timeout"`
   137  
   138  	// MaxTSDBOpeningConcurrencyOnStartup limits the number of concurrently opening TSDB's during startup.
   139  	MaxTSDBOpeningConcurrencyOnStartup int `yaml:"max_tsdb_opening_concurrency_on_startup"`
   140  
   141  	// If true, user TSDBs are not closed on shutdown. Only for testing.
   142  	// If false (default), user TSDBs are closed to make sure all resources are released and closed properly.
   143  	KeepUserTSDBOpenOnShutdown bool `yaml:"-"`
   144  
   145  	// How often to check for idle TSDBs for closing. DefaultCloseIdleTSDBInterval is not suitable for testing, so tests can override.
   146  	CloseIdleTSDBInterval time.Duration `yaml:"-"`
   147  
   148  	// Positive value enables experiemental support for exemplars. 0 or less to disable.
   149  	MaxExemplars int `yaml:"max_exemplars"`
   150  }
   151  
   152  // RegisterFlags registers the TSDBConfig flags.
   153  func (cfg *TSDBConfig) RegisterFlags(f *flag.FlagSet) {
   154  	if len(cfg.BlockRanges) == 0 {
   155  		cfg.BlockRanges = []time.Duration{2 * time.Hour} // Default 2h block
   156  	}
   157  
   158  	f.StringVar(&cfg.Dir, "blocks-storage.tsdb.dir", "tsdb", "Local directory to store TSDBs in the ingesters.")
   159  	f.Var(&cfg.BlockRanges, "blocks-storage.tsdb.block-ranges-period", "TSDB blocks range period.")
   160  	f.DurationVar(&cfg.Retention, "blocks-storage.tsdb.retention-period", 6*time.Hour, "TSDB blocks retention in the ingester before a block is removed. This should be larger than the block_ranges_period and large enough to give store-gateways and queriers enough time to discover newly uploaded blocks.")
   161  	f.DurationVar(&cfg.ShipInterval, "blocks-storage.tsdb.ship-interval", 1*time.Minute, "How frequently the TSDB blocks are scanned and new ones are shipped to the storage. 0 means shipping is disabled.")
   162  	f.IntVar(&cfg.ShipConcurrency, "blocks-storage.tsdb.ship-concurrency", 10, "Maximum number of tenants concurrently shipping blocks to the storage.")
   163  	f.IntVar(&cfg.MaxTSDBOpeningConcurrencyOnStartup, "blocks-storage.tsdb.max-tsdb-opening-concurrency-on-startup", 10, "limit the number of concurrently opening TSDB's on startup")
   164  	f.DurationVar(&cfg.HeadCompactionInterval, "blocks-storage.tsdb.head-compaction-interval", 1*time.Minute, "How frequently does Cortex try to compact TSDB head. Block is only created if data covers smallest block range. Must be greater than 0 and max 5 minutes.")
   165  	f.IntVar(&cfg.HeadCompactionConcurrency, "blocks-storage.tsdb.head-compaction-concurrency", 5, "Maximum number of tenants concurrently compacting TSDB head into a new block")
   166  	f.DurationVar(&cfg.HeadCompactionIdleTimeout, "blocks-storage.tsdb.head-compaction-idle-timeout", 1*time.Hour, "If TSDB head is idle for this duration, it is compacted. Note that up to 25% jitter is added to the value to avoid ingesters compacting concurrently. 0 means disabled.")
   167  	f.IntVar(&cfg.HeadChunksWriteBufferSize, "blocks-storage.tsdb.head-chunks-write-buffer-size-bytes", chunks.DefaultWriteBufferSize, "The write buffer size used by the head chunks mapper. Lower values reduce memory utilisation on clusters with a large number of tenants at the cost of increased disk I/O operations.")
   168  	f.IntVar(&cfg.StripeSize, "blocks-storage.tsdb.stripe-size", 16384, "The number of shards of series to use in TSDB (must be a power of 2). Reducing this will decrease memory footprint, but can negatively impact performance.")
   169  	f.BoolVar(&cfg.WALCompressionEnabled, "blocks-storage.tsdb.wal-compression-enabled", false, "True to enable TSDB WAL compression.")
   170  	f.IntVar(&cfg.WALSegmentSizeBytes, "blocks-storage.tsdb.wal-segment-size-bytes", wal.DefaultSegmentSize, "TSDB WAL segments files max size (bytes).")
   171  	f.BoolVar(&cfg.FlushBlocksOnShutdown, "blocks-storage.tsdb.flush-blocks-on-shutdown", false, "True to flush blocks to storage on shutdown. If false, incomplete blocks will be reused after restart.")
   172  	f.DurationVar(&cfg.CloseIdleTSDBTimeout, "blocks-storage.tsdb.close-idle-tsdb-timeout", 0, "If TSDB has not received any data for this duration, and all blocks from TSDB have been shipped, TSDB is closed and deleted from local disk. If set to positive value, this value should be equal or higher than -querier.query-ingesters-within flag to make sure that TSDB is not closed prematurely, which could cause partial query results. 0 or negative value disables closing of idle TSDB.")
   173  	f.IntVar(&cfg.MaxExemplars, "blocks-storage.tsdb.max-exemplars", 0, "Enables support for exemplars in TSDB and sets the maximum number that will be stored. 0 or less means disabled.")
   174  }
   175  
   176  // Validate the config.
   177  func (cfg *TSDBConfig) Validate() error {
   178  	if cfg.ShipInterval > 0 && cfg.ShipConcurrency <= 0 {
   179  		return errInvalidShipConcurrency
   180  	}
   181  
   182  	if cfg.MaxTSDBOpeningConcurrencyOnStartup <= 0 {
   183  		return errInvalidOpeningConcurrency
   184  	}
   185  
   186  	if cfg.HeadCompactionInterval <= 0 || cfg.HeadCompactionInterval > 5*time.Minute {
   187  		return errInvalidCompactionInterval
   188  	}
   189  
   190  	if cfg.HeadCompactionConcurrency <= 0 {
   191  		return errInvalidCompactionConcurrency
   192  	}
   193  
   194  	if cfg.HeadChunksWriteBufferSize < chunks.MinWriteBufferSize || cfg.HeadChunksWriteBufferSize > chunks.MaxWriteBufferSize || cfg.HeadChunksWriteBufferSize%1024 != 0 {
   195  		return errors.Errorf("head chunks write buffer size must be a multiple of 1024 between %d and %d", chunks.MinWriteBufferSize, chunks.MaxWriteBufferSize)
   196  	}
   197  
   198  	if cfg.StripeSize <= 1 || (cfg.StripeSize&(cfg.StripeSize-1)) != 0 { // ensure stripe size is a positive power of 2
   199  		return errInvalidStripeSize
   200  	}
   201  
   202  	if len(cfg.BlockRanges) == 0 {
   203  		return errEmptyBlockranges
   204  	}
   205  
   206  	if cfg.WALSegmentSizeBytes <= 0 {
   207  		return errInvalidWALSegmentSizeBytes
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // BlocksDir returns the directory path where TSDB blocks and wal should be
   214  // stored by the ingester
   215  func (cfg *TSDBConfig) BlocksDir(userID string) string {
   216  	return filepath.Join(cfg.Dir, userID)
   217  }
   218  
   219  // IsShippingEnabled returns whether blocks shipping is enabled.
   220  func (cfg *TSDBConfig) IsBlocksShippingEnabled() bool {
   221  	return cfg.ShipInterval > 0
   222  }
   223  
   224  // BucketStoreConfig holds the config information for Bucket Stores used by the querier and store-gateway.
   225  type BucketStoreConfig struct {
   226  	SyncDir                  string              `yaml:"sync_dir"`
   227  	SyncInterval             time.Duration       `yaml:"sync_interval"`
   228  	MaxConcurrent            int                 `yaml:"max_concurrent"`
   229  	TenantSyncConcurrency    int                 `yaml:"tenant_sync_concurrency"`
   230  	BlockSyncConcurrency     int                 `yaml:"block_sync_concurrency"`
   231  	MetaSyncConcurrency      int                 `yaml:"meta_sync_concurrency"`
   232  	ConsistencyDelay         time.Duration       `yaml:"consistency_delay"`
   233  	IndexCache               IndexCacheConfig    `yaml:"index_cache"`
   234  	ChunksCache              ChunksCacheConfig   `yaml:"chunks_cache"`
   235  	MetadataCache            MetadataCacheConfig `yaml:"metadata_cache"`
   236  	IgnoreDeletionMarksDelay time.Duration       `yaml:"ignore_deletion_mark_delay"`
   237  	BucketIndex              BucketIndexConfig   `yaml:"bucket_index"`
   238  
   239  	// Chunk pool.
   240  	MaxChunkPoolBytes           uint64 `yaml:"max_chunk_pool_bytes"`
   241  	ChunkPoolMinBucketSizeBytes int    `yaml:"chunk_pool_min_bucket_size_bytes" doc:"hidden"`
   242  	ChunkPoolMaxBucketSizeBytes int    `yaml:"chunk_pool_max_bucket_size_bytes" doc:"hidden"`
   243  
   244  	// Controls whether index-header lazy loading is enabled.
   245  	IndexHeaderLazyLoadingEnabled     bool          `yaml:"index_header_lazy_loading_enabled"`
   246  	IndexHeaderLazyLoadingIdleTimeout time.Duration `yaml:"index_header_lazy_loading_idle_timeout"`
   247  
   248  	// Controls the partitioner, used to aggregate multiple GET object API requests.
   249  	// The config option is hidden until experimental.
   250  	PartitionerMaxGapBytes uint64 `yaml:"partitioner_max_gap_bytes" doc:"hidden"`
   251  
   252  	// Controls what is the ratio of postings offsets store will hold in memory.
   253  	// Larger value will keep less offsets, which will increase CPU cycles needed for query touching those postings.
   254  	// It's meant for setups that want low baseline memory pressure and where less traffic is expected.
   255  	// On the contrary, smaller value will increase baseline memory usage, but improve latency slightly.
   256  	// 1 will keep all in memory. Default value is the same as in Prometheus which gives a good balance.
   257  	PostingOffsetsInMemSampling int `yaml:"postings_offsets_in_mem_sampling" doc:"hidden"`
   258  }
   259  
   260  // RegisterFlags registers the BucketStore flags
   261  func (cfg *BucketStoreConfig) RegisterFlags(f *flag.FlagSet) {
   262  	cfg.IndexCache.RegisterFlagsWithPrefix(f, "blocks-storage.bucket-store.index-cache.")
   263  	cfg.ChunksCache.RegisterFlagsWithPrefix(f, "blocks-storage.bucket-store.chunks-cache.")
   264  	cfg.MetadataCache.RegisterFlagsWithPrefix(f, "blocks-storage.bucket-store.metadata-cache.")
   265  	cfg.BucketIndex.RegisterFlagsWithPrefix(f, "blocks-storage.bucket-store.bucket-index.")
   266  
   267  	f.StringVar(&cfg.SyncDir, "blocks-storage.bucket-store.sync-dir", "tsdb-sync", "Directory to store synchronized TSDB index headers.")
   268  	f.DurationVar(&cfg.SyncInterval, "blocks-storage.bucket-store.sync-interval", 15*time.Minute, "How frequently to scan the bucket, or to refresh the bucket index (if enabled), in order to look for changes (new blocks shipped by ingesters and blocks deleted by retention or compaction).")
   269  	f.Uint64Var(&cfg.MaxChunkPoolBytes, "blocks-storage.bucket-store.max-chunk-pool-bytes", uint64(2*units.Gibibyte), "Max size - in bytes - of a chunks pool, used to reduce memory allocations. The pool is shared across all tenants. 0 to disable the limit.")
   270  	f.IntVar(&cfg.ChunkPoolMinBucketSizeBytes, "blocks-storage.bucket-store.chunk-pool-min-bucket-size-bytes", ChunkPoolDefaultMinBucketSize, "Size - in bytes - of the smallest chunks pool bucket.")
   271  	f.IntVar(&cfg.ChunkPoolMaxBucketSizeBytes, "blocks-storage.bucket-store.chunk-pool-max-bucket-size-bytes", ChunkPoolDefaultMaxBucketSize, "Size - in bytes - of the largest chunks pool bucket.")
   272  	f.IntVar(&cfg.MaxConcurrent, "blocks-storage.bucket-store.max-concurrent", 100, "Max number of concurrent queries to execute against the long-term storage. The limit is shared across all tenants.")
   273  	f.IntVar(&cfg.TenantSyncConcurrency, "blocks-storage.bucket-store.tenant-sync-concurrency", 10, "Maximum number of concurrent tenants synching blocks.")
   274  	f.IntVar(&cfg.BlockSyncConcurrency, "blocks-storage.bucket-store.block-sync-concurrency", 20, "Maximum number of concurrent blocks synching per tenant.")
   275  	f.IntVar(&cfg.MetaSyncConcurrency, "blocks-storage.bucket-store.meta-sync-concurrency", 20, "Number of Go routines to use when syncing block meta files from object storage per tenant.")
   276  	f.DurationVar(&cfg.ConsistencyDelay, "blocks-storage.bucket-store.consistency-delay", 0, "Minimum age of a block before it's being read. Set it to safe value (e.g 30m) if your object storage is eventually consistent. GCS and S3 are (roughly) strongly consistent.")
   277  	f.DurationVar(&cfg.IgnoreDeletionMarksDelay, "blocks-storage.bucket-store.ignore-deletion-marks-delay", time.Hour*6, "Duration after which the blocks marked for deletion will be filtered out while fetching blocks. "+
   278  		"The idea of ignore-deletion-marks-delay is to ignore blocks that are marked for deletion with some delay. This ensures store can still serve blocks that are meant to be deleted but do not have a replacement yet. "+
   279  		"Default is 6h, half of the default value for -compactor.deletion-delay.")
   280  	f.IntVar(&cfg.PostingOffsetsInMemSampling, "blocks-storage.bucket-store.posting-offsets-in-mem-sampling", store.DefaultPostingOffsetInMemorySampling, "Controls what is the ratio of postings offsets that the store will hold in memory.")
   281  	f.BoolVar(&cfg.IndexHeaderLazyLoadingEnabled, "blocks-storage.bucket-store.index-header-lazy-loading-enabled", false, "If enabled, store-gateway will lazy load an index-header only once required by a query.")
   282  	f.DurationVar(&cfg.IndexHeaderLazyLoadingIdleTimeout, "blocks-storage.bucket-store.index-header-lazy-loading-idle-timeout", 20*time.Minute, "If index-header lazy loading is enabled and this setting is > 0, the store-gateway will offload unused index-headers after 'idle timeout' inactivity.")
   283  	f.Uint64Var(&cfg.PartitionerMaxGapBytes, "blocks-storage.bucket-store.partitioner-max-gap-bytes", store.PartitionerMaxGapSize, "Max size - in bytes - of a gap for which the partitioner aggregates together two bucket GET object requests.")
   284  }
   285  
   286  // Validate the config.
   287  func (cfg *BucketStoreConfig) Validate() error {
   288  	err := cfg.IndexCache.Validate()
   289  	if err != nil {
   290  		return errors.Wrap(err, "index-cache configuration")
   291  	}
   292  	err = cfg.ChunksCache.Validate()
   293  	if err != nil {
   294  		return errors.Wrap(err, "chunks-cache configuration")
   295  	}
   296  	err = cfg.MetadataCache.Validate()
   297  	if err != nil {
   298  		return errors.Wrap(err, "metadata-cache configuration")
   299  	}
   300  	return nil
   301  }
   302  
   303  type BucketIndexConfig struct {
   304  	Enabled               bool          `yaml:"enabled"`
   305  	UpdateOnErrorInterval time.Duration `yaml:"update_on_error_interval"`
   306  	IdleTimeout           time.Duration `yaml:"idle_timeout"`
   307  	MaxStalePeriod        time.Duration `yaml:"max_stale_period"`
   308  }
   309  
   310  func (cfg *BucketIndexConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) {
   311  	f.BoolVar(&cfg.Enabled, prefix+"enabled", false, "True to enable querier and store-gateway to discover blocks in the storage via bucket index instead of bucket scanning.")
   312  	f.DurationVar(&cfg.UpdateOnErrorInterval, prefix+"update-on-error-interval", time.Minute, "How frequently a bucket index, which previously failed to load, should be tried to load again. This option is used only by querier.")
   313  	f.DurationVar(&cfg.IdleTimeout, prefix+"idle-timeout", time.Hour, "How long a unused bucket index should be cached. Once this timeout expires, the unused bucket index is removed from the in-memory cache. This option is used only by querier.")
   314  	f.DurationVar(&cfg.MaxStalePeriod, prefix+"max-stale-period", time.Hour, "The maximum allowed age of a bucket index (last updated) before queries start failing because the bucket index is too old. The bucket index is periodically updated by the compactor, while this check is enforced in the querier (at query time).")
   315  }