From 10caef09a743179b3f976e83fa26c3d532f2ee0d Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 18 Dec 2023 16:37:54 +0800 Subject: [PATCH] *: provide a option to wait for init stats to finish before providing service during startup (#43381) (#43445) ref pingcap/tidb#42160, close pingcap/tidb#43385 --- config/config.go | 6 ++++++ config/config.toml.example | 3 +++ config/config_test.go | 2 ++ domain/domain.go | 23 ++++++++++++++++------- statistics/handle/handle.go | 3 +++ tidb-server/main.go | 3 +++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 1ef50edb01fd5..00217028a6acc 100644 --- a/config/config.go +++ b/config/config.go @@ -683,6 +683,11 @@ type Performance struct { MemoryUsageAlarmRatio float64 `toml:"memory-usage-alarm-ratio" json:"memory-usage-alarm-ratio"` EnableLoadFMSketch bool `toml:"enable-load-fmsketch" json:"enable-load-fmsketch"` + + // If ForceInitStats is true, when tidb starts up, it doesn't provide service until init stats is finished. + // If ForceInitStats is false, tidb can provide service before init stats is finished. Note that during the period + // of init stats the optimizer may make bad decisions due to pseudo stats. + ForceInitStats bool `toml:"force-init-stats" json:"force-init-stats"` } // PlanCache is the PlanCache section of the config. @@ -941,6 +946,7 @@ var defaultConf = Config{ EnableStatsCacheMemQuota: false, RunAutoAnalyze: true, EnableLoadFMSketch: false, + ForceInitStats: false, }, ProxyProtocol: ProxyProtocol{ Networks: "", diff --git a/config/config.toml.example b/config/config.toml.example index 2d3b1acd0b29c..f9ae48fcf6fc3 100644 --- a/config/config.toml.example +++ b/config/config.toml.example @@ -255,6 +255,9 @@ max-txn-ttl = 3600000 # If you find the CPU used by GC is too high or GC is too frequent and impact your business you can increase this value. gogc = 100 +# Whether to wait for init stats to finish before providing service during startup +force-init-stats = false + [proxy-protocol] # PROXY protocol acceptable client networks. # Empty string means disable PROXY protocol, * means all networks. diff --git a/config/config_test.go b/config/config_test.go index f4909ee15c23f..b4b439744045e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -736,6 +736,7 @@ tidb-max-reuse-column = 20 txn-total-size-limit=2000 tcp-no-delay = false enable-load-fmsketch = true +force-init-stats = true [tikv-client] commit-timeout="41s" max-batch-size=128 @@ -827,6 +828,7 @@ max_connections = 200 require.Equal(t, 10240, conf.Status.GRPCInitialWindowSize) require.Equal(t, 40960, conf.Status.GRPCMaxSendMsgSize) require.True(t, conf.Performance.EnableLoadFMSketch) + require.True(t, conf.Performance.ForceInitStats) err = f.Truncate(0) require.NoError(t, err) diff --git a/domain/domain.go b/domain/domain.go index 874c74c16146b..055c9e6bc8601 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -1927,6 +1927,20 @@ func (do *Domain) newOwnerManager(prompt, ownerKey string) owner.Manager { return statsOwner } +func (do *Domain) initStats() { + statsHandle := do.StatsHandle() + defer func() { + close(statsHandle.InitStatsDone) + }() + t := time.Now() + err := statsHandle.InitStats(do.InfoSchema()) + if err != nil { + logutil.BgLogger().Error("init stats info failed", zap.Duration("take time", time.Since(t)), zap.Error(err)) + } else { + logutil.BgLogger().Info("init stats info time", zap.Duration("take time", time.Since(t))) + } +} + func (do *Domain) loadStatsWorker() { defer util.Recover(metrics.LabelDomain, "loadStatsWorker", nil, false) lease := do.statsLease @@ -1938,14 +1952,9 @@ func (do *Domain) loadStatsWorker() { loadTicker.Stop() logutil.BgLogger().Info("loadStatsWorker exited.") }() + do.initStats() statsHandle := do.StatsHandle() - t := time.Now() - err := statsHandle.InitStats(do.InfoSchema()) - if err != nil { - logutil.BgLogger().Error("init stats info failed", zap.Duration("take time", time.Since(t)), zap.Error(err)) - } else { - logutil.BgLogger().Info("init stats info time", zap.Duration("take time", time.Since(t))) - } + var err error for { select { case <-loadTicker.C: diff --git a/statistics/handle/handle.go b/statistics/handle/handle.go index 22da2184ace78..ff2a56935b266 100644 --- a/statistics/handle/handle.go +++ b/statistics/handle/handle.go @@ -128,6 +128,8 @@ type Handle struct { serverIDGetter func() uint64 // tableLocked used to store locked tables tableLocked []int64 + + InitStatsDone chan struct{} } // GetTableLockedAndClearForTest for unit test only @@ -476,6 +478,7 @@ func NewHandle(ctx, initStatsCtx sessionctx.Context, lease time.Duration, pool s pool: pool, sysProcTracker: tracker, serverIDGetter: serverIDGetter, + InitStatsDone: make(chan struct{}), } handle.initStatsCtx = initStatsCtx handle.lease.Store(lease) diff --git a/tidb-server/main.go b/tidb-server/main.go index 80bcf40392b6c..4ff93417a107a 100644 --- a/tidb-server/main.go +++ b/tidb-server/main.go @@ -232,6 +232,9 @@ func main() { close(exited) }) topsql.SetupTopSQL() + if config.GetGlobalConfig().Performance.ForceInitStats { + <-dom.StatsHandle().InitStatsDone + } terror.MustNil(svr.Run()) <-exited syncLog()