Skip to content

Commit 39e5ade

Browse files
txthrottler: verify config at vttablet startup, consolidate funcs (vitessio#13115)
* txthrottler: verify config at vttablet startup, consolidate funcs Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Use explicit dest in prototext.Unmarshal Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Use for loop for TestVerifyTxThrottlerConfig Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Cleanup test Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Fix go vet complaint Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Add back synonym flag Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Update go/vt/vttablet/tabletserver/txthrottler/tx_throttler.go Co-authored-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * Address staticcheck linter error Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> --------- Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> Co-authored-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
1 parent 28dbd9e commit 39e5ade

File tree

6 files changed

+242
-129
lines changed

6 files changed

+242
-129
lines changed

go/flags/endtoend/vttablet.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,11 +342,11 @@ Usage of vttablet:
342342
--twopc_abandon_age float time in seconds. Any unresolved transaction older than this time will be sent to the coordinator to be resolved.
343343
--twopc_coordinator_address string address of the (VTGate) process(es) that will be used to notify of abandoned transactions.
344344
--twopc_enable if the flag is on, 2pc is enabled. Other 2pc flags must be supplied.
345-
--tx-throttler-config string Synonym to -tx_throttler_config (default "target_replication_lag_sec: 2\nmax_replication_lag_sec: 10\ninitial_rate: 100\nmax_increase: 1\nemergency_decrease: 0.5\nmin_duration_between_increases_sec: 40\nmax_duration_between_increases_sec: 62\nmin_duration_between_decreases_sec: 20\nspread_backlog_across_sec: 20\nage_bad_rate_after_sec: 180\nbad_rate_increase: 0.1\nmax_rate_approach_threshold: 0.9\n")
345+
--tx-throttler-config string Synonym to -tx_throttler_config (default "target_replication_lag_sec:2 max_replication_lag_sec:10 initial_rate:100 max_increase:1 emergency_decrease:0.5 min_duration_between_increases_sec:40 max_duration_between_increases_sec:62 min_duration_between_decreases_sec:20 spread_backlog_across_sec:20 age_bad_rate_after_sec:180 bad_rate_increase:0.1 max_rate_approach_threshold:0.9")
346346
--tx-throttler-default-priority int Default priority assigned to queries that lack priority information (default 100)
347347
--tx-throttler-healthcheck-cells strings Synonym to -tx_throttler_healthcheck_cells
348348
--tx-throttler-tablet-types strings A comma-separated list of tablet types. Only tablets of this type are monitored for replication lag by the transaction throttler. Supported types are replica and/or rdonly. (default replica)
349-
--tx_throttler_config string The configuration of the transaction throttler as a text-formatted throttlerdata.Configuration protocol buffer message. (default "target_replication_lag_sec: 2\nmax_replication_lag_sec: 10\ninitial_rate: 100\nmax_increase: 1\nemergency_decrease: 0.5\nmin_duration_between_increases_sec: 40\nmax_duration_between_increases_sec: 62\nmin_duration_between_decreases_sec: 20\nspread_backlog_across_sec: 20\nage_bad_rate_after_sec: 180\nbad_rate_increase: 0.1\nmax_rate_approach_threshold: 0.9\n")
349+
--tx_throttler_config string The configuration of the transaction throttler as a text-formatted throttlerdata.Configuration protocol buffer message. (default "target_replication_lag_sec:2 max_replication_lag_sec:10 initial_rate:100 max_increase:1 emergency_decrease:0.5 min_duration_between_increases_sec:40 max_duration_between_increases_sec:62 min_duration_between_decreases_sec:20 spread_backlog_across_sec:20 age_bad_rate_after_sec:180 bad_rate_increase:0.1 max_rate_approach_threshold:0.9")
350350
--tx_throttler_healthcheck_cells strings A comma-separated list of cells. Only tabletservers running in these cells will be monitored for replication lag by the transaction throttler.
351351
--unhealthy_threshold duration replication lag after which a replica is considered unhealthy (default 2h0m0s)
352352
--use_super_read_only Set super_read_only flag when performing planned failover.

go/flagutil/flagutil.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,17 @@ func DualFormatBoolVar(fs *pflag.FlagSet, p *bool, name string, value bool, usag
193193
}
194194
}
195195

196+
// DualFormatVar creates a flag which supports both dashes and underscores
197+
func DualFormatVar(fs *pflag.FlagSet, val pflag.Value, name string, usage string) {
198+
dashes := strings.Replace(name, "_", "-", -1)
199+
underscores := strings.Replace(name, "-", "_", -1)
200+
201+
fs.Var(val, underscores, usage)
202+
if dashes != underscores {
203+
fs.Var(val, dashes, fmt.Sprintf("Synonym to -%s", underscores))
204+
}
205+
}
206+
196207
// DurationOrIntVar implements pflag.Value for flags that have historically been
197208
// of type IntVar (and then converted to seconds or some other unit) but are
198209
// now transitioning to a proper DurationVar type.

go/vt/vttablet/tabletserver/tabletenv/config.go

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ import (
3030
"vitess.io/vitess/go/streamlog"
3131
"vitess.io/vitess/go/vt/dbconfigs"
3232
"vitess.io/vitess/go/vt/log"
33-
querypb "vitess.io/vitess/go/vt/proto/query"
34-
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
35-
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
3633
"vitess.io/vitess/go/vt/servenv"
3734
"vitess.io/vitess/go/vt/sqlparser"
3835
"vitess.io/vitess/go/vt/throttler"
3936
"vitess.io/vitess/go/vt/topo/topoproto"
4037
"vitess.io/vitess/go/vt/vterrors"
38+
39+
querypb "vitess.io/vitess/go/vt/proto/query"
40+
throttlerdatapb "vitess.io/vitess/go/vt/proto/throttlerdata"
41+
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
42+
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
4143
)
4244

4345
// These constants represent values for various config parameters.
@@ -88,6 +90,24 @@ var (
8890
txLogHandler = "/debug/txlog"
8991
)
9092

93+
type TxThrottlerConfigFlag struct {
94+
*throttlerdatapb.Configuration
95+
}
96+
97+
func NewTxThrottlerConfigFlag() *TxThrottlerConfigFlag {
98+
return &TxThrottlerConfigFlag{&throttlerdatapb.Configuration{}}
99+
}
100+
101+
func (t *TxThrottlerConfigFlag) Get() *throttlerdatapb.Configuration {
102+
return t.Configuration
103+
}
104+
105+
func (t *TxThrottlerConfigFlag) Set(arg string) error {
106+
return prototext.Unmarshal([]byte(arg), t.Configuration)
107+
}
108+
109+
func (t *TxThrottlerConfigFlag) Type() string { return "string" }
110+
91111
// RegisterTabletEnvFlags is a public API to register tabletenv flags for use by test cases that expect
92112
// some flags to be set with default values
93113
func RegisterTabletEnvFlags(fs *pflag.FlagSet) {
@@ -143,7 +163,7 @@ func registerTabletEnvFlags(fs *pflag.FlagSet) {
143163
SecondsVar(fs, &currentConfig.TwoPCAbandonAge, "twopc_abandon_age", defaultConfig.TwoPCAbandonAge, "time in seconds. Any unresolved transaction older than this time will be sent to the coordinator to be resolved.")
144164
// Tx throttler config
145165
flagutil.DualFormatBoolVar(fs, &currentConfig.EnableTxThrottler, "enable_tx_throttler", defaultConfig.EnableTxThrottler, "If true replication-lag-based throttling on transactions will be enabled.")
146-
flagutil.DualFormatStringVar(fs, &currentConfig.TxThrottlerConfig, "tx_throttler_config", defaultConfig.TxThrottlerConfig, "The configuration of the transaction throttler as a text-formatted throttlerdata.Configuration protocol buffer message.")
166+
flagutil.DualFormatVar(fs, currentConfig.TxThrottlerConfig, "tx_throttler_config", "The configuration of the transaction throttler as a text-formatted throttlerdata.Configuration protocol buffer message.")
147167
flagutil.DualFormatStringListVar(fs, &currentConfig.TxThrottlerHealthCheckCells, "tx_throttler_healthcheck_cells", defaultConfig.TxThrottlerHealthCheckCells, "A comma-separated list of cells. Only tabletservers running in these cells will be monitored for replication lag by the transaction throttler.")
148168
fs.IntVar(&currentConfig.TxThrottlerDefaultPriority, "tx-throttler-default-priority", defaultConfig.TxThrottlerDefaultPriority, "Default priority assigned to queries that lack priority information")
149169
fs.Var(currentConfig.TxThrottlerTabletTypes, "tx-throttler-tablet-types", "A comma-separated list of tablet types. Only tablets of this type are monitored for replication lag by the transaction throttler. Supported types are replica and/or rdonly.")
@@ -316,7 +336,7 @@ type TabletConfig struct {
316336
TwoPCAbandonAge Seconds `json:"-"`
317337

318338
EnableTxThrottler bool `json:"-"`
319-
TxThrottlerConfig string `json:"-"`
339+
TxThrottlerConfig *TxThrottlerConfigFlag `json:"-"`
320340
TxThrottlerHealthCheckCells []string `json:"-"`
321341
TxThrottlerDefaultPriority int `json:"-"`
322342
TxThrottlerTabletTypes *topoproto.TabletTypeListFlag `json:"-"`
@@ -470,9 +490,6 @@ func (c *TabletConfig) Verify() error {
470490
if v := c.HotRowProtection.MaxConcurrency; v <= 0 {
471491
return fmt.Errorf("-hot_row_protection_concurrent_transactions must be > 0 (specified value: %v)", v)
472492
}
473-
if v := c.TxThrottlerDefaultPriority; v > sqlparser.MaxPriorityValue || v < 0 {
474-
return fmt.Errorf("--tx-throttler-default-priority must be > 0 and < 100 (specified value: %d)", v)
475-
}
476493
return nil
477494
}
478495

@@ -508,6 +525,22 @@ func (c *TabletConfig) verifyTransactionLimitConfig() error {
508525

509526
// verifyTxThrottlerConfig checks the TxThrottler related config for sanity.
510527
func (c *TabletConfig) verifyTxThrottlerConfig() error {
528+
if !c.EnableTxThrottler {
529+
return nil
530+
}
531+
532+
err := throttler.MaxReplicationLagModuleConfig{Configuration: c.TxThrottlerConfig.Get()}.Verify()
533+
if err != nil {
534+
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "failed to parse throttlerdatapb.Configuration config: %v", err)
535+
}
536+
537+
if len(c.TxThrottlerHealthCheckCells) == 0 {
538+
return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "empty healthCheckCells given: %+v", c.TxThrottlerHealthCheckCells)
539+
}
540+
if v := c.TxThrottlerDefaultPriority; v > sqlparser.MaxPriorityValue || v < 0 {
541+
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "--tx-throttler-default-priority must be > 0 and < 100 (specified value: %d)", v)
542+
}
543+
511544
if c.TxThrottlerTabletTypes == nil || len(*c.TxThrottlerTabletTypes) == 0 {
512545
return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "--tx-throttler-tablet-types must be defined when transaction throttler is enabled")
513546
}
@@ -519,6 +552,7 @@ func (c *TabletConfig) verifyTxThrottlerConfig() error {
519552
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported tablet type %q", tabletType)
520553
}
521554
}
555+
522556
return nil
523557
}
524558

@@ -606,17 +640,16 @@ var defaultConfig = TabletConfig{
606640
EnablePerWorkloadTableMetrics: false,
607641
}
608642

609-
// defaultTxThrottlerConfig formats the default throttlerdata.Configuration
610-
// object in text format. It uses the object returned by
611-
// throttler.DefaultMaxReplicationLagModuleConfig().Configuration and overrides some of its
612-
// fields. It panics on error.
613-
func defaultTxThrottlerConfig() string {
643+
// defaultTxThrottlerConfig returns the default TxThrottlerConfigFlag object based on
644+
// a throttler.DefaultMaxReplicationLagModuleConfig().Configuration and overrides some of
645+
// its fields. It panics on error.
646+
func defaultTxThrottlerConfig() *TxThrottlerConfigFlag {
614647
// Take throttler.DefaultMaxReplicationLagModuleConfig and override some fields.
615648
config := throttler.DefaultMaxReplicationLagModuleConfig().Configuration
616649
// TODO(erez): Make DefaultMaxReplicationLagModuleConfig() return a MaxReplicationLagSec of 10
617650
// and remove this line.
618651
config.MaxReplicationLagSec = 10
619-
return prototext.Format(config)
652+
return &TxThrottlerConfigFlag{config}
620653
}
621654

622655
func defaultTransactionLimitConfig() TransactionLimitConfig {

go/vt/vttablet/tabletserver/tabletenv/config_test.go

Lines changed: 126 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ import (
2626

2727
"vitess.io/vitess/go/test/utils"
2828
"vitess.io/vitess/go/vt/dbconfigs"
29-
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
30-
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
29+
"vitess.io/vitess/go/vt/throttler"
3130
"vitess.io/vitess/go/vt/topo/topoproto"
3231
"vitess.io/vitess/go/vt/vterrors"
3332
"vitess.io/vitess/go/yaml2"
33+
34+
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
35+
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
3436
)
3537

3638
func TestConfigParse(t *testing.T) {
@@ -325,31 +327,133 @@ func TestFlags(t *testing.T) {
325327
assert.Equal(t, want, currentConfig)
326328
}
327329

328-
func TestVerifyTxThrottlerConfig(t *testing.T) {
330+
func TestTxThrottlerConfigFlag(t *testing.T) {
331+
f := NewTxThrottlerConfigFlag()
332+
defaultMaxReplicationLagModuleConfig := throttler.DefaultMaxReplicationLagModuleConfig().Configuration
333+
329334
{
330-
// default config (replica)
331-
assert.Nil(t, currentConfig.verifyTxThrottlerConfig())
335+
assert.Nil(t, f.Set(defaultMaxReplicationLagModuleConfig.String()))
336+
assert.Equal(t, defaultMaxReplicationLagModuleConfig.String(), f.String())
337+
assert.Equal(t, "string", f.Type())
332338
}
333339
{
334-
// replica + rdonly (allowed)
335-
currentConfig.TxThrottlerTabletTypes = &topoproto.TabletTypeListFlag{
336-
topodatapb.TabletType_REPLICA,
337-
topodatapb.TabletType_RDONLY,
338-
}
339-
assert.Nil(t, currentConfig.verifyTxThrottlerConfig())
340+
defaultMaxReplicationLagModuleConfig.TargetReplicationLagSec = 5
341+
assert.Nil(t, f.Set(defaultMaxReplicationLagModuleConfig.String()))
342+
assert.NotNil(t, f.Get())
343+
assert.Equal(t, int64(5), f.Get().TargetReplicationLagSec)
340344
}
341345
{
342-
// no tablet types
343-
currentConfig.TxThrottlerTabletTypes = &topoproto.TabletTypeListFlag{}
344-
err := currentConfig.verifyTxThrottlerConfig()
345-
assert.NotNil(t, err)
346-
assert.Equal(t, vtrpcpb.Code_FAILED_PRECONDITION, vterrors.Code(err))
346+
assert.NotNil(t, f.Set("should not parse"))
347347
}
348-
{
349-
// disallowed tablet type
350-
currentConfig.TxThrottlerTabletTypes = &topoproto.TabletTypeListFlag{topodatapb.TabletType_DRAINED}
351-
err := currentConfig.verifyTxThrottlerConfig()
352-
assert.NotNil(t, err)
353-
assert.Equal(t, vtrpcpb.Code_INVALID_ARGUMENT, vterrors.Code(err))
348+
}
349+
350+
func TestVerifyTxThrottlerConfig(t *testing.T) {
351+
defaultMaxReplicationLagModuleConfig := throttler.DefaultMaxReplicationLagModuleConfig().Configuration
352+
invalidMaxReplicationLagModuleConfig := throttler.DefaultMaxReplicationLagModuleConfig().Configuration
353+
invalidMaxReplicationLagModuleConfig.TargetReplicationLagSec = -1
354+
355+
type testConfig struct {
356+
Name string
357+
ExpectedErrorCode vtrpcpb.Code
358+
//
359+
EnableTxThrottler bool
360+
TxThrottlerConfig *TxThrottlerConfigFlag
361+
TxThrottlerHealthCheckCells []string
362+
TxThrottlerTabletTypes *topoproto.TabletTypeListFlag
363+
TxThrottlerDefaultPriority int
364+
}
365+
366+
tests := []testConfig{
367+
{
368+
// default (disabled)
369+
Name: "default",
370+
EnableTxThrottler: false,
371+
},
372+
{
373+
// enabled with invalid throttler config
374+
Name: "enabled invalid config",
375+
ExpectedErrorCode: vtrpcpb.Code_INVALID_ARGUMENT,
376+
EnableTxThrottler: true,
377+
TxThrottlerConfig: &TxThrottlerConfigFlag{invalidMaxReplicationLagModuleConfig},
378+
},
379+
{
380+
// enabled without cells defined
381+
Name: "enabled without cells",
382+
ExpectedErrorCode: vtrpcpb.Code_FAILED_PRECONDITION,
383+
EnableTxThrottler: true,
384+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
385+
},
386+
{
387+
// enabled with good config (default/replica tablet type)
388+
Name: "enabled",
389+
EnableTxThrottler: true,
390+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
391+
TxThrottlerHealthCheckCells: []string{"cell1"},
392+
},
393+
{
394+
// enabled + replica and rdonly tablet types
395+
Name: "enabled plus rdonly",
396+
EnableTxThrottler: true,
397+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
398+
TxThrottlerHealthCheckCells: []string{"cell1"},
399+
TxThrottlerTabletTypes: &topoproto.TabletTypeListFlag{
400+
topodatapb.TabletType_REPLICA,
401+
topodatapb.TabletType_RDONLY,
402+
},
403+
},
404+
{
405+
// enabled without tablet types
406+
Name: "enabled without tablet types",
407+
ExpectedErrorCode: vtrpcpb.Code_FAILED_PRECONDITION,
408+
EnableTxThrottler: true,
409+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
410+
TxThrottlerHealthCheckCells: []string{"cell1"},
411+
TxThrottlerTabletTypes: &topoproto.TabletTypeListFlag{},
412+
},
413+
{
414+
// enabled + disallowed tablet type
415+
Name: "enabled disallowed tablet type",
416+
ExpectedErrorCode: vtrpcpb.Code_INVALID_ARGUMENT,
417+
EnableTxThrottler: true,
418+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
419+
TxThrottlerHealthCheckCells: []string{"cell1"},
420+
TxThrottlerTabletTypes: &topoproto.TabletTypeListFlag{topodatapb.TabletType_DRAINED},
421+
},
422+
{
423+
// enabled + disallowed priority
424+
Name: "enabled disallowed priority",
425+
ExpectedErrorCode: vtrpcpb.Code_INVALID_ARGUMENT,
426+
EnableTxThrottler: true,
427+
TxThrottlerConfig: &TxThrottlerConfigFlag{defaultMaxReplicationLagModuleConfig},
428+
TxThrottlerDefaultPriority: 12345,
429+
TxThrottlerHealthCheckCells: []string{"cell1"},
430+
},
431+
}
432+
433+
for _, test := range tests {
434+
test := test
435+
t.Run(test.Name, func(t *testing.T) {
436+
t.Parallel()
437+
438+
config := defaultConfig
439+
config.EnableTxThrottler = test.EnableTxThrottler
440+
if test.TxThrottlerConfig == nil {
441+
test.TxThrottlerConfig = NewTxThrottlerConfigFlag()
442+
}
443+
config.TxThrottlerConfig = test.TxThrottlerConfig
444+
config.TxThrottlerHealthCheckCells = test.TxThrottlerHealthCheckCells
445+
config.TxThrottlerDefaultPriority = test.TxThrottlerDefaultPriority
446+
if test.TxThrottlerTabletTypes != nil {
447+
config.TxThrottlerTabletTypes = test.TxThrottlerTabletTypes
448+
}
449+
450+
err := config.verifyTxThrottlerConfig()
451+
if test.ExpectedErrorCode == vtrpcpb.Code_OK {
452+
assert.Nil(t, err)
453+
} else {
454+
assert.NotNil(t, err)
455+
assert.Equal(t, test.ExpectedErrorCode, vterrors.Code(err))
456+
}
457+
})
354458
}
355459
}

0 commit comments

Comments
 (0)