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 }