mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-11-30 10:59:32 +08:00
Add GC Tuner (#20321)
Signed-off-by: xiaofan-luan <xiaofan.luan@zilliz.com> Signed-off-by: xiaofan-luan <xiaofan.luan@zilliz.com>
This commit is contained in:
parent
31c22a9672
commit
ffd52f0d08
@ -34,6 +34,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@ -52,6 +53,7 @@ import (
|
||||
"github.com/milvus-io/milvus/internal/types"
|
||||
"github.com/milvus-io/milvus/internal/util/concurrency"
|
||||
"github.com/milvus-io/milvus/internal/util/dependency"
|
||||
"github.com/milvus-io/milvus/internal/util/gc"
|
||||
"github.com/milvus-io/milvus/internal/util/hardware"
|
||||
"github.com/milvus-io/milvus/internal/util/initcore"
|
||||
"github.com/milvus-io/milvus/internal/util/metricsinfo"
|
||||
@ -301,6 +303,16 @@ func (node *QueryNode) Init() error {
|
||||
|
||||
node.InitSegcore()
|
||||
|
||||
if Params.QueryNodeCfg.GCHelperEnabled {
|
||||
action := func(GOGC uint32) {
|
||||
debug.SetGCPercent(int(GOGC))
|
||||
}
|
||||
gc.NewTuner(Params.QueryNodeCfg.OverloadedMemoryThresholdPercentage, uint32(Params.QueryNodeCfg.MinimumGOGCConfig), uint32(Params.QueryNodeCfg.MaximumGOGCConfig), action)
|
||||
} else {
|
||||
action := func(uint32) {}
|
||||
gc.NewTuner(Params.QueryNodeCfg.OverloadedMemoryThresholdPercentage, uint32(Params.QueryNodeCfg.MinimumGOGCConfig), uint32(Params.QueryNodeCfg.MaximumGOGCConfig), action)
|
||||
}
|
||||
|
||||
log.Info("query node init successfully",
|
||||
zap.Int64("queryNodeID", paramtable.GetNodeID()),
|
||||
zap.String("Address", node.address),
|
||||
|
121
internal/util/gc/gc_tuner.go
Normal file
121
internal/util/gc/gc_tuner.go
Normal file
@ -0,0 +1,121 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/util/hardware"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var defaultGOGC int
|
||||
var previousGOGC uint32
|
||||
|
||||
var minGOGC uint32
|
||||
var maxGOGC uint32
|
||||
|
||||
var memoryThreshold uint64
|
||||
var action func(uint32)
|
||||
|
||||
type finalizer struct {
|
||||
ref *finalizerRef
|
||||
}
|
||||
|
||||
type finalizerRef struct {
|
||||
parent *finalizer
|
||||
}
|
||||
|
||||
// just a finializer to handle go gc
|
||||
func finalizerHandler(f *finalizerRef) {
|
||||
optimizeGOGC()
|
||||
runtime.SetFinalizer(f, finalizerHandler)
|
||||
}
|
||||
|
||||
func optimizeGOGC() {
|
||||
var m runtime.MemStats
|
||||
// This will trigger a STW so be careful
|
||||
runtime.ReadMemStats(&m)
|
||||
|
||||
heapuse := m.HeapInuse
|
||||
|
||||
totaluse := hardware.GetUsedMemoryCount()
|
||||
heapTarget := memoryThreshold - (totaluse - heapuse)
|
||||
|
||||
newGoGC := uint32(math.Floor(float64(heapTarget-heapuse) / float64(heapuse) * 100))
|
||||
if newGoGC < minGOGC {
|
||||
newGoGC = minGOGC
|
||||
} else if newGoGC > maxGOGC {
|
||||
newGoGC = maxGOGC
|
||||
}
|
||||
|
||||
action(newGoGC)
|
||||
|
||||
toMB := func(mem uint64) uint64 {
|
||||
return mem / 1024 / 1024
|
||||
}
|
||||
|
||||
log.Info("GC Tune done", zap.Uint32("previous GOGC", previousGOGC),
|
||||
zap.Uint64("heapuse ", toMB(heapuse)),
|
||||
zap.Uint64("total memory", toMB(totaluse)),
|
||||
zap.Uint64("next GC", toMB(m.NextGC)),
|
||||
zap.Uint32("new GOGC", newGoGC),
|
||||
)
|
||||
|
||||
previousGOGC = newGoGC
|
||||
}
|
||||
|
||||
func NewTuner(targetPercent float64, minimumGOGCConfig uint32, maximumGOGCConfig uint32, fn func(uint322 uint32)) *finalizer {
|
||||
// initiate GOGC parameter
|
||||
if envGOGC := os.Getenv("GOGC"); envGOGC != "" {
|
||||
n, err := strconv.Atoi(envGOGC)
|
||||
if err == nil {
|
||||
defaultGOGC = n
|
||||
}
|
||||
} else {
|
||||
// the default value of GOGC is 100 for now
|
||||
defaultGOGC = 100
|
||||
}
|
||||
action = fn
|
||||
minGOGC = minimumGOGCConfig
|
||||
maxGOGC = maximumGOGCConfig
|
||||
|
||||
previousGOGC = uint32(defaultGOGC)
|
||||
|
||||
totalMemory := hardware.GetMemoryCount()
|
||||
if totalMemory == 0 {
|
||||
log.Warn("Failed to get memory count, disable gc auto tune", zap.Int("Initial GoGC", defaultGOGC))
|
||||
// noop
|
||||
action = func(uint32) {}
|
||||
return nil
|
||||
}
|
||||
memoryThreshold = uint64(float64(totalMemory) * targetPercent)
|
||||
log.Info("GC Helper initialized.", zap.Uint32("Initial GoGC", previousGOGC),
|
||||
zap.Uint32("minimumGOGC", minGOGC),
|
||||
zap.Uint32("maximumGOGC", maxGOGC),
|
||||
zap.Uint64("memoryThreshold", memoryThreshold))
|
||||
f := &finalizer{}
|
||||
|
||||
f.ref = &finalizerRef{parent: f}
|
||||
runtime.SetFinalizer(f.ref, finalizerHandler)
|
||||
f.ref = nil
|
||||
return f
|
||||
}
|
@ -865,6 +865,10 @@ type queryNodeConfig struct {
|
||||
MaxGroupNQ int64
|
||||
TopKMergeRatio float64
|
||||
CPURatio float64
|
||||
|
||||
GCHelperEnabled bool
|
||||
MinimumGOGCConfig int
|
||||
MaximumGOGCConfig int
|
||||
}
|
||||
|
||||
func (p *queryNodeConfig) init(base *BaseTable) {
|
||||
@ -893,6 +897,10 @@ func (p *queryNodeConfig) init(base *BaseTable) {
|
||||
p.initEnableDisk()
|
||||
p.initDiskCapacity()
|
||||
p.initMaxDiskUsagePercentage()
|
||||
|
||||
p.initGCTunerEnbaled()
|
||||
p.initMaximumGOGC()
|
||||
p.initMinimumGOGC()
|
||||
}
|
||||
|
||||
// InitAlias initializes an alias for the QueryNode role.
|
||||
@ -1053,6 +1061,18 @@ func (p *queryNodeConfig) initDiskCapacity() {
|
||||
p.DiskCapacityLimit = diskSize * 1024 * 1024 * 1024
|
||||
}
|
||||
|
||||
func (p *queryNodeConfig) initGCTunerEnbaled() {
|
||||
p.GCHelperEnabled = p.Base.ParseBool("queryNode.gchelper.enabled", true)
|
||||
}
|
||||
|
||||
func (p *queryNodeConfig) initMinimumGOGC() {
|
||||
p.MinimumGOGCConfig = p.Base.ParseIntWithDefault("queryNode.gchelper.minimumGoGC", 30)
|
||||
}
|
||||
|
||||
func (p *queryNodeConfig) initMaximumGOGC() {
|
||||
p.MaximumGOGCConfig = p.Base.ParseIntWithDefault("queryNode.gchelper.maximumGoGC", 200)
|
||||
}
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
// --- datacoord ---
|
||||
type dataCoordConfig struct {
|
||||
|
Loading…
Reference in New Issue
Block a user