mirror of https://github.com/grafana/loki
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
15 KiB
305 lines
15 KiB
![]()
6 years ago
|
package validation
|
||
|
|
||
|
import (
|
||
|
"flag"
|
||
|
"time"
|
||
![]()
5 years ago
|
|
||
|
"github.com/grafana/loki/pkg/util/flagext"
|
||
![]()
6 years ago
|
)
|
||
|
|
||
![]()
5 years ago
|
const (
|
||
|
// Local ingestion rate strategy
|
||
|
LocalIngestionRateStrategy = "local"
|
||
|
|
||
|
// Global ingestion rate strategy
|
||
|
GlobalIngestionRateStrategy = "global"
|
||
|
|
||
|
bytesInMB = 1048576
|
||
|
)
|
||
|
|
||
![]()
6 years ago
|
// Limits describe all the limits for users; can be used to describe global default
|
||
|
// limits via flags, or per-user limits via yaml config.
|
||
|
type Limits struct {
|
||
|
// Distributor enforced limits.
|
||
![]()
5 years ago
|
IngestionRateStrategy string `yaml:"ingestion_rate_strategy"`
|
||
|
IngestionRateMB float64 `yaml:"ingestion_rate_mb"`
|
||
|
IngestionBurstSizeMB float64 `yaml:"ingestion_burst_size_mb"`
|
||
|
MaxLabelNameLength int `yaml:"max_label_name_length"`
|
||
|
MaxLabelValueLength int `yaml:"max_label_value_length"`
|
||
|
MaxLabelNamesPerSeries int `yaml:"max_label_names_per_series"`
|
||
|
RejectOldSamples bool `yaml:"reject_old_samples"`
|
||
|
RejectOldSamplesMaxAge time.Duration `yaml:"reject_old_samples_max_age"`
|
||
|
CreationGracePeriod time.Duration `yaml:"creation_grace_period"`
|
||
|
EnforceMetricName bool `yaml:"enforce_metric_name"`
|
||
|
MaxLineSize flagext.ByteSize `yaml:"max_line_size"`
|
||
![]()
6 years ago
|
|
||
|
// Ingester enforced limits.
|
||
![]()
5 years ago
|
MaxLocalStreamsPerUser int `yaml:"max_streams_per_user"`
|
||
|
MaxGlobalStreamsPerUser int `yaml:"max_global_streams_per_user"`
|
||
![]()
6 years ago
|
|
||
|
// Querier enforced limits.
|
||
|
MaxChunksPerQuery int `yaml:"max_chunks_per_query"`
|
||
![]()
5 years ago
|
MaxQuerySeries int `yaml:"max_query_series"`
|
||
![]()
4 years ago
|
MaxQueryLookback time.Duration `yaml:"max_query_lookback"`
|
||
![]()
6 years ago
|
MaxQueryLength time.Duration `yaml:"max_query_length"`
|
||
|
MaxQueryParallelism int `yaml:"max_query_parallelism"`
|
||
|
CardinalityLimit int `yaml:"cardinality_limit"`
|
||
|
MaxStreamsMatchersPerQuery int `yaml:"max_streams_matchers_per_query"`
|
||
![]()
5 years ago
|
MaxConcurrentTailRequests int `yaml:"max_concurrent_tail_requests"`
|
||
![]()
5 years ago
|
MaxEntriesLimitPerQuery int `yaml:"max_entries_limit_per_query"`
|
||
![]()
5 years ago
|
MaxCacheFreshness time.Duration `yaml:"max_cache_freshness_per_query"`
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
// Query frontend enforced limits. The default is actually parameterized by the queryrange config.
|
||
|
QuerySplitDuration time.Duration `yaml:"split_queries_by_interval"`
|
||
|
|
||
![]()
4 years ago
|
// Ruler defaults and limits.
|
||
|
RulerEvaluationDelay time.Duration `yaml:"ruler_evaluation_delay_duration"`
|
||
|
RulerMaxRulesPerRuleGroup int `yaml:"ruler_max_rules_per_rule_group"`
|
||
|
RulerMaxRuleGroupsPerTenant int `yaml:"ruler_max_rule_groups_per_tenant"`
|
||
|
|
||
![]()
6 years ago
|
// Config for overrides, convenient if it goes here.
|
||
|
PerTenantOverrideConfig string `yaml:"per_tenant_override_config"`
|
||
|
PerTenantOverridePeriod time.Duration `yaml:"per_tenant_override_period"`
|
||
|
}
|
||
|
|
||
|
// RegisterFlags adds the flags required to config this to the given FlagSet
|
||
|
func (l *Limits) RegisterFlags(f *flag.FlagSet) {
|
||
![]()
5 years ago
|
f.StringVar(&l.IngestionRateStrategy, "distributor.ingestion-rate-limit-strategy", "local", "Whether the ingestion rate limit should be applied individually to each distributor instance (local), or evenly shared across the cluster (global).")
|
||
|
f.Float64Var(&l.IngestionRateMB, "distributor.ingestion-rate-limit-mb", 4, "Per-user ingestion rate limit in sample size per second. Units in MB.")
|
||
|
f.Float64Var(&l.IngestionBurstSizeMB, "distributor.ingestion-burst-size-mb", 6, "Per-user allowed ingestion burst size (in sample size). Units in MB.")
|
||
![]()
5 years ago
|
f.Var(&l.MaxLineSize, "distributor.max-line-size", "maximum line length allowed, i.e. 100mb. Default (0) means unlimited.")
|
||
![]()
6 years ago
|
f.IntVar(&l.MaxLabelNameLength, "validation.max-length-label-name", 1024, "Maximum length accepted for label names")
|
||
|
f.IntVar(&l.MaxLabelValueLength, "validation.max-length-label-value", 2048, "Maximum length accepted for label value. This setting also applies to the metric name")
|
||
|
f.IntVar(&l.MaxLabelNamesPerSeries, "validation.max-label-names-per-series", 30, "Maximum number of label names per series.")
|
||
|
f.BoolVar(&l.RejectOldSamples, "validation.reject-old-samples", false, "Reject old samples.")
|
||
|
f.DurationVar(&l.RejectOldSamplesMaxAge, "validation.reject-old-samples.max-age", 14*24*time.Hour, "Maximum accepted sample age before rejecting.")
|
||
|
f.DurationVar(&l.CreationGracePeriod, "validation.create-grace-period", 10*time.Minute, "Duration which table will be created/deleted before/after it's needed; we won't accept sample from before this time.")
|
||
|
f.BoolVar(&l.EnforceMetricName, "validation.enforce-metric-name", true, "Enforce every sample has a metric name.")
|
||
![]()
5 years ago
|
f.IntVar(&l.MaxEntriesLimitPerQuery, "validation.max-entries-limit", 5000, "Per-user entries limit per query")
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
f.IntVar(&l.MaxLocalStreamsPerUser, "ingester.max-streams-per-user", 10e3, "Maximum number of active streams per user, per ingester. 0 to disable.")
|
||
|
f.IntVar(&l.MaxGlobalStreamsPerUser, "ingester.max-global-streams-per-user", 0, "Maximum number of active streams per user, across the cluster. 0 to disable.")
|
||
![]()
6 years ago
|
|
||
|
f.IntVar(&l.MaxChunksPerQuery, "store.query-chunk-limit", 2e6, "Maximum number of chunks that can be fetched in a single query.")
|
||
|
f.DurationVar(&l.MaxQueryLength, "store.max-query-length", 0, "Limit to length of chunk store queries, 0 to disable.")
|
||
![]()
5 years ago
|
f.IntVar(&l.MaxQuerySeries, "querier.max-query-series", 500, "Limit the maximum of unique series returned by a metric query. When the limit is reached an error is returned.")
|
||
![]()
4 years ago
|
f.DurationVar(&l.MaxQueryLookback, "querier.max-query-lookback", 0, "Limit how long back data (series and metadata) can be queried, up until <lookback> duration ago. This limit is enforced in the query-frontend, querier and ruler. If the requested time range is outside the allowed range, the request will not fail but will be manipulated to only query data within the allowed time range. 0 to disable.")
|
||
![]()
6 years ago
|
f.IntVar(&l.MaxQueryParallelism, "querier.max-query-parallelism", 14, "Maximum number of queries will be scheduled in parallel by the frontend.")
|
||
|
f.IntVar(&l.CardinalityLimit, "store.cardinality-limit", 1e5, "Cardinality limit for index queries.")
|
||
|
f.IntVar(&l.MaxStreamsMatchersPerQuery, "querier.max-streams-matcher-per-query", 1000, "Limit the number of streams matchers per query")
|
||
![]()
5 years ago
|
f.IntVar(&l.MaxConcurrentTailRequests, "querier.max-concurrent-tail-requests", 10, "Limit the number of concurrent tail requests")
|
||
![]()
5 years ago
|
f.DurationVar(&l.MaxCacheFreshness, "frontend.max-cache-freshness", 1*time.Minute, "Most recent allowed cacheable result per-tenant, to prevent caching very recent results that might still be in flux.")
|
||
![]()
6 years ago
|
|
||
![]()
4 years ago
|
f.DurationVar(&l.RulerEvaluationDelay, "ruler.evaluation-delay-duration", 0, "Duration to delay the evaluation of rules to ensure the underlying metrics have been pushed to Cortex.")
|
||
|
f.IntVar(&l.RulerMaxRulesPerRuleGroup, "ruler.max-rules-per-rule-group", 0, "Maximum number of rules per rule group per-tenant. 0 to disable.")
|
||
|
f.IntVar(&l.RulerMaxRuleGroupsPerTenant, "ruler.max-rule-groups-per-tenant", 0, "Maximum number of rule groups per-tenant. 0 to disable.")
|
||
|
|
||
![]()
6 years ago
|
f.StringVar(&l.PerTenantOverrideConfig, "limits.per-user-override-config", "", "File name of per-user overrides.")
|
||
|
f.DurationVar(&l.PerTenantOverridePeriod, "limits.per-user-override-period", 10*time.Second, "Period with this to reload the overrides.")
|
||
|
}
|
||
|
|
||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||
|
func (l *Limits) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||
|
// We want to set c to the defaults and then overwrite it with the input.
|
||
|
// To make unmarshal fill the plain data struct rather than calling UnmarshalYAML
|
||
|
// again, we have to hide it using a type indirection. See prometheus/config.
|
||
|
|
||
|
// During startup we wont have a default value so we don't want to overwrite them
|
||
|
if defaultLimits != nil {
|
||
|
*l = *defaultLimits
|
||
|
}
|
||
|
type plain Limits
|
||
|
return unmarshal((*plain)(l))
|
||
|
}
|
||
|
|
||
|
// When we load YAML from disk, we want the various per-customer limits
|
||
|
// to default to any values specified on the command line, not default
|
||
|
// command line values. This global contains those values. I (Tom) cannot
|
||
|
// find a nicer way I'm afraid.
|
||
|
var defaultLimits *Limits
|
||
|
|
||
![]()
5 years ago
|
// SetDefaultLimitsForYAMLUnmarshalling sets global default limits, used when loading
|
||
|
// Limits from YAML files. This is used to ensure per-tenant limits are defaulted to
|
||
|
// those values.
|
||
|
func SetDefaultLimitsForYAMLUnmarshalling(defaults Limits) {
|
||
|
defaultLimits = &defaults
|
||
|
}
|
||
|
|
||
|
// TenantLimits is a function that returns limits for given tenant, or
|
||
|
// nil, if there are no tenant-specific limits.
|
||
|
type TenantLimits func(userID string) *Limits
|
||
|
|
||
![]()
6 years ago
|
// Overrides periodically fetch a set of per-user overrides, and provides convenience
|
||
|
// functions for fetching the correct value.
|
||
|
type Overrides struct {
|
||
![]()
5 years ago
|
defaultLimits *Limits
|
||
|
tenantLimits TenantLimits
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// NewOverrides makes a new Overrides.
|
||
![]()
5 years ago
|
func NewOverrides(defaults Limits, tenantLimits TenantLimits) (*Overrides, error) {
|
||
![]()
6 years ago
|
return &Overrides{
|
||
![]()
5 years ago
|
tenantLimits: tenantLimits,
|
||
|
defaultLimits: &defaults,
|
||
![]()
6 years ago
|
}, nil
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
// IngestionRateStrategy returns whether the ingestion rate limit should be individually applied
|
||
|
// to each distributor instance (local) or evenly shared across the cluster (global).
|
||
|
func (o *Overrides) IngestionRateStrategy() string {
|
||
|
// The ingestion rate strategy can't be overridden on a per-tenant basis,
|
||
|
// so here we just pick the value for a not-existing user ID (empty string).
|
||
![]()
5 years ago
|
return o.getOverridesForUser("").IngestionRateStrategy
|
||
![]()
5 years ago
|
}
|
||
|
|
||
|
// IngestionRateBytes returns the limit on ingester rate (MBs per second).
|
||
|
func (o *Overrides) IngestionRateBytes(userID string) float64 {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).IngestionRateMB * bytesInMB
|
||
![]()
6 years ago
|
}
|
||
|
|
||
![]()
5 years ago
|
// IngestionBurstSizeBytes returns the burst size for ingestion rate.
|
||
|
func (o *Overrides) IngestionBurstSizeBytes(userID string) int {
|
||
![]()
5 years ago
|
return int(o.getOverridesForUser(userID).IngestionBurstSizeMB * bytesInMB)
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxLabelNameLength returns maximum length a label name can be.
|
||
|
func (o *Overrides) MaxLabelNameLength(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxLabelNameLength
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxLabelValueLength returns maximum length a label value can be. This also is
|
||
|
// the maximum length of a metric name.
|
||
|
func (o *Overrides) MaxLabelValueLength(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxLabelValueLength
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxLabelNamesPerSeries returns maximum number of label/value pairs timeseries.
|
||
|
func (o *Overrides) MaxLabelNamesPerSeries(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxLabelNamesPerSeries
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// RejectOldSamples returns true when we should reject samples older than certain
|
||
|
// age.
|
||
|
func (o *Overrides) RejectOldSamples(userID string) bool {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).RejectOldSamples
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// RejectOldSamplesMaxAge returns the age at which samples should be rejected.
|
||
|
func (o *Overrides) RejectOldSamplesMaxAge(userID string) time.Duration {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).RejectOldSamplesMaxAge
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// CreationGracePeriod is misnamed, and actually returns how far into the future
|
||
|
// we should accept samples.
|
||
|
func (o *Overrides) CreationGracePeriod(userID string) time.Duration {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).CreationGracePeriod
|
||
![]()
6 years ago
|
}
|
||
|
|
||
![]()
5 years ago
|
// MaxLocalStreamsPerUser returns the maximum number of streams a user is allowed to store
|
||
|
// in a single ingester.
|
||
|
func (o *Overrides) MaxLocalStreamsPerUser(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxLocalStreamsPerUser
|
||
![]()
5 years ago
|
}
|
||
|
|
||
|
// MaxGlobalStreamsPerUser returns the maximum number of streams a user is allowed to store
|
||
|
// across the cluster.
|
||
|
func (o *Overrides) MaxGlobalStreamsPerUser(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxGlobalStreamsPerUser
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxChunksPerQuery returns the maximum number of chunks allowed per query.
|
||
|
func (o *Overrides) MaxChunksPerQuery(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxChunksPerQuery
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxQueryLength returns the limit of the length (in time) of a query.
|
||
|
func (o *Overrides) MaxQueryLength(userID string) time.Duration {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxQueryLength
|
||
![]()
6 years ago
|
}
|
||
|
|
||
![]()
5 years ago
|
// MaxQueryLength returns the limit of the series of metric queries.
|
||
|
func (o *Overrides) MaxQuerySeries(userID string) int {
|
||
|
return o.getOverridesForUser(userID).MaxQuerySeries
|
||
|
}
|
||
|
|
||
![]()
6 years ago
|
// MaxQueryParallelism returns the limit to the number of sub-queries the
|
||
|
// frontend will process in parallel.
|
||
|
func (o *Overrides) MaxQueryParallelism(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxQueryParallelism
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// EnforceMetricName whether to enforce the presence of a metric name.
|
||
|
func (o *Overrides) EnforceMetricName(userID string) bool {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).EnforceMetricName
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// CardinalityLimit whether to enforce the presence of a metric name.
|
||
|
func (o *Overrides) CardinalityLimit(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).CardinalityLimit
|
||
![]()
6 years ago
|
}
|
||
|
|
||
|
// MaxStreamsMatchersPerQuery returns the limit to number of streams matchers per query.
|
||
|
func (o *Overrides) MaxStreamsMatchersPerQuery(userID string) int {
|
||
![]()
5 years ago
|
return o.getOverridesForUser(userID).MaxStreamsMatchersPerQuery
|
||
|
}
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
// QuerySplitDuration returns the tenant specific splitby interval applied in the query frontend.
|
||
|
func (o *Overrides) QuerySplitDuration(userID string) time.Duration {
|
||
|
return o.getOverridesForUser(userID).QuerySplitDuration
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
// MaxConcurrentTailRequests returns the limit to number of concurrent tail requests.
|
||
|
func (o *Overrides) MaxConcurrentTailRequests(userID string) int {
|
||
|
return o.getOverridesForUser(userID).MaxConcurrentTailRequests
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
// MaxLineSize returns the maximum size in bytes the distributor should allow.
|
||
|
func (o *Overrides) MaxLineSize(userID string) int {
|
||
|
return o.getOverridesForUser(userID).MaxLineSize.Val()
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
// MaxEntriesLimitPerQuery returns the limit to number of entries the querier should return per query.
|
||
|
func (o *Overrides) MaxEntriesLimitPerQuery(userID string) int {
|
||
|
return o.getOverridesForUser(userID).MaxEntriesLimitPerQuery
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
func (o *Overrides) MaxCacheFreshness(userID string) time.Duration {
|
||
|
return o.getOverridesForUser(userID).MaxCacheFreshness
|
||
|
}
|
||
|
|
||
![]()
4 years ago
|
// MaxQueryLookback returns the max lookback period of queries.
|
||
|
func (o *Overrides) MaxQueryLookback(userID string) time.Duration {
|
||
|
return o.getOverridesForUser(userID).MaxQueryLookback
|
||
|
}
|
||
|
|
||
![]()
4 years ago
|
// EvaluationDelay returns the rules evaluation delay for a given user.
|
||
|
func (o *Overrides) EvaluationDelay(userID string) time.Duration {
|
||
|
return o.getOverridesForUser(userID).RulerEvaluationDelay
|
||
|
}
|
||
|
|
||
|
// RulerTenantShardSize returns shard size (number of rulers) used by this tenant when using shuffle-sharding strategy.
|
||
|
// Not used in Loki.
|
||
|
func (o *Overrides) RulerTenantShardSize(userID string) int {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
// RulerMaxRulesPerRuleGroup returns the maximum number of rules per rule group for a given user.
|
||
|
func (o *Overrides) RulerMaxRulesPerRuleGroup(userID string) int {
|
||
|
return o.getOverridesForUser(userID).RulerMaxRulesPerRuleGroup
|
||
|
}
|
||
|
|
||
|
// RulerMaxRuleGroupsPerTenant returns the maximum number of rule groups for a given user.
|
||
|
func (o *Overrides) RulerMaxRuleGroupsPerTenant(userID string) int {
|
||
|
return o.getOverridesForUser(userID).RulerMaxRuleGroupsPerTenant
|
||
|
}
|
||
|
|
||
![]()
5 years ago
|
func (o *Overrides) getOverridesForUser(userID string) *Limits {
|
||
|
if o.tenantLimits != nil {
|
||
|
l := o.tenantLimits(userID)
|
||
|
if l != nil {
|
||
|
return l
|
||
|
}
|
||
![]()
6 years ago
|
}
|
||
![]()
5 years ago
|
return o.defaultLimits
|
||
![]()
6 years ago
|
}
|