github.com/grafana/pyroscope@v1.18.0/pkg/distributor/rate_strategy.go (about)

     1  // SPDX-License-Identifier: AGPL-3.0-only
     2  // Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/distributor/ingestion_rate_strategy.go
     3  // Provenance-includes-license: Apache-2.0
     4  // Provenance-includes-copyright: The Cortex Authors.
     5  
     6  package distributor
     7  
     8  import (
     9  	"golang.org/x/time/rate"
    10  
    11  	"github.com/grafana/dskit/limiter"
    12  )
    13  
    14  // ReadLifecycler represents the read interface to the lifecycler.
    15  type ReadLifecycler interface {
    16  	HealthyInstancesCount() int
    17  }
    18  
    19  type globalStrategy struct {
    20  	baseStrategy limiter.RateLimiterStrategy
    21  	ring         ReadLifecycler
    22  }
    23  
    24  // newGlobalRateStrategy represents a ingestion rate limiting strategy that enforces the rate
    25  // limiting globally, configuring a per-distributor local rate limiter as "ingestion_rate / N",
    26  // where N is the number of distributor replicas (it's automatically adjusted if the
    27  // number of replicas change).
    28  //
    29  // The global strategy requires the distributors to form their own ring, which
    30  // is used to keep track of the current number of healthy distributor replicas.
    31  func newGlobalRateStrategy(baseStrategy limiter.RateLimiterStrategy, ring ReadLifecycler) limiter.RateLimiterStrategy {
    32  	return &globalStrategy{
    33  		baseStrategy: baseStrategy,
    34  		ring:         ring,
    35  	}
    36  }
    37  
    38  func (s *globalStrategy) Limit(tenantID string) float64 {
    39  	numDistributors := s.ring.HealthyInstancesCount()
    40  
    41  	limit := s.baseStrategy.Limit(tenantID)
    42  
    43  	if numDistributors == 0 || limit == float64(rate.Inf) {
    44  		return limit
    45  	}
    46  	return limit / float64(numDistributors)
    47  }
    48  
    49  func (s *globalStrategy) Burst(tenantID string) int {
    50  	// The meaning of burst doesn't change for the global strategy, in order
    51  	// to keep it easier to understand for users / operators.
    52  	return s.baseStrategy.Burst(tenantID)
    53  }
    54  
    55  type ingestionRateStrategy struct {
    56  	limits Limits
    57  }
    58  
    59  func newIngestionRateStrategy(limits Limits) limiter.RateLimiterStrategy {
    60  	return &ingestionRateStrategy{
    61  		limits: limits,
    62  	}
    63  }
    64  
    65  func (s *ingestionRateStrategy) Limit(tenantID string) float64 {
    66  	return s.limits.IngestionRateBytes(tenantID)
    67  }
    68  
    69  func (s *ingestionRateStrategy) Burst(tenantID string) int {
    70  	return s.limits.IngestionBurstSizeBytes(tenantID)
    71  }
    72  
    73  type infiniteStrategy struct{}
    74  
    75  func newInfiniteRateStrategy() limiter.RateLimiterStrategy {
    76  	return &infiniteStrategy{}
    77  }
    78  
    79  func (s *infiniteStrategy) Limit(tenantID string) float64 {
    80  	return float64(rate.Inf)
    81  }
    82  
    83  func (s *infiniteStrategy) Burst(tenantID string) int {
    84  	// Burst is ignored when limit = rate.Inf
    85  	return 0
    86  }