Skip to content

Commit 169a062

Browse files
authored
Add limit for store gateway downloaded bytes (#5179)
* add limit for store gateway downloaded bytes Signed-off-by: Ben Ye <[email protected]> * update docs Signed-off-by: Ben Ye <[email protected]> * update docs Signed-off-by: Ben Ye <[email protected]> * update changelog Signed-off-by: Ben Ye <[email protected]> --------- Signed-off-by: Ben Ye <[email protected]>
1 parent 1b16ce3 commit 169a062

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## master / unreleased
44
* [CHANGE] Alertmanager: Validating new fields on the PagerDuty AM config. #5290
55
* [CHANGE] Ingester: Creating label `native-histogram-sample` on the `cortex_discarded_samples_total` to keep track of discarded native histogram samples. #5289
6+
* [FEATURE] Store Gateway: Add `max_downloaded_bytes_per_request` to limit max bytes to download per store gateway request.
67
* [BUGFIX] Ruler: Validate if rule group can be safely converted back to rule group yaml from protobuf message #5265
78
* [BUGFIX] Querier: Convert gRPC `ResourceExhausted` status code from store gateway to 422 limit error. #5286
89
* [BUGFIX] Alertmanager: Route web-ui requests to the alertmanager distributor when sharding is enabled. #5293

docs/configuration/config-file-reference.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,6 +2950,11 @@ The `limits_config` configures default and per-tenant limits imposed by Cortex s
29502950
# CLI flag: -store-gateway.tenant-shard-size
29512951
[store_gateway_tenant_shard_size: <int> | default = 0]
29522952

2953+
# The maximum number of data bytes to download per gRPC request in Store
2954+
# Gateway, including Series/LabelNames/LabelValues requests. 0 to disable.
2955+
# CLI flag: -store-gateway.max-downloaded-bytes-per-request
2956+
[max_downloaded_bytes_per_request: <int> | default = 0]
2957+
29532958
# Delete blocks containing samples older than the specified retention period. 0
29542959
# to disable.
29552960
# CLI flag: -compactor.blocks-retention-period

pkg/storegateway/bucket_stores.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ func (u *BucketStores) getOrCreateStore(userID string) (*store.BucketStore, erro
492492
u.syncDirForUser(userID),
493493
newChunksLimiterFactory(u.limits, userID),
494494
newSeriesLimiterFactory(u.limits, userID),
495-
store.NewBytesLimiterFactory(0),
495+
newBytesLimiterFactory(u.limits, userID),
496496
u.partitioner,
497497
u.cfg.BucketStore.BlockSyncConcurrency,
498498
false, // No need to enable backward compatibility with Thanos pre 0.8.0 queriers
@@ -637,3 +637,13 @@ func newSeriesLimiterFactory(limits *validation.Overrides, userID string) store.
637637
}
638638
}
639639
}
640+
641+
func newBytesLimiterFactory(limits *validation.Overrides, userID string) store.BytesLimiterFactory {
642+
return func(failedCounter prometheus.Counter) store.BytesLimiter {
643+
// Since limit overrides could be live reloaded, we have to get the current user's limit
644+
// each time a new limiter is instantiated.
645+
return &limiter{
646+
limiter: store.NewLimiter(uint64(limits.MaxDownloadedBytesPerRequest(userID)), failedCounter),
647+
}
648+
}
649+
}

pkg/util/validation/limits.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ type Limits struct {
9595
RulerMaxRuleGroupsPerTenant int `yaml:"ruler_max_rule_groups_per_tenant" json:"ruler_max_rule_groups_per_tenant"`
9696

9797
// Store-gateway.
98-
StoreGatewayTenantShardSize int `yaml:"store_gateway_tenant_shard_size" json:"store_gateway_tenant_shard_size"`
98+
StoreGatewayTenantShardSize int `yaml:"store_gateway_tenant_shard_size" json:"store_gateway_tenant_shard_size"`
99+
MaxDownloadedBytesPerRequest int `yaml:"max_downloaded_bytes_per_request" json:"max_downloaded_bytes_per_request"`
99100

100101
// Compactor.
101102
CompactorBlocksRetentionPeriod model.Duration `yaml:"compactor_blocks_retention_period" json:"compactor_blocks_retention_period"`
@@ -182,6 +183,7 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) {
182183

183184
// Store-gateway.
184185
f.IntVar(&l.StoreGatewayTenantShardSize, "store-gateway.tenant-shard-size", 0, "The default tenant's shard size when the shuffle-sharding strategy is used. Must be set when the store-gateway sharding is enabled with the shuffle-sharding strategy. When this setting is specified in the per-tenant overrides, a value of 0 disables shuffle sharding for the tenant.")
186+
f.IntVar(&l.MaxDownloadedBytesPerRequest, "store-gateway.max-downloaded-bytes-per-request", 0, "The maximum number of data bytes to download per gRPC request in Store Gateway, including Series/LabelNames/LabelValues requests. 0 to disable.")
185187

186188
// Alertmanager.
187189
f.Var(&l.AlertmanagerReceiversBlockCIDRNetworks, "alertmanager.receivers-firewall-block-cidr-networks", "Comma-separated list of network CIDRs to block in Alertmanager receiver integrations.")
@@ -430,6 +432,12 @@ func (o *Overrides) MaxFetchedDataBytesPerQuery(userID string) int {
430432
return o.GetOverridesForUser(userID).MaxFetchedDataBytesPerQuery
431433
}
432434

435+
// MaxDownloadedBytesPerRequest returns the maximum number of bytes to download for each gRPC request in Store Gateway,
436+
// including any data fetched from cache or object storage.
437+
func (o *Overrides) MaxDownloadedBytesPerRequest(userID string) int {
438+
return o.GetOverridesForUser(userID).MaxDownloadedBytesPerRequest
439+
}
440+
433441
// MaxQueryLookback returns the max lookback period of queries.
434442
func (o *Overrides) MaxQueryLookback(userID string) time.Duration {
435443
return time.Duration(o.GetOverridesForUser(userID).MaxQueryLookback)

pkg/util/validation/limits_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,35 @@ tenant2:
564564
require.Equal(t, 3, ov.MaxExemplars("tenant2"))
565565
require.Equal(t, 5, ov.MaxExemplars("tenant3"))
566566
}
567+
568+
func TestMaxDownloadedBytesPerRequestOverridesPerTenant(t *testing.T) {
569+
SetDefaultLimitsForYAMLUnmarshalling(Limits{
570+
MaxLabelNameLength: 100,
571+
})
572+
573+
baseYAML := `
574+
max_downloaded_bytes_per_request: 5`
575+
overridesYAML := `
576+
tenant1:
577+
max_downloaded_bytes_per_request: 1
578+
tenant2:
579+
max_downloaded_bytes_per_request: 3
580+
`
581+
582+
l := Limits{}
583+
err := yaml.UnmarshalStrict([]byte(baseYAML), &l)
584+
require.NoError(t, err)
585+
586+
overrides := map[string]*Limits{}
587+
err = yaml.Unmarshal([]byte(overridesYAML), &overrides)
588+
require.NoError(t, err, "parsing overrides")
589+
590+
tl := newMockTenantLimits(overrides)
591+
592+
ov, err := NewOverrides(l, tl)
593+
require.NoError(t, err)
594+
595+
require.Equal(t, 1, ov.MaxDownloadedBytesPerRequest("tenant1"))
596+
require.Equal(t, 3, ov.MaxDownloadedBytesPerRequest("tenant2"))
597+
require.Equal(t, 5, ov.MaxDownloadedBytesPerRequest("tenant3"))
598+
}

0 commit comments

Comments
 (0)