diff --git a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go index 2aa83263544..d459a467c26 100644 --- a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go +++ b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go @@ -13,8 +13,6 @@ package config // MySQLClusterConfigurationSettings has the settings for a specific MySQL cluster. It derives its information // from MySQLConfigurationSettings type MySQLClusterConfigurationSettings struct { - User string // override MySQLConfigurationSettings's, or leave empty to inherit those settings - Password string // override MySQLConfigurationSettings's, or leave empty to inherit those settings MetricQuery string // override MySQLConfigurationSettings's, or leave empty to inherit those settings CacheMillis int // override MySQLConfigurationSettings's, or leave empty to inherit those settings ThrottleThreshold float64 // override MySQLConfigurationSettings's, or leave empty to inherit those settings @@ -33,8 +31,6 @@ func (settings *MySQLClusterConfigurationSettings) postReadAdjustments() error { // MySQLConfigurationSettings has the general configuration for all MySQL clusters type MySQLConfigurationSettings struct { - User string - Password string MetricQuery string CacheMillis int // optional, if defined then probe result will be cached, and future probes may use cached value ThrottleThreshold float64 @@ -59,12 +55,6 @@ func (settings *MySQLConfigurationSettings) postReadAdjustments() error { if err := clusterSettings.postReadAdjustments(); err != nil { return err } - if clusterSettings.User == "" { - clusterSettings.User = settings.User - } - if clusterSettings.Password == "" { - clusterSettings.Password = settings.Password - } if clusterSettings.MetricQuery == "" { clusterSettings.MetricQuery = settings.MetricQuery } diff --git a/go/vt/vttablet/tabletserver/throttle/mysql/mysql_throttle_metric.go b/go/vt/vttablet/tabletserver/throttle/mysql/mysql_throttle_metric.go index 1a133796ba5..d4d8dde6366 100644 --- a/go/vt/vttablet/tabletserver/throttle/mysql/mysql_throttle_metric.go +++ b/go/vt/vttablet/tabletserver/throttle/mysql/mysql_throttle_metric.go @@ -13,8 +13,6 @@ import ( "github.com/patrickmn/go-cache" metrics "github.com/rcrowley/go-metrics" - - "vitess.io/vitess/go/vt/orchestrator/external/golib/sqlutils" ) // MetricsQueryType indicates the type of metrics query on MySQL backend. See following. @@ -118,44 +116,6 @@ func ReadThrottleMetric(probe *Probe, clusterName string, overrideGetMetricFunc }() }(mySQLThrottleMetric, started) - if overrideGetMetricFunc != nil { - mySQLThrottleMetric = overrideGetMetricFunc() - return cacheMySQLThrottleMetric(probe, mySQLThrottleMetric) - } - - dbURI := probe.GetDBUri("information_schema") - db, fromCache, err := sqlutils.GetDB(dbURI) - - if err != nil { - mySQLThrottleMetric.Err = err - return mySQLThrottleMetric - } - if !fromCache { - db.SetMaxOpenConns(maxPoolConnections) - db.SetMaxIdleConns(maxIdleConnections) - } - metricsQueryType := GetMetricsQueryType(probe.MetricQuery) - switch metricsQueryType { - case MetricsQueryTypeSelect: - mySQLThrottleMetric.Err = db.QueryRow(probe.MetricQuery).Scan(&mySQLThrottleMetric.Value) - return cacheMySQLThrottleMetric(probe, mySQLThrottleMetric) - case MetricsQueryTypeShowGlobal: - var variableName string // just a placeholder - mySQLThrottleMetric.Err = db.QueryRow(probe.MetricQuery).Scan(&variableName, &mySQLThrottleMetric.Value) - return cacheMySQLThrottleMetric(probe, mySQLThrottleMetric) - case MetricsQueryTypeDefault: - mySQLThrottleMetric.Err = sqlutils.QueryRowsMap(db, `show slave status`, func(m sqlutils.RowMap) error { - IOThreadRunning := m.GetString("Slave_IO_Running") - SQLThreadRunning := m.GetString("Slave_SQL_Running") - replicationLagSeconds := m.GetNullInt64("Seconds_Behind_Master") - if !replicationLagSeconds.Valid { - return fmt.Errorf("replication not running; Slave_IO_Running=%+v, Slave_SQL_Running=%+v", IOThreadRunning, SQLThreadRunning) - } - mySQLThrottleMetric.Value = float64(replicationLagSeconds.Int64) - return nil - }) - return cacheMySQLThrottleMetric(probe, mySQLThrottleMetric) - } - mySQLThrottleMetric.Err = fmt.Errorf("Unsupported metrics query type: %s", probe.MetricQuery) - return mySQLThrottleMetric + mySQLThrottleMetric = overrideGetMetricFunc() + return cacheMySQLThrottleMetric(probe, mySQLThrottleMetric) } diff --git a/go/vt/vttablet/tabletserver/throttle/mysql/probe.go b/go/vt/vttablet/tabletserver/throttle/mysql/probe.go index 187f058a2d5..5e0dd7fa1fa 100644 --- a/go/vt/vttablet/tabletserver/throttle/mysql/probe.go +++ b/go/vt/vttablet/tabletserver/throttle/mysql/probe.go @@ -8,18 +8,11 @@ package mysql import ( "fmt" - "net" ) -const maxPoolConnections = 3 -const maxIdleConnections = 3 -const timeoutMillis = 1000 - // Probe is the minimal configuration required to connect to a MySQL server type Probe struct { Key InstanceKey - User string - Password string MetricQuery string TabletHost string TabletPort int @@ -51,38 +44,12 @@ func NewProbe() *Probe { return config } -// DuplicateCredentials creates a new connection config with given key and with same credentials as this config -func (p *Probe) DuplicateCredentials(key InstanceKey) *Probe { - config := &Probe{ - Key: key, - User: p.User, - Password: p.Password, - } - return config -} - -// Duplicate duplicates this probe, including credentials -func (p *Probe) Duplicate() *Probe { - return p.DuplicateCredentials(p.Key) -} - // String returns a human readable string of this struct func (p *Probe) String() string { - return fmt.Sprintf("%s, user=%s", p.Key.DisplayString(), p.User) + return fmt.Sprintf("%s, tablet=%s:%d", p.Key.DisplayString(), p.TabletHost, p.TabletPort) } // Equals checks if this probe has same instance key as another func (p *Probe) Equals(other *Probe) bool { return p.Key.Equals(&other.Key) } - -// GetDBUri returns the DB URI for the mysql server indicated by this probe -func (p *Probe) GetDBUri(databaseName string) string { - hostname := p.Key.Hostname - var ip = net.ParseIP(hostname) - if (ip != nil) && (ip.To4() == nil) { - // Wrap IPv6 literals in square brackets - hostname = fmt.Sprintf("[%s]", hostname) - } - return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=true&charset=utf8mb4,utf8,latin1&timeout=%dms", p.User, p.Password, hostname, p.Key.Port, databaseName, timeoutMillis) -} diff --git a/go/vt/vttablet/tabletserver/throttle/mysql/probe_test.go b/go/vt/vttablet/tabletserver/throttle/mysql/probe_test.go index 8baa60529de..cb63441d419 100644 --- a/go/vt/vttablet/tabletserver/throttle/mysql/probe_test.go +++ b/go/vt/vttablet/tabletserver/throttle/mysql/probe_test.go @@ -16,32 +16,4 @@ func TestNewProbe(t *testing.T) { c := NewProbe() assert.Equal(t, "", c.Key.Hostname) assert.Equal(t, 0, c.Key.Port) - assert.Equal(t, "", c.User) - assert.Equal(t, "", c.Password) -} - -func TestDuplicateCredentials(t *testing.T) { - c := NewProbe() - c.Key = InstanceKey{Hostname: "myhost", Port: 3306} - c.User = "gromit" - c.Password = "penguin" - - dup := c.DuplicateCredentials(InstanceKey{Hostname: "otherhost", Port: 3310}) - assert.Equal(t, "otherhost", dup.Key.Hostname) - assert.Equal(t, 3310, dup.Key.Port) - assert.Equal(t, "gromit", dup.User) - assert.Equal(t, "penguin", dup.Password) -} - -func TestDuplicate(t *testing.T) { - c := NewProbe() - c.Key = InstanceKey{Hostname: "myhost", Port: 3306} - c.User = "gromit" - c.Password = "penguin" - - dup := c.Duplicate() - assert.Equal(t, "myhost", dup.Key.Hostname) - assert.Equal(t, 3306, dup.Key.Port) - assert.Equal(t, "gromit", dup.User) - assert.Equal(t, "penguin", dup.Password) } diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go index b096bc5157d..9c7944ac12b 100644 --- a/go/vt/vttablet/tabletserver/throttle/throttler.go +++ b/go/vt/vttablet/tabletserver/throttle/throttler.go @@ -24,10 +24,8 @@ import ( "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/timer" - "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/log" topodatapb "vitess.io/vitess/go/vt/proto/topodata" - "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -57,8 +55,6 @@ const ( defaultThrottleTTLMinutes = 60 defaultThrottleRatio = 1.0 - maxPasswordLength = 32 - shardStoreName = "shard" selfStoreName = "self" ) @@ -71,16 +67,6 @@ var ( throttlerCheckAsCheckSelf = flag.Bool("throttle_check_as_check_self", false, "Should throttler/check return a throttler/check-self result (changes throttler behavior for writes)") ) var ( - throttlerUser = "vt_tablet_throttler" - throttlerGrant = fmt.Sprintf("'%s'@'%s'", throttlerUser, "%") - - sqlCreateThrottlerUser = []string{ - `CREATE USER IF NOT EXISTS %s IDENTIFIED BY '%s'`, - `ALTER USER %s IDENTIFIED BY '%s'`, - } - sqlGrantThrottlerUser = []string{ - `GRANT SELECT ON _vt.heartbeat TO %s`, - } replicationLagQuery = `select unix_timestamp(now(6))-max(ts/1000000000) as replication_lag from _vt.heartbeat` ) @@ -192,7 +178,7 @@ func NewThrottler(env tabletenv.Env, ts *topo.Server, tabletTypeFunc func() topo throttler.initThrottleTabletTypes() throttler.ThrottleApp("abusing-app", time.Now().Add(time.Hour*24*365*10), defaultThrottleRatio) throttler.check = NewThrottlerCheck(throttler) - throttler.initConfig("") + throttler.initConfig() throttler.check.SelfChecks(context.Background()) } return throttler @@ -224,7 +210,7 @@ func (throttler *Throttler) InitDBConfig(keyspace, shard string) { } // initThrottler initializes config -func (throttler *Throttler) initConfig(password string) { +func (throttler *Throttler) initConfig() { log.Infof("Throttler: initializing config") config.Instance = &config.ConfigurationSettings{ Stores: config.StoresSettings{ @@ -243,20 +229,14 @@ func (throttler *Throttler) initConfig(password string) { throttler.metricsQueryType = mysql.GetMetricsQueryType(throttler.metricsQuery) config.Instance.Stores.MySQL.Clusters[selfStoreName] = &config.MySQLClusterConfigurationSettings{ - User: "", // running on local tablet server, will use vttablet DBA user - Password: "", // running on local tablet server, will use vttablet DBA user MetricQuery: throttler.metricsQuery, ThrottleThreshold: throttler.MetricsThreshold.Get(), IgnoreHostsCount: 0, } - if password != "" { - config.Instance.Stores.MySQL.Clusters[shardStoreName] = &config.MySQLClusterConfigurationSettings{ - User: throttlerUser, - Password: password, - MetricQuery: throttler.metricsQuery, - ThrottleThreshold: throttler.MetricsThreshold.Get(), - IgnoreHostsCount: 0, - } + config.Instance.Stores.MySQL.Clusters[shardStoreName] = &config.MySQLClusterConfigurationSettings{ + MetricQuery: throttler.metricsQuery, + ThrottleThreshold: throttler.MetricsThreshold.Get(), + IgnoreHostsCount: 0, } } @@ -298,63 +278,6 @@ func (throttler *Throttler) Close() { atomic.StoreInt64(&throttler.isOpen, 0) } -// createThrottlerUser creates or updates the throttler account and assigns it a random password -func (throttler *Throttler) createThrottlerUser(ctx context.Context) (password string, err error) { - if atomic.LoadInt64(&throttler.isOpen) == 0 { - return "", fmt.Errorf("createThrottlerUser: not open") - } - - conn, err := dbconnpool.NewDBConnection(ctx, throttler.env.Config().DB.DbaWithDB()) - if err != nil { - return password, err - } - defer conn.Close() - - // Double check this server is writable - tm, err := conn.ExecuteFetch("select @@global.read_only as read_only from dual", 1, true) - if err != nil { - return password, err - } - row := tm.Named().Row() - if row == nil { - return password, fmt.Errorf("unexpected result for MySQL variables: %+v", tm.Rows) - } - readOnly, err := row.ToBool("read_only") - if err != nil { - return password, err - } - if readOnly { - return password, fmt.Errorf("createThrottlerUser(): server is read_only") - } - - password = textutil.RandomHash()[0:maxPasswordLength] - { - // There seems to be a bug where CREATE USER hangs. If CREATE USER is preceded by - // any query that writes to the binary log, CREATE USER does not hang. - // The simplest such query is FLUSH STATUS. Other options are FLUSH PRIVILEGES or similar. - // The bug was found in MySQL 8.0.21, and not found in 5.7.30 - // - shlomi - simpleBinlogQuery := `FLUSH STATUS` - if _, err := conn.ExecuteFetch(simpleBinlogQuery, 0, false); err != nil { - return password, err - } - } - for _, query := range sqlCreateThrottlerUser { - parsed := sqlparser.BuildParsedQuery(query, throttlerGrant, password) - if _, err := conn.ExecuteFetch(parsed.Query, 0, false); err != nil { - return password, err - } - } - for _, query := range sqlGrantThrottlerUser { - parsed := sqlparser.BuildParsedQuery(query, throttlerGrant) - if _, err := conn.ExecuteFetch(parsed.Query, 0, false); err != nil { - return password, err - } - } - log.Infof("Throttler: user created/updated") - return password, nil -} - // readSelfMySQLThrottleMetric reads the mysql metric from thi very tablet's backend mysql. func (throttler *Throttler) readSelfMySQLThrottleMetric() *mysql.MySQLThrottleMetric { metric := &mysql.MySQLThrottleMetric{ @@ -429,7 +352,6 @@ func (throttler *Throttler) Operate(ctx context.Context) { mysqlAggregateTicker := addTicker(mysqlAggregateInterval) throttledAppsTicker := addTicker(throttledAppsSnapshotInterval) - shouldCreateThrottlerUser := false for { select { case <-leaderCheckTicker.C: @@ -446,9 +368,10 @@ func (throttler *Throttler) Operate(ctx context.Context) { } } + transitionedIntoLeader := false if shouldBeLeader > throttler.isLeader { log.Infof("Throttler: transition into leadership") - shouldCreateThrottlerUser = true + transitionedIntoLeader = true } if shouldBeLeader < throttler.isLeader { log.Infof("Throttler: transition out of leadership") @@ -456,16 +379,9 @@ func (throttler *Throttler) Operate(ctx context.Context) { atomic.StoreInt64(&throttler.isLeader, shouldBeLeader) - if shouldCreateThrottlerUser { - password, err := throttler.createThrottlerUser(ctx) - if err == nil { - throttler.initConfig(password) - shouldCreateThrottlerUser = false - // transitioned into leadership, let's speed up the next 'refresh' and 'collect' ticks - go mysqlRefreshTicker.TickNow() - } else { - log.Errorf("Error creating throttler account: %+v", err) - } + if transitionedIntoLeader { + // transitioned into leadership, let's speed up the next 'refresh' and 'collect' ticks + go mysqlRefreshTicker.TickNow() } }() } @@ -521,11 +437,6 @@ func (throttler *Throttler) Operate(ctx context.Context) { } func (throttler *Throttler) generateTabletHTTPProbeFunction(ctx context.Context, clusterName string, probe *mysql.Probe) (probeFunc func() *mysql.MySQLThrottleMetric) { - if probe.TabletHost == "" { - // nil function means no override; throttler will use default probe behavior, which is to open a direct - // connection to mysql and run a query - return nil - } return func() *mysql.MySQLThrottleMetric { // Hit a tablet's `check-self` via HTTP, and convert its CheckResult JSON output into a MySQLThrottleMetric mySQLThrottleMetric := mysql.NewMySQLThrottleMetric() @@ -575,13 +486,13 @@ func (throttler *Throttler) collectMySQLMetrics(ctx context.Context) error { } defer atomic.StoreInt64(&probe.QueryInProgress, 0) - // Apply an override to metrics read, if this is the special "self" cluster - // (where we incidentally know there's a single probe) - overrideGetMySQLThrottleMetricFunc := throttler.readSelfMySQLThrottleMetric - if clusterName != selfStoreName { - overrideGetMySQLThrottleMetricFunc = throttler.generateTabletHTTPProbeFunction(ctx, clusterName, probe) + var throttleMetricFunc func() *mysql.MySQLThrottleMetric + if clusterName == selfStoreName { + throttleMetricFunc = throttler.readSelfMySQLThrottleMetric + } else { + throttleMetricFunc = throttler.generateTabletHTTPProbeFunction(ctx, clusterName, probe) } - throttleMetrics := mysql.ReadThrottleMetric(probe, clusterName, overrideGetMySQLThrottleMetricFunc) + throttleMetrics := mysql.ReadThrottleMetric(probe, clusterName, throttleMetricFunc) throttler.mysqlThrottleMetricChan <- throttleMetrics }() } @@ -607,8 +518,6 @@ func (throttler *Throttler) refreshMySQLInventory(ctx context.Context) error { probe := &mysql.Probe{ Key: *key, - User: clusterSettings.User, - Password: clusterSettings.Password, TabletHost: tabletHost, TabletPort: tabletPort, MetricQuery: clusterSettings.MetricQuery,