Skip to content

Commit d6f922d

Browse files
authored
Configurable block listing strategy (#5828)
* make block listing strategy configurable. Change default strategy from Recursive to Concurrent Signed-off-by: Ben Ye <benye@amazon.com> * update docs Signed-off-by: Ben Ye <benye@amazon.com> --------- Signed-off-by: Ben Ye <benye@amazon.com>
1 parent b5e84e4 commit d6f922d

File tree

13 files changed

+127
-36
lines changed

13 files changed

+127
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* [CHANGE] Ruler: Remove `cortex_ruler_write_requests_total`, `cortex_ruler_write_requests_failed_total`, `cortex_ruler_queries_total`, `cortex_ruler_queries_failed_total`, and `cortex_ruler_query_seconds_total` metrics for the tenant when the ruler deletes the manager for the tenant. #5772
1010
* [CHANGE] Main: Mark `mem-ballast-size-bytes` flag as deprecated. #5816
1111
* [CHANGE] Querier: Mark `-querier.ingester-streaming` flag as deprecated. Now query ingester streaming is always enabled. #5817
12-
* [CHANGE] AlertManager API: Removal of all api/v1/ endpoints following [2970](https://github.com/prometheus/alertmanager/pull/2970). [5841]
12+
* [CHANGE] Compactor/Bucket Store: Added `-blocks-storage.bucket-store.block-discovery-strategy` to configure different block listing strategy. Reverted the current recursive block listing mechanism and use the strategy `Concurrent` as in 1.15. #5828
1313
* [FEATURE] Ingester: Add per-tenant new metric `cortex_ingester_tsdb_data_replay_duration_seconds`. #5477
1414
* [FEATURE] Query Frontend/Scheduler: Add query priority support. #5605
1515
* [FEATURE] Tracing: Add `kuberesolver` to resolve endpoints address with `kubernetes://` prefix as Kubernetes service. #5731

docs/blocks-storage/querier.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,17 @@ blocks_storage:
13141314
# CLI flag: -blocks-storage.bucket-store.bucket-index.max-stale-period
13151315
[max_stale_period: <duration> | default = 1h]
13161316

1317+
# One of concurrent, recursive, bucket_index. When set to concurrent, stores
1318+
# will concurrently issue one call per directory to discover active blocks
1319+
# in the bucket. The recursive strategy iterates through all objects in the
1320+
# bucket, recursively traversing into each directory. This avoids N+1 calls
1321+
# at the expense of having slower bucket iterations. bucket_index strategy
1322+
# can be used in Compactor only and utilizes the existing bucket index to
1323+
# fetch block IDs to sync. This avoids iterating the bucket but can be
1324+
# impacted by delays of cleaner creating bucket index.
1325+
# CLI flag: -blocks-storage.bucket-store.block-discovery-strategy
1326+
[block_discovery_strategy: <string> | default = "concurrent"]
1327+
13171328
# Max size - in bytes - of a chunks pool, used to reduce memory allocations.
13181329
# The pool is shared across all tenants. 0 to disable the limit.
13191330
# CLI flag: -blocks-storage.bucket-store.max-chunk-pool-bytes

docs/blocks-storage/store-gateway.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,17 @@ blocks_storage:
14231423
# CLI flag: -blocks-storage.bucket-store.bucket-index.max-stale-period
14241424
[max_stale_period: <duration> | default = 1h]
14251425

1426+
# One of concurrent, recursive, bucket_index. When set to concurrent, stores
1427+
# will concurrently issue one call per directory to discover active blocks
1428+
# in the bucket. The recursive strategy iterates through all objects in the
1429+
# bucket, recursively traversing into each directory. This avoids N+1 calls
1430+
# at the expense of having slower bucket iterations. bucket_index strategy
1431+
# can be used in Compactor only and utilizes the existing bucket index to
1432+
# fetch block IDs to sync. This avoids iterating the bucket but can be
1433+
# impacted by delays of cleaner creating bucket index.
1434+
# CLI flag: -blocks-storage.bucket-store.block-discovery-strategy
1435+
[block_discovery_strategy: <string> | default = "concurrent"]
1436+
14261437
# Max size - in bytes - of a chunks pool, used to reduce memory allocations.
14271438
# The pool is shared across all tenants. 0 to disable the limit.
14281439
# CLI flag: -blocks-storage.bucket-store.max-chunk-pool-bytes

docs/configuration/config-file-reference.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,17 @@ bucket_store:
18501850
# CLI flag: -blocks-storage.bucket-store.bucket-index.max-stale-period
18511851
[max_stale_period: <duration> | default = 1h]
18521852

1853+
# One of concurrent, recursive, bucket_index. When set to concurrent, stores
1854+
# will concurrently issue one call per directory to discover active blocks in
1855+
# the bucket. The recursive strategy iterates through all objects in the
1856+
# bucket, recursively traversing into each directory. This avoids N+1 calls at
1857+
# the expense of having slower bucket iterations. bucket_index strategy can be
1858+
# used in Compactor only and utilizes the existing bucket index to fetch block
1859+
# IDs to sync. This avoids iterating the bucket but can be impacted by delays
1860+
# of cleaner creating bucket index.
1861+
# CLI flag: -blocks-storage.bucket-store.block-discovery-strategy
1862+
[block_discovery_strategy: <string> | default = "concurrent"]
1863+
18531864
# Max size - in bytes - of a chunks pool, used to reduce memory allocations.
18541865
# The pool is shared across all tenants. 0 to disable the limit.
18551866
# CLI flag: -blocks-storage.bucket-store.max-chunk-pool-bytes

pkg/compactor/compactor.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -827,22 +827,26 @@ func (c *Compactor) compactUser(ctx context.Context, userID string) error {
827827
// out of order chunks or index file too big.
828828
noCompactMarkerFilter := compact.NewGatherNoCompactionMarkFilter(ulogger, bucket, c.compactorCfg.MetaSyncConcurrency)
829829

830-
var blockIDsFetcher block.Lister
831-
var fetcherULogger log.Logger
832-
if c.storageCfg.BucketStore.BucketIndex.Enabled {
833-
fetcherULogger = log.With(ulogger, "blockIdsFetcher", "BucketIndexBlockIDsFetcher")
834-
blockIDsFetcher = bucketindex.NewBlockIDsFetcher(fetcherULogger, c.bucketClient, userID, c.limits)
835-
836-
} else {
837-
fetcherULogger = log.With(ulogger, "blockIdsFetcher", "BaseBlockIDsFetcher")
838-
blockIDsFetcher = block.NewRecursiveLister(fetcherULogger, bucket)
830+
var blockLister block.Lister
831+
switch cortex_tsdb.BlockDiscoveryStrategy(c.storageCfg.BucketStore.BlockDiscoveryStrategy) {
832+
case cortex_tsdb.ConcurrentDiscovery:
833+
blockLister = block.NewConcurrentLister(ulogger, bucket)
834+
case cortex_tsdb.RecursiveDiscovery:
835+
blockLister = block.NewRecursiveLister(ulogger, bucket)
836+
case cortex_tsdb.BucketIndexDiscovery:
837+
if !c.storageCfg.BucketStore.BucketIndex.Enabled {
838+
return cortex_tsdb.ErrInvalidBucketIndexBlockDiscoveryStrategy
839+
}
840+
blockLister = bucketindex.NewBlockLister(ulogger, c.bucketClient, userID, c.limits)
841+
default:
842+
return cortex_tsdb.ErrBlockDiscoveryStrategy
839843
}
840844

841845
fetcher, err := block.NewMetaFetcher(
842-
fetcherULogger,
846+
ulogger,
843847
c.compactorCfg.MetaSyncConcurrency,
844848
bucket,
845-
blockIDsFetcher,
849+
blockLister,
846850
c.metaSyncDirForUser(userID),
847851
reg,
848852
// List of filters to apply (order matters).

pkg/compactor/compactor_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,7 @@ func prepareConfig() Config {
16731673
func prepare(t *testing.T, compactorCfg Config, bucketClient objstore.InstrumentedBucket, limits *validation.Limits) (*Compactor, *tsdbCompactorMock, *tsdbPlannerMock, *concurrency.SyncBuffer, prometheus.Gatherer) {
16741674
storageCfg := cortex_tsdb.BlocksStorageConfig{}
16751675
flagext.DefaultValues(&storageCfg)
1676+
storageCfg.BucketStore.BlockDiscoveryStrategy = string(cortex_tsdb.RecursiveDiscovery)
16761677

16771678
// Create a temporary directory for compactor data.
16781679
compactorCfg.DataDir = t.TempDir()

pkg/querier/blocks_finder_bucket_scan.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ type BucketScanBlocksFinderConfig struct {
4343
ConsistencyDelay time.Duration
4444
IgnoreDeletionMarksDelay time.Duration
4545
IgnoreBlocksWithin time.Duration
46+
47+
BlockDiscoveryStrategy string
4648
}
4749

4850
// BucketScanBlocksFinder is a BlocksFinder implementation periodically scanning the bucket to discover blocks.
@@ -384,12 +386,25 @@ func (d *BucketScanBlocksFinder) createMetaFetcher(userID string) (block.Metadat
384386
filters = append(filters, storegateway.NewIgnoreNonQueryableBlocksFilter(d.logger, d.cfg.IgnoreBlocksWithin))
385387
}
386388

387-
blockIdsFetcher := block.NewRecursiveLister(userLogger, userBucket)
389+
var (
390+
err error
391+
blockLister block.Lister
392+
)
393+
switch cortex_tsdb.BlockDiscoveryStrategy(d.cfg.BlockDiscoveryStrategy) {
394+
case cortex_tsdb.ConcurrentDiscovery:
395+
blockLister = block.NewConcurrentLister(userLogger, userBucket)
396+
case cortex_tsdb.RecursiveDiscovery:
397+
blockLister = block.NewRecursiveLister(userLogger, userBucket)
398+
case cortex_tsdb.BucketIndexDiscovery:
399+
return nil, nil, nil, cortex_tsdb.ErrInvalidBucketIndexBlockDiscoveryStrategy
400+
default:
401+
return nil, nil, nil, cortex_tsdb.ErrBlockDiscoveryStrategy
402+
}
388403
f, err := block.NewMetaFetcher(
389404
userLogger,
390405
d.cfg.MetasConcurrency,
391406
userBucket,
392-
blockIdsFetcher,
407+
blockLister,
393408
// The fetcher stores cached metas in the "meta-syncer/" sub directory.
394409
filepath.Join(d.cfg.CacheDir, userID),
395410
userReg,

pkg/querier/blocks_finder_bucket_scan_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,5 +521,6 @@ func prepareBucketScanBlocksFinderConfig() BucketScanBlocksFinderConfig {
521521
MetasConcurrency: 10,
522522
IgnoreDeletionMarksDelay: time.Hour,
523523
IgnoreBlocksWithin: 10 * time.Hour, // All blocks created in the last 10 hour shouldn't be scanned.
524+
BlockDiscoveryStrategy: string(cortex_tsdb.RecursiveDiscovery),
524525
}
525526
}

pkg/querier/blocks_store_queryable.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ func NewBlocksStoreQueryableFromConfig(querierCfg Config, gatewayCfg storegatewa
219219
CacheDir: storageCfg.BucketStore.SyncDir,
220220
IgnoreDeletionMarksDelay: storageCfg.BucketStore.IgnoreDeletionMarksDelay,
221221
IgnoreBlocksWithin: storageCfg.BucketStore.IgnoreBlocksWithin,
222+
BlockDiscoveryStrategy: storageCfg.BucketStore.BlockDiscoveryStrategy,
222223
}, bucketClient, limits, logger, reg)
223224
}
224225

pkg/storage/tsdb/bucketindex/block_ids_fetcher.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,40 @@ import (
1313
"github.com/cortexproject/cortex/pkg/storage/bucket"
1414
)
1515

16-
type BlockIDsFetcher struct {
17-
logger log.Logger
18-
bkt objstore.Bucket
19-
userID string
20-
cfgProvider bucket.TenantConfigProvider
21-
baseBlockIDsFetcher block.Lister
16+
type BlockLister struct {
17+
logger log.Logger
18+
bkt objstore.Bucket
19+
userID string
20+
cfgProvider bucket.TenantConfigProvider
21+
baseLister block.Lister
2222
}
2323

24-
func NewBlockIDsFetcher(logger log.Logger, bkt objstore.Bucket, userID string, cfgProvider bucket.TenantConfigProvider) *BlockIDsFetcher {
24+
func NewBlockLister(logger log.Logger, bkt objstore.Bucket, userID string, cfgProvider bucket.TenantConfigProvider) *BlockLister {
2525
userBkt := bucket.NewUserBucketClient(userID, bkt, cfgProvider)
26-
baseBlockIDsFetcher := block.NewRecursiveLister(logger, userBkt)
27-
return &BlockIDsFetcher{
28-
logger: logger,
29-
bkt: bkt,
30-
userID: userID,
31-
cfgProvider: cfgProvider,
32-
baseBlockIDsFetcher: baseBlockIDsFetcher,
26+
baseLister := block.NewConcurrentLister(logger, userBkt)
27+
return &BlockLister{
28+
logger: logger,
29+
bkt: bkt,
30+
userID: userID,
31+
cfgProvider: cfgProvider,
32+
baseLister: baseLister,
3333
}
3434
}
3535

36-
func (f *BlockIDsFetcher) GetActiveAndPartialBlockIDs(ctx context.Context, ch chan<- ulid.ULID) (partialBlocks map[ulid.ULID]bool, err error) {
36+
func (f *BlockLister) GetActiveAndPartialBlockIDs(ctx context.Context, ch chan<- ulid.ULID) (partialBlocks map[ulid.ULID]bool, err error) {
3737
// Fetch the bucket index.
3838
idx, err := ReadIndex(ctx, f.bkt, f.userID, f.cfgProvider, f.logger)
3939
if errors.Is(err, ErrIndexNotFound) {
4040
// This is a legit case happening when the first blocks of a tenant have recently been uploaded by ingesters
4141
// and their bucket index has not been created yet.
4242
// Fallback to BaseBlockIDsFetcher.
43-
return f.baseBlockIDsFetcher.GetActiveAndPartialBlockIDs(ctx, ch)
43+
return f.baseLister.GetActiveAndPartialBlockIDs(ctx, ch)
4444
}
4545
if errors.Is(err, ErrIndexCorrupted) {
4646
// In case a single tenant bucket index is corrupted, we want to return empty active blocks and parital blocks, so skipping this compaction cycle
4747
level.Error(f.logger).Log("msg", "corrupted bucket index found", "user", f.userID, "err", err)
4848
// Fallback to BaseBlockIDsFetcher.
49-
return f.baseBlockIDsFetcher.GetActiveAndPartialBlockIDs(ctx, ch)
49+
return f.baseLister.GetActiveAndPartialBlockIDs(ctx, ch)
5050
}
5151

5252
if errors.Is(err, bucket.ErrCustomerManagedKeyAccessDenied) {

0 commit comments

Comments
 (0)