github.com/grafana/pyroscope@v1.18.0/pkg/validation/limits.go (about) 1 package validation 2 3 import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "iter" 8 "time" 9 10 "gopkg.in/yaml.v3" 11 12 "github.com/pkg/errors" 13 "github.com/prometheus/common/model" 14 15 "github.com/grafana/pyroscope/pkg/distributor/ingestlimits" 16 "github.com/grafana/pyroscope/pkg/distributor/sampling" 17 "github.com/grafana/pyroscope/pkg/distributor/writepath" 18 "github.com/grafana/pyroscope/pkg/frontend/readpath" 19 "github.com/grafana/pyroscope/pkg/metastore/index/cleaner/retention" 20 phlaremodel "github.com/grafana/pyroscope/pkg/model" 21 "github.com/grafana/pyroscope/pkg/phlaredb/block" 22 placement "github.com/grafana/pyroscope/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" 23 ) 24 25 const ( 26 bytesInMB = 1048576 27 28 // MinCompactorPartialBlockDeletionDelay is the minimum partial blocks deletion delay that can be configured in Mimir. 29 // Partial blocks are blocks that are not having meta file uploaded yet. 30 MinCompactorPartialBlockDeletionDelay = 4 * time.Hour 31 ) 32 33 // Limits describe all the limits for tenants; can be used to describe global default 34 // limits via flags, or per-tenant limits via yaml config. 35 // NOTE: we use custom `model.Duration` instead of standard `time.Duration` because, 36 // to support tenant-friendly duration format (e.g: "1h30m45s") in JSON value. 37 type Limits struct { 38 // Distributor enforced limits. 39 IngestionRateMB float64 `yaml:"ingestion_rate_mb" json:"ingestion_rate_mb"` 40 IngestionBurstSizeMB float64 `yaml:"ingestion_burst_size_mb" json:"ingestion_burst_size_mb"` 41 IngestionLimit *ingestlimits.Config `yaml:"ingestion_limit" json:"ingestion_limit" category:"advanced" doc:"hidden"` 42 IngestionBodyLimitMB float64 `yaml:"ingestion_body_limit_mb" json:"ingestion_body_limit_mb" category:"advanced" doc:"hidden"` 43 DistributorSampling *sampling.Config `yaml:"distributor_sampling" json:"distributor_sampling" category:"advanced" doc:"hidden"` 44 MaxLabelNameLength int `yaml:"max_label_name_length" json:"max_label_name_length"` 45 MaxLabelValueLength int `yaml:"max_label_value_length" json:"max_label_value_length"` 46 MaxLabelNamesPerSeries int `yaml:"max_label_names_per_series" json:"max_label_names_per_series"` 47 MaxSessionsPerSeries int `yaml:"max_sessions_per_series" json:"max_sessions_per_series"` 48 EnforceLabelsOrder bool `yaml:"enforce_labels_order" json:"enforce_labels_order"` 49 50 MaxProfileSizeBytes int `yaml:"max_profile_size_bytes" json:"max_profile_size_bytes"` 51 MaxProfileStacktraceSamples int `yaml:"max_profile_stacktrace_samples" json:"max_profile_stacktrace_samples"` 52 MaxProfileStacktraceSampleLabels int `yaml:"max_profile_stacktrace_sample_labels" json:"max_profile_stacktrace_sample_labels"` 53 MaxProfileStacktraceDepth int `yaml:"max_profile_stacktrace_depth" json:"max_profile_stacktrace_depth"` 54 MaxProfileSymbolValueLength int `yaml:"max_profile_symbol_value_length" json:"max_profile_symbol_value_length"` 55 56 // Distributor per-app usage breakdown. 57 DistributorUsageGroups *UsageGroupConfig `yaml:"distributor_usage_groups" json:"distributor_usage_groups"` 58 59 // Distributor aggregation. 60 DistributorAggregationWindow model.Duration `yaml:"distributor_aggregation_window" json:"distributor_aggregation_window"` 61 DistributorAggregationPeriod model.Duration `yaml:"distributor_aggregation_period" json:"distributor_aggregation_period"` 62 63 // IngestionRelabelingRules allow to specify additional relabeling rules that get applied before a profile gets ingested. There are some default relabeling rules, which ensure consistency of profiling series. The position of the default rules can be contolled by IngestionRelabelingDefaultRulesPosition 64 IngestionRelabelingRules IngestionRelabelRules `yaml:"ingestion_relabeling_rules" json:"ingestion_relabeling_rules" category:"advanced"` 65 IngestionRelabelingDefaultRulesPosition RelabelRulesPosition `yaml:"ingestion_relabeling_default_rules_position" json:"ingestion_relabeling_default_rules_position" category:"advanced"` 66 67 SampleTypeRelabelingRules SampleTypeRelabelRules `yaml:"sample_type_relabeling_rules" json:"sample_type_relabeling_rules" category:"advanced"` 68 69 // The tenant shard size determines the how many ingesters a particular 70 // tenant will be sharded to. Needs to be specified on distributors for 71 // correct distribution and on ingesters so that the local ingestion limit 72 // can be calculated correctly. 73 IngestionTenantShardSize int `yaml:"ingestion_tenant_shard_size" json:"ingestion_tenant_shard_size"` 74 75 // IngestionArtificialDelay is the artificial ingestion latency. It make sure the ingestion requests are delayed at the end of the request, to achieve a more uniform latency. 76 IngestionArtificialDelay model.Duration `yaml:"ingestion_artificial_delay" json:"ingestion_artificial_delay" category:"experimental" doc:"hidden"` 77 78 // Ingester enforced limits. 79 MaxLocalSeriesPerTenant int `yaml:"max_local_series_per_tenant" json:"max_local_series_per_tenant"` 80 MaxGlobalSeriesPerTenant int `yaml:"max_global_series_per_tenant" json:"max_global_series_per_tenant"` 81 82 // Querier enforced limits. 83 MaxQueryLookback model.Duration `yaml:"max_query_lookback" json:"max_query_lookback"` 84 MaxQueryLength model.Duration `yaml:"max_query_length" json:"max_query_length"` 85 MaxQueryParallelism int `yaml:"max_query_parallelism" json:"max_query_parallelism"` 86 QueryAnalysisEnabled bool `yaml:"query_analysis_enabled" json:"query_analysis_enabled"` 87 QueryAnalysisSeriesEnabled bool `yaml:"query_analysis_series_enabled" json:"query_analysis_series_enabled"` 88 89 // Flame graph enforced limits. 90 MaxFlameGraphNodesDefault int `yaml:"max_flamegraph_nodes_default" json:"max_flamegraph_nodes_default"` 91 MaxFlameGraphNodesMax int `yaml:"max_flamegraph_nodes_max" json:"max_flamegraph_nodes_max"` 92 MaxFlameGraphNodesOnSelectMergeProfile bool `yaml:"max_flamegraph_nodes_on_select_merge_profile" json:"max_flamegraph_nodes_on_select_merge_profile" category:"advanced" doc:"hidden"` 93 // Store-gateway. 94 StoreGatewayTenantShardSize int `yaml:"store_gateway_tenant_shard_size" json:"store_gateway_tenant_shard_size"` 95 96 // Query frontend. 97 QuerySplitDuration model.Duration `yaml:"split_queries_by_interval" json:"split_queries_by_interval"` 98 QuerySanitizeOnMerge bool `yaml:"query_sanitize_on_merge" json:"query_sanitize_on_merge"` 99 100 // Compactor. 101 CompactorBlocksRetentionPeriod model.Duration `yaml:"compactor_blocks_retention_period" json:"compactor_blocks_retention_period"` 102 CompactorSplitAndMergeShards int `yaml:"compactor_split_and_merge_shards" json:"compactor_split_and_merge_shards"` 103 CompactorSplitAndMergeStageSize int `yaml:"compactor_split_and_merge_stage_size" json:"compactor_split_and_merge_stage_size"` 104 CompactorSplitGroups int `yaml:"compactor_split_groups" json:"compactor_split_groups"` 105 CompactorTenantShardSize int `yaml:"compactor_tenant_shard_size" json:"compactor_tenant_shard_size"` 106 CompactorPartialBlockDeletionDelay model.Duration `yaml:"compactor_partial_block_deletion_delay" json:"compactor_partial_block_deletion_delay"` 107 CompactorDownsamplerEnabled bool `yaml:"compactor_downsampler_enabled" json:"compactor_downsampler_enabled"` 108 109 // This config doesn't have a CLI flag registered here because they're registered in 110 // their own original config struct. 111 S3SSEType string `yaml:"s3_sse_type" json:"s3_sse_type" doc:"nocli|description=S3 server-side encryption type. Required to enable server-side encryption overrides for a specific tenant. If not set, the default S3 client settings are used."` 112 S3SSEKMSKeyID string `yaml:"s3_sse_kms_key_id" json:"s3_sse_kms_key_id" doc:"nocli|description=S3 server-side encryption KMS Key ID. Ignored if the SSE type override is not set."` 113 S3SSEKMSEncryptionContext string `yaml:"s3_sse_kms_encryption_context" json:"s3_sse_kms_encryption_context" doc:"nocli|description=S3 server-side encryption KMS encryption context. If unset and the key ID override is set, the encryption context will not be provided to S3. Ignored if the SSE type override is not set."` 114 115 // Ensure profiles are dated within the IngestionWindow of the distributor. 116 RejectOlderThan model.Duration `yaml:"reject_older_than" json:"reject_older_than"` 117 RejectNewerThan model.Duration `yaml:"reject_newer_than" json:"reject_newer_than"` 118 119 // Write path overrides used in distributor. 120 WritePathOverrides writepath.Config `yaml:",inline" json:",inline"` 121 122 // Write path overrides used in query-frontend. 123 ReadPathOverrides readpath.Config `yaml:",inline" json:",inline"` 124 125 // Data retention configuration. 126 Retention retention.Config `yaml:",inline" json:",inline"` 127 128 // Adaptive placement limits used in distributors and in the metastore. 129 // Distributors use these limits to determine how many shards to allocate 130 // to a tenant dataset by default, if no placement rules defined. 131 AdaptivePlacementLimits placement.PlacementLimits `yaml:",inline" json:",inline"` 132 133 // RecordingRules allow to specify static recording rules. This is not compatible with recording rules 134 // coming from a RecordingRulesClient, that will replace any static rules defined. 135 RecordingRules RecordingRules `yaml:"recording_rules" json:"recording_rules" category:"experimental" doc:"hidden"` 136 137 // Symbolizer. 138 Symbolizer Symbolizer `yaml:"symbolizer" json:"symbolizer" category:"experimental" doc:"hidden"` 139 } 140 141 // LimitError are errors that do not comply with the limits specified. 142 type LimitError string 143 144 func (e LimitError) Error() string { 145 return string(e) 146 } 147 148 // RegisterFlags adds the flags required to config this to the given FlagSet 149 func (l *Limits) RegisterFlags(f *flag.FlagSet) { 150 f.Float64Var(&l.IngestionRateMB, "distributor.ingestion-rate-limit-mb", 4, "Per-tenant ingestion rate limit in sample size per second. Units in MB.") 151 f.Float64Var(&l.IngestionBurstSizeMB, "distributor.ingestion-burst-size-mb", 2, "Per-tenant allowed ingestion burst size (in sample size). Units in MB. The burst size refers to the per-distributor local rate limiter, and should be set at least to the maximum profile size expected in a single push request.") 152 f.Float64Var(&l.IngestionBodyLimitMB, "distributor.ingestion-body-limit-mb", 256, "Per-tenant ingestion body size limit in MB, before decompressing. 0 to disable.") 153 f.IntVar(&l.IngestionTenantShardSize, "distributor.ingestion-tenant-shard-size", 0, "The tenant's shard size used by shuffle-sharding. Must be set both on ingesters and distributors. 0 disables shuffle sharding.") 154 155 f.IntVar(&l.MaxLabelNameLength, "validation.max-length-label-name", 1024, "Maximum length accepted for label names.") 156 f.IntVar(&l.MaxLabelValueLength, "validation.max-length-label-value", 2048, "Maximum length accepted for label value. This setting also applies to the metric name.") 157 f.IntVar(&l.MaxLabelNamesPerSeries, "validation.max-label-names-per-series", 30, "Maximum number of label names per series.") 158 f.IntVar(&l.MaxSessionsPerSeries, "validation.max-sessions-per-series", 0, "Maximum number of sessions per series. 0 to disable.") 159 f.BoolVar(&l.EnforceLabelsOrder, "validation.enforce-labels-order", false, "Enforce labels order optimization.") 160 161 f.IntVar(&l.MaxLocalSeriesPerTenant, "ingester.max-local-series-per-tenant", 0, "Maximum number of active series of profiles per tenant, per ingester. 0 to disable.") 162 f.IntVar(&l.MaxGlobalSeriesPerTenant, "ingester.max-global-series-per-tenant", 5000, "Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change.") 163 164 _ = l.MaxQueryLength.Set("24h") 165 f.Var(&l.MaxQueryLength, "querier.max-query-length", "The limit to length of queries. 0 to disable.") 166 167 _ = l.MaxQueryLookback.Set("7d") 168 f.Var(&l.MaxQueryLookback, "querier.max-query-lookback", "Limit how far back in profiling data can be queried, up until lookback duration ago. This limit is enforced in the query frontend. If the requested time range is outside the allowed range, the request will not fail, but will be modified to only query data within the allowed time range. 0 to disable, default to 7d.") 169 170 f.IntVar(&l.StoreGatewayTenantShardSize, "store-gateway.tenant-shard-size", 0, "The tenant's shard size, used when store-gateway sharding is enabled. Value of 0 disables shuffle sharding for the tenant, that is all tenant blocks are sharded across all store-gateway replicas.") 171 172 _ = l.QuerySplitDuration.Set("0s") 173 f.Var(&l.QuerySplitDuration, "querier.split-queries-by-interval", "Split queries by a time interval and execute in parallel. The value 0 disables splitting by time") 174 f.BoolVar(&l.QuerySanitizeOnMerge, "querier.sanitize-on-merge", true, "Whether profiles should be sanitized when merging.") 175 176 f.IntVar(&l.MaxQueryParallelism, "querier.max-query-parallelism", 0, "Maximum number of queries that will be scheduled in parallel by the frontend.") 177 178 f.BoolVar(&l.QueryAnalysisEnabled, "querier.query-analysis-enabled", true, "Whether query analysis is enabled in the query frontend. If disabled, the /AnalyzeQuery endpoint will return an empty response.") 179 f.BoolVar(&l.QueryAnalysisSeriesEnabled, "querier.query-analysis-series-enabled", false, "Whether the series portion of query analysis is enabled. If disabled, no series data (e.g., series count) will be calculated by the /AnalyzeQuery endpoint.") 180 181 f.IntVar(&l.MaxProfileSizeBytes, "validation.max-profile-size-bytes", 4*1024*1024, "Maximum size of a profile in bytes. This is based off the uncompressed size. 0 to disable.") 182 f.IntVar(&l.MaxProfileStacktraceSamples, "validation.max-profile-stacktrace-samples", 16000, "Maximum number of samples in a profile. 0 to disable.") 183 f.IntVar(&l.MaxProfileStacktraceSampleLabels, "validation.max-profile-stacktrace-sample-labels", 100, "Maximum number of labels in a profile sample. 0 to disable.") 184 f.IntVar(&l.MaxProfileStacktraceDepth, "validation.max-profile-stacktrace-depth", 1000, "Maximum depth of a profile stacktrace. Profiles are not rejected instead stacktraces are truncated. 0 to disable.") 185 f.IntVar(&l.MaxProfileSymbolValueLength, "validation.max-profile-symbol-value-length", 65535, "Maximum length of a profile symbol value (labels, function names and filenames, etc...). Profiles are not rejected instead symbol values are truncated. 0 to disable.") 186 187 f.IntVar(&l.MaxFlameGraphNodesDefault, "querier.max-flamegraph-nodes-default", 8<<10, "Maximum number of flame graph nodes by default. 0 to disable.") 188 f.IntVar(&l.MaxFlameGraphNodesMax, "querier.max-flamegraph-nodes-max", 1<<20, "Maximum number of flame graph nodes allowed. 0 to disable.") 189 f.BoolVar(&l.MaxFlameGraphNodesOnSelectMergeProfile, "querier.max-flamegraph-nodes-on-select-merge-profile", false, "Enforce the max nodes limits and defaults on SelectMergeProfile API. Historically this limit was not enforced to enable to gather full pprof profiles without truncation.") 190 191 f.Var(&l.DistributorAggregationWindow, "distributor.aggregation-window", "Duration of the distributor aggregation window. Requires aggregation period to be specified. 0 to disable.") 192 f.Var(&l.DistributorAggregationPeriod, "distributor.aggregation-period", "Duration of the distributor aggregation period. Requires aggregation window to be specified. 0 to disable.") 193 194 f.Var(&l.CompactorBlocksRetentionPeriod, "compactor.blocks-retention-period", "Delete blocks containing samples older than the specified retention period. 0 to disable.") 195 f.IntVar(&l.CompactorSplitAndMergeShards, "compactor.split-and-merge-shards", 0, "The number of shards to use when splitting blocks. 0 to disable splitting.") 196 f.IntVar(&l.CompactorSplitAndMergeStageSize, "compactor.split-and-merge-stage-size", 0, "Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards.") 197 f.IntVar(&l.CompactorSplitGroups, "compactor.split-groups", 1, "Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards.") 198 f.IntVar(&l.CompactorTenantShardSize, "compactor.compactor-tenant-shard-size", 0, "Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors.") 199 _ = l.CompactorPartialBlockDeletionDelay.Set("1d") 200 f.Var(&l.CompactorPartialBlockDeletionDelay, "compactor.partial-block-deletion-delay", fmt.Sprintf("If a partial block (unfinished block without %s file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is %s: a lower value will be ignored and the feature disabled. 0 to disable.", block.MetaFilename, MinCompactorPartialBlockDeletionDelay.String())) 201 f.BoolVar(&l.CompactorDownsamplerEnabled, "compactor.compactor-downsampler-enabled", true, "If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. Note: This set the default for the teanant overrides, in order to be effective it also requires compactor.downsampler-enabled to be set to true.") 202 203 _ = l.RejectNewerThan.Set("10m") 204 f.Var(&l.RejectNewerThan, "validation.reject-newer-than", "This limits how far into the future profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 10m.") 205 206 _ = l.RejectOlderThan.Set("1h") 207 f.Var(&l.RejectOlderThan, "validation.reject-older-than", "This limits how far into the past profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 1h.") 208 209 _ = l.IngestionRelabelingDefaultRulesPosition.Set("first") 210 f.Var(&l.IngestionRelabelingDefaultRulesPosition, "distributor.ingestion-relabeling-default-rules-position", "Position of the default ingestion relabeling rules in relation to relabel rules from overrides. Valid values are 'first', 'last' or 'disabled'.") 211 _ = l.IngestionRelabelingRules.Set("[]") 212 f.Var(&l.IngestionRelabelingRules, "distributor.ingestion-relabeling-rules", "List of ingestion relabel configurations. The relabeling rules work the same way, as those of [Prometheus](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config). All rules are applied in the order they are specified. Note: In most situations, it is more effective to use relabeling directly in Grafana Alloy.") 213 214 _ = l.SampleTypeRelabelingRules.Set("[]") 215 f.Var(&l.SampleTypeRelabelingRules, "distributor.sample-type-relabeling-rules", "List of sample type relabel configurations. Rules are applied to sample types with __type__ and __unit__ labels, along with all series labels.") 216 217 f.Var(&l.IngestionArtificialDelay, "distributor.ingestion-artificial-delay", "Target ingestion delay to apply to all tenants. If set to a non-zero value, the distributor will artificially delay ingestion time-frame by the specified duration by computing the difference between actual ingestion and the target. There is no delay on actual ingestion of samples, it is only the response back to the client.") 218 219 } 220 221 // UnmarshalYAML implements the yaml.Unmarshaler interface. 222 func (l *Limits) UnmarshalYAML(unmarshal func(interface{}) error) error { 223 // We want to set c to the defaults and then overwrite it with the input. 224 // To make unmarshal fill the plain data struct rather than calling UnmarshalYAML 225 // again, we have to hide it using a type indirection. See prometheus/config. 226 type plain Limits 227 228 // During startup we wont have a default value so we don't want to overwrite them 229 if defaultLimits != nil { 230 b, err := yaml.Marshal(defaultLimits) 231 if err != nil { 232 return errors.Wrap(err, "cloning limits (marshaling)") 233 } 234 if err := yaml.Unmarshal(b, (*plain)(l)); err != nil { 235 return errors.Wrap(err, "cloning limits (unmarshaling)") 236 } 237 } 238 return unmarshal((*plain)(l)) 239 } 240 241 // Validate validates that this limits config is valid. 242 func (l *Limits) Validate() error { 243 if l.IngestionRelabelingDefaultRulesPosition != "" { 244 if err := l.IngestionRelabelingDefaultRulesPosition.Set(string(l.IngestionRelabelingDefaultRulesPosition)); err != nil { 245 return err 246 } 247 } 248 249 for idx, rule := range l.RecordingRules { 250 _, err := phlaremodel.NewRecordingRule(rule) 251 if err != nil { 252 return fmt.Errorf("rule at pos %d is not valid: %v", idx, err) 253 } 254 } 255 256 return nil 257 } 258 259 // When we load YAML from disk, we want the various per-customer limits 260 // to default to any values specified on the command line, not default 261 // command line values. This global contains those values. I (Tom) cannot 262 // find a nicer way I'm afraid. 263 var defaultLimits *Limits 264 265 // SetDefaultLimitsForYAMLUnmarshalling sets global default limits, used when loading 266 // Limits from YAML files. This is used to ensure per-tenant limits are defaulted to 267 // those values. 268 func SetDefaultLimitsForYAMLUnmarshalling(defaults Limits) { 269 defaultLimits = &defaults 270 } 271 272 type TenantLimits interface { 273 // TenantLimits is a function that returns limits for given tenant, or 274 // nil, if there are no tenant-specific limits. 275 TenantLimits(tenantID string) *Limits 276 // AllByTenantID gets a mapping of all tenant IDs and limits for that tenant 277 AllByTenantID() map[string]*Limits 278 // RuntimeConfig returns the runtime config values, if available, and nil otherwise. 279 RuntimeConfig() *RuntimeConfigValues 280 } 281 282 // Overrides periodically fetch a set of per-tenant overrides, and provides convenience 283 // functions for fetching the correct value. 284 type Overrides struct { 285 defaultLimits *Limits 286 tenantLimits TenantLimits 287 } 288 289 // NewOverrides makes a new Overrides. 290 func NewOverrides(defaults Limits, tenantLimits TenantLimits) (*Overrides, error) { 291 return &Overrides{ 292 tenantLimits: tenantLimits, 293 defaultLimits: &defaults, 294 }, nil 295 } 296 297 func (o *Overrides) AllByTenantID() map[string]*Limits { 298 if o.tenantLimits != nil { 299 return o.tenantLimits.AllByTenantID() 300 } 301 return nil 302 } 303 304 // IngestionRateBytes returns the limit on ingester rate (MBs per second). 305 func (o *Overrides) IngestionRateBytes(tenantID string) float64 { 306 return o.getOverridesForTenant(tenantID).IngestionRateMB * bytesInMB 307 } 308 309 // IngestionBurstSizeBytes returns the burst size for ingestion rate. 310 func (o *Overrides) IngestionBurstSizeBytes(tenantID string) int { 311 return int(o.getOverridesForTenant(tenantID).IngestionBurstSizeMB * bytesInMB) 312 } 313 314 func (o *Overrides) IngestionBodyLimitBytes(tenantID string) int64 { 315 return int64(o.getOverridesForTenant(tenantID).IngestionBodyLimitMB * bytesInMB) 316 } 317 318 func (o *Overrides) IngestionLimit(tenantID string) *ingestlimits.Config { 319 return o.getOverridesForTenant(tenantID).IngestionLimit 320 } 321 322 func (o *Overrides) DistributorSampling(tenantID string) *sampling.Config { 323 return o.getOverridesForTenant(tenantID).DistributorSampling 324 } 325 326 // IngestionArtificialDelay returns the artificial ingestion latency for a given user. 327 func (o *Overrides) IngestionArtificialDelay(tenantID string) time.Duration { 328 return time.Duration(o.getOverridesForTenant(tenantID).IngestionArtificialDelay) 329 } 330 331 // IngestionTenantShardSize returns the ingesters shard size for a given user. 332 func (o *Overrides) IngestionTenantShardSize(tenantID string) int { 333 return o.getOverridesForTenant(tenantID).IngestionTenantShardSize 334 } 335 336 // MaxLabelNameLength returns maximum length a label name can be. 337 func (o *Overrides) MaxLabelNameLength(tenantID string) int { 338 return o.getOverridesForTenant(tenantID).MaxLabelNameLength 339 } 340 341 // MaxLabelValueLength returns maximum length a label value can be. This also is 342 // the maximum length of a metric name. 343 func (o *Overrides) MaxLabelValueLength(tenantID string) int { 344 return o.getOverridesForTenant(tenantID).MaxLabelValueLength 345 } 346 347 // MaxLabelNamesPerSeries returns maximum number of label/value pairs timeseries. 348 func (o *Overrides) MaxLabelNamesPerSeries(tenantID string) int { 349 return o.getOverridesForTenant(tenantID).MaxLabelNamesPerSeries 350 } 351 352 // MaxProfileSizeBytes returns the maximum size of a profile in bytes. 353 func (o *Overrides) MaxProfileSizeBytes(tenantID string) int { 354 return o.getOverridesForTenant(tenantID).MaxProfileSizeBytes 355 } 356 357 // MaxProfileStacktraceSamples returns the maximum number of samples in a profile. 358 func (o *Overrides) MaxProfileStacktraceSamples(tenantID string) int { 359 return o.getOverridesForTenant(tenantID).MaxProfileStacktraceSamples 360 } 361 362 // MaxProfileStacktraceSampleLabels returns the maximum number of labels in a profile sample. 363 func (o *Overrides) MaxProfileStacktraceSampleLabels(tenantID string) int { 364 return o.getOverridesForTenant(tenantID).MaxProfileStacktraceSampleLabels 365 } 366 367 // MaxProfileStacktraceDepth returns the maximum depth of a profile stacktrace. 368 func (o *Overrides) MaxProfileStacktraceDepth(tenantID string) int { 369 return o.getOverridesForTenant(tenantID).MaxProfileStacktraceDepth 370 } 371 372 // MaxProfileSymbolValueLength returns the maximum length of a profile symbol value (labels, function name and filename, etc...). 373 func (o *Overrides) MaxProfileSymbolValueLength(tenantID string) int { 374 return o.getOverridesForTenant(tenantID).MaxProfileSymbolValueLength 375 } 376 377 // MaxSessionsPerSeries returns the maximum number of sessions per single series. 378 func (o *Overrides) MaxSessionsPerSeries(tenantID string) int { 379 return o.getOverridesForTenant(tenantID).MaxSessionsPerSeries 380 } 381 382 func (o *Overrides) EnforceLabelsOrder(tenantID string) bool { 383 return o.getOverridesForTenant(tenantID).EnforceLabelsOrder 384 } 385 386 func (o *Overrides) DistributorAggregationWindow(tenantID string) model.Duration { 387 return o.getOverridesForTenant(tenantID).DistributorAggregationWindow 388 } 389 390 func (o *Overrides) DistributorAggregationPeriod(tenantID string) model.Duration { 391 return o.getOverridesForTenant(tenantID).DistributorAggregationPeriod 392 } 393 394 // MaxLocalSeriesPerTenant returns the maximum number of series a tenant is allowed to store 395 // in a single ingester. 396 func (o *Overrides) MaxLocalSeriesPerTenant(tenantID string) int { 397 return o.getOverridesForTenant(tenantID).MaxLocalSeriesPerTenant 398 } 399 400 // MaxGlobalSeriesPerTenant returns the maximum number of series a tenant is allowed to store 401 // across the cluster. 402 func (o *Overrides) MaxGlobalSeriesPerTenant(tenantID string) int { 403 return o.getOverridesForTenant(tenantID).MaxGlobalSeriesPerTenant 404 } 405 406 // MaxQueryLength returns the limit of the length (in time) of a query. 407 func (o *Overrides) MaxQueryLength(tenantID string) time.Duration { 408 return time.Duration(o.getOverridesForTenant(tenantID).MaxQueryLength) 409 } 410 411 // MaxQueryParallelism returns the limit to the number of sub-queries the 412 // frontend will process in parallel. 413 func (o *Overrides) MaxQueryParallelism(tenantID string) int { 414 return o.getOverridesForTenant(tenantID).MaxQueryParallelism 415 } 416 417 // MaxQueryLookback returns the max lookback period of queries. 418 func (o *Overrides) MaxQueryLookback(tenantID string) time.Duration { 419 return time.Duration(o.getOverridesForTenant(tenantID).MaxQueryLookback) 420 } 421 422 // MaxFlameGraphNodesDefault returns the max flame graph nodes used by default. 423 func (o *Overrides) MaxFlameGraphNodesDefault(tenantID string) int { 424 return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesDefault 425 } 426 427 // MaxFlameGraphNodesMax returns the max flame graph nodes allowed. 428 func (o *Overrides) MaxFlameGraphNodesMax(tenantID string) int { 429 return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesMax 430 } 431 432 // MaxFlameGraphNodesOnSelectMergeProfiles returns if the max flame graph nodes should be enforced for the SelectMergeProfile API. 433 func (o *Overrides) MaxFlameGraphNodesOnSelectMergeProfile(tenantID string) bool { 434 return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesOnSelectMergeProfile 435 } 436 437 // StoreGatewayTenantShardSize returns the store-gateway shard size for a given user. 438 func (o *Overrides) StoreGatewayTenantShardSize(userID string) int { 439 return o.getOverridesForTenant(userID).StoreGatewayTenantShardSize 440 } 441 442 // QuerySplitDuration returns the tenant specific split by interval applied in the query frontend. 443 func (o *Overrides) QuerySplitDuration(tenantID string) time.Duration { 444 return time.Duration(o.getOverridesForTenant(tenantID).QuerySplitDuration) 445 } 446 447 // QuerySanitizeOnMerge returns whether profiles should be sanitized in the read path. 448 func (o *Overrides) QuerySanitizeOnMerge(tenantID string) bool { 449 return o.getOverridesForTenant(tenantID).QuerySanitizeOnMerge 450 } 451 452 // CompactorTenantShardSize returns number of compactors that this user can use. 0 = all compactors. 453 func (o *Overrides) CompactorTenantShardSize(userID string) int { 454 return o.getOverridesForTenant(userID).CompactorTenantShardSize 455 } 456 457 // CompactorBlocksRetentionPeriod returns the retention period for a given user. 458 func (o *Overrides) CompactorBlocksRetentionPeriod(userID string) time.Duration { 459 return time.Duration(o.getOverridesForTenant(userID).CompactorBlocksRetentionPeriod) 460 } 461 462 // CompactorSplitAndMergeShards returns the number of shards to use when splitting blocks. 463 func (o *Overrides) CompactorSplitAndMergeShards(userID string) int { 464 return o.getOverridesForTenant(userID).CompactorSplitAndMergeShards 465 } 466 467 // CompactorSplitAndMergeStageSize returns the number of stages split shards will be written to. 468 func (o *Overrides) CompactorSplitAndMergeStageSize(userID string) int { 469 return o.getOverridesForTenant(userID).CompactorSplitAndMergeStageSize 470 } 471 472 // CompactorSplitGroups returns the number of groups that blocks for splitting should be grouped into. 473 func (o *Overrides) CompactorSplitGroups(userID string) int { 474 return o.getOverridesForTenant(userID).CompactorSplitGroups 475 } 476 477 // CompactorPartialBlockDeletionDelay returns the partial block deletion delay time period for a given user, 478 // and whether the configured value was valid. If the value wasn't valid, the returned delay is the default one 479 // and the caller is responsible to warn the Mimir operator about it. 480 func (o *Overrides) CompactorPartialBlockDeletionDelay(userID string) (delay time.Duration, valid bool) { 481 delay = time.Duration(o.getOverridesForTenant(userID).CompactorPartialBlockDeletionDelay) 482 483 // Forcefully disable partial blocks deletion if the configured delay is too low. 484 if delay > 0 && delay < MinCompactorPartialBlockDeletionDelay { 485 return 0, false 486 } 487 488 return delay, true 489 } 490 491 // CompactorDownsamplerEnabled returns true if the downsampler is enabled for a given user. 492 func (o *Overrides) CompactorDownsamplerEnabled(userId string) bool { 493 return o.getOverridesForTenant(userId).CompactorDownsamplerEnabled 494 } 495 496 // S3SSEType returns the per-tenant S3 SSE type. 497 func (o *Overrides) S3SSEType(user string) string { 498 return o.getOverridesForTenant(user).S3SSEType 499 } 500 501 // S3SSEKMSKeyID returns the per-tenant S3 KMS-SSE key id. 502 func (o *Overrides) S3SSEKMSKeyID(user string) string { 503 return o.getOverridesForTenant(user).S3SSEKMSKeyID 504 } 505 506 // S3SSEKMSEncryptionContext returns the per-tenant S3 KMS-SSE encryption context. 507 func (o *Overrides) S3SSEKMSEncryptionContext(user string) string { 508 return o.getOverridesForTenant(user).S3SSEKMSEncryptionContext 509 } 510 511 // MaxQueriersPerTenant returns the limit to the number of queriers that can be used 512 // Shuffle sharding will be used to distribute queries across queriers. 513 // 0 means no limit. Currently disabled. 514 func (o *Overrides) MaxQueriersPerTenant(tenant string) int { return 0 } 515 516 // RejectNewerThan will ensure that profiles are further than the return value into the future are reject. 517 func (o *Overrides) RejectNewerThan(tenantID string) time.Duration { 518 return time.Duration(o.getOverridesForTenant(tenantID).RejectNewerThan) 519 } 520 521 // RejectOlderThan will ensure that profiles that are older than the return value are rejected. 522 func (o *Overrides) RejectOlderThan(tenantID string) time.Duration { 523 return time.Duration(o.getOverridesForTenant(tenantID).RejectOlderThan) 524 } 525 526 // QueryAnalysisEnabled can be used to disable the query analysis endpoint in the query frontend. 527 func (o *Overrides) QueryAnalysisEnabled(tenantID string) bool { 528 return o.getOverridesForTenant(tenantID).QueryAnalysisEnabled 529 } 530 531 func (o *Overrides) Retention() (defaults retention.Config, overrides iter.Seq2[string, retention.Config]) { 532 return GetOverride(o, func(tenantID string, limits *Limits) retention.Config { 533 return limits.Retention 534 }) 535 } 536 537 // GetOverride is a convenience function to get an override value for all tenants. 538 // The order is not deterministic. 539 func GetOverride[T any](o *Overrides, fn func(string, *Limits) T) (defaults T, overrides iter.Seq2[string, T]) { 540 defaults = fn("", o.defaultLimits) 541 if o.tenantLimits == nil { 542 return defaults, func(yield func(string, T) bool) {} 543 } 544 c := o.tenantLimits.RuntimeConfig() 545 if c == nil { 546 return defaults, func(yield func(string, T) bool) {} 547 } 548 return defaults, func(yield func(string, T) bool) { 549 for tenantID, limits := range c.TenantLimits { 550 if !yield(tenantID, fn(tenantID, limits)) { 551 return 552 } 553 } 554 } 555 } 556 557 // QueryAnalysisSeriesEnabled can be used to disable the series portion of the query analysis endpoint in the query frontend. 558 // To be used for tenants where calculating series can be expensive. 559 func (o *Overrides) QueryAnalysisSeriesEnabled(tenantID string) bool { 560 return o.getOverridesForTenant(tenantID).QueryAnalysisSeriesEnabled 561 } 562 563 func (o *Overrides) WritePathOverrides(tenantID string) writepath.Config { 564 return o.getOverridesForTenant(tenantID).WritePathOverrides 565 } 566 567 func (o *Overrides) ReadPathOverrides(tenantID string) readpath.Config { 568 return o.getOverridesForTenant(tenantID).ReadPathOverrides 569 } 570 571 func (o *Overrides) PlacementLimits(tenantID string) placement.PlacementLimits { 572 // Both limits aimed at the same thing: limit the number of shards tenant's 573 // data is distributed to. The IngestionTenantShardSize specifies the number 574 // of ingester instances (taking into account the replication factor), while 575 // the PlacementLimits.TenantShards specifies the number of shards and it's 576 // not set by default. Each segment writer own very small number of shards 577 // (4, by default) so we can use the same value for both. 578 t := o.getOverridesForTenant(tenantID) 579 l := t.AdaptivePlacementLimits 580 if t.IngestionTenantShardSize > 0 && uint64(t.IngestionTenantShardSize) > l.TenantShards { 581 l.TenantShards = uint64(t.IngestionTenantShardSize) 582 } 583 return l 584 } 585 586 func (o *Overrides) DefaultLimits() *Limits { 587 return o.defaultLimits 588 } 589 590 func (o *Overrides) getOverridesForTenant(tenantID string) *Limits { 591 if o.tenantLimits != nil { 592 l := o.tenantLimits.TenantLimits(tenantID) 593 if l != nil { 594 return l 595 } 596 } 597 return o.defaultLimits 598 } 599 600 // OverwriteMarshalingStringMap will overwrite the src map when unmarshaling 601 // as opposed to merging. 602 type OverwriteMarshalingStringMap struct { 603 m map[string]string 604 } 605 606 func NewOverwriteMarshalingStringMap(m map[string]string) OverwriteMarshalingStringMap { 607 return OverwriteMarshalingStringMap{m: m} 608 } 609 610 func (sm *OverwriteMarshalingStringMap) Map() map[string]string { 611 return sm.m 612 } 613 614 // MarshalJSON explicitly uses the type receiver and not pointer receiver 615 // or it won't be called 616 func (sm OverwriteMarshalingStringMap) MarshalJSON() ([]byte, error) { 617 return json.Marshal(sm.m) 618 } 619 620 func (sm *OverwriteMarshalingStringMap) UnmarshalJSON(val []byte) error { 621 var def map[string]string 622 if err := json.Unmarshal(val, &def); err != nil { 623 return err 624 } 625 sm.m = def 626 627 return nil 628 } 629 630 // MarshalYAML explicitly uses the type receiver and not pointer receiver 631 // or it won't be called 632 func (sm OverwriteMarshalingStringMap) MarshalYAML() (interface{}, error) { 633 return sm.m, nil 634 } 635 636 func (sm *OverwriteMarshalingStringMap) UnmarshalYAML(unmarshal func(interface{}) error) error { 637 var def map[string]string 638 639 err := unmarshal(&def) 640 if err != nil { 641 return err 642 } 643 sm.m = def 644 645 return nil 646 }