Skip to content

Commit

Permalink
tenantrate: switch to a single token bucket
Browse files Browse the repository at this point in the history
Tenant rate limiting currently uses four separate token buckets, each
with its own rate and burst limits. In this commit we switch to a
single shared token bucket (see cockroachdb#55114 for motivation).

We use a "cost model" to map read and write requests to "KV Compute
Units". Requests have a base cost plus a per-byte cost. The details
are documented in settings.go. The values were chosen based on
experiments ran by Nathan:
https://docs.google.com/spreadsheets/d/1PPlIcKnusOqWtBoOZVd9xBEMPe5Ss1FgrJlYFgpQZaM/edit#gid=735409177

The rate was chosen so that it maps to 20% of 1 KV vCPU. This keeps
the rate limit on small requests roughly the same as before
(especially on mixed workloads).

The largest departure from the previous limits is that we allow much
more read bytes (the per-byte cost of reads is small in the cost
model). If we were to keep close to the previous limits, the value of
kv.tenant_rate_limiter.read_cost_per_megabyte would be 200 instead of
10.  Perhaps we want to be more conservative here and make this
value somewhere in-between?

Fixes cockroachdb#55114.

Release note: None
  • Loading branch information
RaduBerinde committed Mar 30, 2021
1 parent 0e70529 commit 7769353
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 366 deletions.
14 changes: 7 additions & 7 deletions pkg/kv/kvserver/tenantrate/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type LimiterFactory struct {
systemLimiter systemLimiter
mu struct {
syncutil.RWMutex
limits LimitConfigs
limits Config
tenants map[roachpb.TenantID]*refCountedLimiter
}
}
Expand All @@ -53,12 +53,12 @@ func NewLimiterFactory(st *cluster.Settings, knobs *TestingKnobs) *LimiterFactor
rl.knobs = *knobs
}
rl.mu.tenants = make(map[roachpb.TenantID]*refCountedLimiter)
rl.mu.limits = LimitConfigsFromSettings(st)
rl.mu.limits = ConfigFromSettings(st)
rl.systemLimiter = systemLimiter{
tenantMetrics: rl.metrics.tenantMetrics(roachpb.SystemTenantID),
}
for _, setOnChange := range settingsSetOnChangeFuncs {
setOnChange(&st.SV, rl.updateLimits)
for _, setting := range configSettings {
setting.SetOnChange(&st.SV, rl.updateConfig)
}
return rl
}
Expand Down Expand Up @@ -114,12 +114,12 @@ func (rl *LimiterFactory) Release(lim Limiter) {
}
}

func (rl *LimiterFactory) updateLimits() {
func (rl *LimiterFactory) updateConfig() {
rl.mu.Lock()
defer rl.mu.Unlock()
rl.mu.limits = LimitConfigsFromSettings(rl.settings)
rl.mu.limits = ConfigFromSettings(rl.settings)
for _, rcLim := range rl.mu.tenants {
rcLim.lim.updateLimits(rl.mu.limits)
rcLim.lim.updateConfig(rl.mu.limits)
}
}

Expand Down
45 changes: 33 additions & 12 deletions pkg/kv/kvserver/tenantrate/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,38 @@

package tenantrate

import "github.com/cockroachdb/cockroach/pkg/settings/cluster"
import "github.com/cockroachdb/cockroach/pkg/settings"

// OverrideSettingsWithRateLimits utilizes LimitConfigs from the values stored in the
// settings.
func OverrideSettingsWithRateLimits(settings *cluster.Settings, rl LimitConfigs) {
readRequestRateLimit.Override(&settings.SV, float64(rl.ReadRequests.Rate))
readRequestBurstLimit.Override(&settings.SV, rl.ReadRequests.Burst)
writeRequestRateLimit.Override(&settings.SV, float64(rl.WriteRequests.Rate))
writeRequestBurstLimit.Override(&settings.SV, rl.WriteRequests.Burst)
readRateLimit.Override(&settings.SV, int64(rl.ReadBytes.Rate))
readBurstLimit.Override(&settings.SV, rl.ReadBytes.Burst)
writeRateLimit.Override(&settings.SV, int64(rl.WriteBytes.Rate))
writeBurstLimit.Override(&settings.SV, rl.WriteBytes.Burst)
// SettingValues is a struct that can be populated from test files, via YAML.
type SettingValues struct {
Rate float64
Burst float64

Read Factors
Write Factors
}

// Factors for reads and writes.
type Factors struct {
Base float64
PerByte float64
}

// OverrideSettings sets the cluster setting according to the given
// settingValues.
//
// Uninitialized (zero) values are ignored.
func OverrideSettings(sv *settings.Values, vals SettingValues) {
override := func(setting *settings.FloatSetting, val float64) {
if val != 0 {
setting.Override(sv, val)
}
}
override(kvcuRateLimit, vals.Rate)
override(kvcuBurstLimitSeconds, vals.Burst/kvcuRateLimit.Get(sv))

override(readRequestCost, vals.Read.Base)
override(readCostPerMB, vals.Read.PerByte*1024*1024)
override(writeRequestCost, vals.Write.Base)
override(writeCostPerMB, vals.Write.PerByte*1024*1024)
}
Loading

0 comments on commit 7769353

Please sign in to comment.