mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-08 03:00:27 +08:00
优化指标统计性能
This commit is contained in:
@@ -26,9 +26,9 @@ func init() {
|
|||||||
type Manager struct {
|
type Manager struct {
|
||||||
isQuiting bool
|
isQuiting bool
|
||||||
|
|
||||||
tasks map[int64]*Task // itemId => *Task
|
taskMap map[int64]*Task // itemId => *Task
|
||||||
categoryTasks map[string][]*Task // category => []*Task
|
categoryTaskMap map[string][]*Task // category => []*Task
|
||||||
locker sync.RWMutex
|
locker sync.RWMutex
|
||||||
|
|
||||||
hasHTTPMetrics bool
|
hasHTTPMetrics bool
|
||||||
hasTCPMetrics bool
|
hasTCPMetrics bool
|
||||||
@@ -37,8 +37,8 @@ type Manager struct {
|
|||||||
|
|
||||||
func NewManager() *Manager {
|
func NewManager() *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
tasks: map[int64]*Task{},
|
taskMap: map[int64]*Task{},
|
||||||
categoryTasks: map[string][]*Task{},
|
categoryTaskMap: map[string][]*Task{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func (this *Manager) Update(items []*serverconfigs.MetricItemConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 停用以前的 或 修改现在的
|
// 停用以前的 或 修改现在的
|
||||||
for itemId, task := range this.tasks {
|
for itemId, task := range this.taskMap {
|
||||||
newItem, ok := newMap[itemId]
|
newItem, ok := newMap[itemId]
|
||||||
if !ok || !newItem.IsOn { // 停用以前的
|
if !ok || !newItem.IsOn { // 停用以前的
|
||||||
remotelogs.Println("METRIC_MANAGER", "stop task '"+strconv.FormatInt(itemId, 10)+"'")
|
remotelogs.Println("METRIC_MANAGER", "stop task '"+strconv.FormatInt(itemId, 10)+"'")
|
||||||
@@ -64,7 +64,7 @@ func (this *Manager) Update(items []*serverconfigs.MetricItemConfig) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("METRIC_MANAGER", "stop task '"+strconv.FormatInt(itemId, 10)+"' failed: "+err.Error())
|
remotelogs.Error("METRIC_MANAGER", "stop task '"+strconv.FormatInt(itemId, 10)+"' failed: "+err.Error())
|
||||||
}
|
}
|
||||||
delete(this.tasks, itemId)
|
delete(this.taskMap, itemId)
|
||||||
} else { // 更新已存在的
|
} else { // 更新已存在的
|
||||||
if newItem.Version != task.item.Version {
|
if newItem.Version != task.item.Version {
|
||||||
remotelogs.Println("METRIC_MANAGER", "update task '"+strconv.FormatInt(itemId, 10)+"'")
|
remotelogs.Println("METRIC_MANAGER", "update task '"+strconv.FormatInt(itemId, 10)+"'")
|
||||||
@@ -78,7 +78,7 @@ func (this *Manager) Update(items []*serverconfigs.MetricItemConfig) {
|
|||||||
if !newItem.IsOn {
|
if !newItem.IsOn {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, ok := this.tasks[newItem.Id]
|
_, ok := this.taskMap[newItem.Id]
|
||||||
if !ok {
|
if !ok {
|
||||||
remotelogs.Println("METRIC_MANAGER", "start task '"+strconv.FormatInt(newItem.Id, 10)+"'")
|
remotelogs.Println("METRIC_MANAGER", "start task '"+strconv.FormatInt(newItem.Id, 10)+"'")
|
||||||
task := NewTask(newItem)
|
task := NewTask(newItem)
|
||||||
@@ -92,7 +92,7 @@ func (this *Manager) Update(items []*serverconfigs.MetricItemConfig) {
|
|||||||
remotelogs.Error("METRIC_MANAGER", "start task failed: "+err.Error())
|
remotelogs.Error("METRIC_MANAGER", "start task failed: "+err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
this.tasks[newItem.Id] = task
|
this.taskMap[newItem.Id] = task
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,11 +100,11 @@ func (this *Manager) Update(items []*serverconfigs.MetricItemConfig) {
|
|||||||
this.hasHTTPMetrics = false
|
this.hasHTTPMetrics = false
|
||||||
this.hasTCPMetrics = false
|
this.hasTCPMetrics = false
|
||||||
this.hasUDPMetrics = false
|
this.hasUDPMetrics = false
|
||||||
this.categoryTasks = map[string][]*Task{}
|
this.categoryTaskMap = map[string][]*Task{}
|
||||||
for _, task := range this.tasks {
|
for _, task := range this.taskMap {
|
||||||
tasks := this.categoryTasks[task.item.Category]
|
var tasks = this.categoryTaskMap[task.item.Category]
|
||||||
tasks = append(tasks, task)
|
tasks = append(tasks, task)
|
||||||
this.categoryTasks[task.item.Category] = tasks
|
this.categoryTaskMap[task.item.Category] = tasks
|
||||||
|
|
||||||
switch task.item.Category {
|
switch task.item.Category {
|
||||||
case serverconfigs.MetricItemCategoryHTTP:
|
case serverconfigs.MetricItemCategoryHTTP:
|
||||||
@@ -124,10 +124,12 @@ func (this *Manager) Add(obj MetricInterface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.locker.RLock()
|
this.locker.RLock()
|
||||||
for _, task := range this.categoryTasks[obj.MetricCategory()] {
|
var tasks = this.categoryTaskMap[obj.MetricCategory()]
|
||||||
|
this.locker.RUnlock()
|
||||||
|
|
||||||
|
for _, task := range tasks {
|
||||||
task.Add(obj)
|
task.Add(obj)
|
||||||
}
|
}
|
||||||
this.locker.RUnlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Manager) HasHTTPMetrics() bool {
|
func (this *Manager) HasHTTPMetrics() bool {
|
||||||
@@ -149,9 +151,9 @@ func (this *Manager) Quit() {
|
|||||||
remotelogs.Println("METRIC_MANAGER", "quit")
|
remotelogs.Println("METRIC_MANAGER", "quit")
|
||||||
|
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
for _, task := range this.tasks {
|
for _, task := range this.taskMap {
|
||||||
_ = task.Stop()
|
_ = task.Stop()
|
||||||
}
|
}
|
||||||
this.tasks = map[int64]*Task{}
|
this.taskMap = map[int64]*Task{}
|
||||||
this.locker.Unlock()
|
this.locker.Unlock()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ func TestNewManager(t *testing.T) {
|
|||||||
var manager = NewManager()
|
var manager = NewManager()
|
||||||
{
|
{
|
||||||
manager.Update([]*serverconfigs.MetricItemConfig{})
|
manager.Update([]*serverconfigs.MetricItemConfig{})
|
||||||
for _, task := range manager.tasks {
|
for _, task := range manager.taskMap {
|
||||||
t.Log(task.item.Id)
|
t.Log(task.item.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func TestNewManager(t *testing.T) {
|
|||||||
Id: 3,
|
Id: 3,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
for _, task := range manager.tasks {
|
for _, task := range manager.taskMap {
|
||||||
t.Log("task:", task.item.Id)
|
t.Log("task:", task.item.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ func TestNewManager(t *testing.T) {
|
|||||||
Id: 2,
|
Id: 2,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
for _, task := range manager.tasks {
|
for _, task := range manager.taskMap {
|
||||||
t.Log("task:", task.item.Id)
|
t.Log("task:", task.item.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func TestNewManager(t *testing.T) {
|
|||||||
Version: 1,
|
Version: 1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
for _, task := range manager.tasks {
|
for _, task := range manager.taskMap {
|
||||||
t.Log("task:", task.item.Id)
|
t.Log("task:", task.item.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ type Stat struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SumStat(serverId int64, keys []string, time string, version int32, itemId int64) string {
|
func SumStat(serverId int64, keys []string, time string, version int32, itemId int64) string {
|
||||||
keysData := strings.Join(keys, "$EDGE$")
|
var keysData = strings.Join(keys, "$EDGE$")
|
||||||
return strconv.FormatUint(fnv.HashString(strconv.FormatInt(serverId, 10)+"@"+keysData+"@"+time+"@"+strconv.Itoa(int(version))+"@"+strconv.FormatInt(itemId, 10)), 10)
|
return strconv.FormatUint(fnv.HashString(strconv.FormatInt(serverId, 10)+"@"+keysData+"@"+time+"@"+strconv.Itoa(int(version))+"@"+strconv.FormatInt(itemId, 10)), 10)
|
||||||
}
|
}
|
||||||
|
|||||||
20
internal/metrics/sum_test.go
Normal file
20
internal/metrics/sum_test.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package metrics_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/metrics"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkSumStat(b *testing.B) {
|
||||||
|
runtime.GOMAXPROCS(2)
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
metrics.SumStat(1, []string{"1.2.3.4"}, timeutil.Format("Ymd"), 1, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ type Task struct {
|
|||||||
serverIdMapLocker sync.Mutex
|
serverIdMapLocker sync.Mutex
|
||||||
|
|
||||||
statsMap map[string]*Stat // 待写入队列,hash => *Stat
|
statsMap map[string]*Stat // 待写入队列,hash => *Stat
|
||||||
statsLocker sync.Mutex
|
statsLocker sync.RWMutex
|
||||||
statsTicker *utils.Ticker
|
statsTicker *utils.Ticker
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ func (this *Task) Add(obj MetricInterface) {
|
|||||||
|
|
||||||
var keys = []string{}
|
var keys = []string{}
|
||||||
for _, key := range this.item.Keys {
|
for _, key := range this.item.Keys {
|
||||||
k := obj.MetricKey(key)
|
var k = obj.MetricKey(key)
|
||||||
|
|
||||||
// 忽略499状态
|
// 忽略499状态
|
||||||
if key == "${status}" && k == "499" {
|
if key == "${status}" && k == "499" {
|
||||||
@@ -253,14 +254,19 @@ func (this *Task) Add(obj MetricInterface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hash = SumStat(obj.MetricServerId(), keys, this.item.CurrentTime(), this.item.Version, this.item.Id)
|
var hash = SumStat(obj.MetricServerId(), keys, this.item.CurrentTime(), this.item.Version, this.item.Id)
|
||||||
this.statsLocker.Lock()
|
var countItems int
|
||||||
|
this.statsLocker.RLock()
|
||||||
oldStat, ok := this.statsMap[hash]
|
oldStat, ok := this.statsMap[hash]
|
||||||
|
if !ok {
|
||||||
|
countItems = len(this.statsMap)
|
||||||
|
}
|
||||||
|
this.statsLocker.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
oldStat.Value += v
|
atomic.AddInt64(&oldStat.Value, 1)
|
||||||
oldStat.Hash = hash
|
|
||||||
} else {
|
} else {
|
||||||
// 防止过载
|
// 防止过载
|
||||||
if len(this.statsMap) < MaxQueueSize {
|
if countItems < MaxQueueSize {
|
||||||
|
this.statsLocker.Lock()
|
||||||
this.statsMap[hash] = &Stat{
|
this.statsMap[hash] = &Stat{
|
||||||
ServerId: obj.MetricServerId(),
|
ServerId: obj.MetricServerId(),
|
||||||
Keys: keys,
|
Keys: keys,
|
||||||
@@ -268,9 +274,9 @@ func (this *Task) Add(obj MetricInterface) {
|
|||||||
Time: this.item.CurrentTime(),
|
Time: this.item.CurrentTime(),
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
}
|
}
|
||||||
|
this.statsLocker.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.statsLocker.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop 停止任务
|
// Stop 停止任务
|
||||||
|
|||||||
@@ -4,11 +4,15 @@ package metrics_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/metrics"
|
"github.com/TeaOSLab/EdgeNode/internal/metrics"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -213,3 +217,65 @@ func TestTask_Upload(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("ok")
|
t.Log("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var testingTask *metrics.Task
|
||||||
|
var testingTaskInitOnce = &sync.Once{}
|
||||||
|
|
||||||
|
func initTestingTask() {
|
||||||
|
testingTask = metrics.NewTask(&serverconfigs.MetricItemConfig{
|
||||||
|
Id: 1,
|
||||||
|
IsOn: false,
|
||||||
|
Category: "tcp",
|
||||||
|
Period: 1,
|
||||||
|
PeriodUnit: serverconfigs.MetricItemPeriodUnitDay,
|
||||||
|
Keys: []string{"${remoteAddr}"},
|
||||||
|
Value: "${countRequest}",
|
||||||
|
})
|
||||||
|
|
||||||
|
err := testingTask.Init()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = testingTask.Start()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTask_Add(b *testing.B) {
|
||||||
|
runtime.GOMAXPROCS(1)
|
||||||
|
|
||||||
|
testingTaskInitOnce.Do(func() {
|
||||||
|
initTestingTask()
|
||||||
|
})
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
testingTask.Add(&taskRequest{})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type taskRequest struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *taskRequest) MetricKey(key string) string {
|
||||||
|
return configutils.ParseVariables(key, func(varName string) (value string) {
|
||||||
|
return "1.2.3.4"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *taskRequest) MetricValue(value string) (result int64, ok bool) {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *taskRequest) MetricServerId() int64 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *taskRequest) MetricCategory() string {
|
||||||
|
return "http"
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,3 +14,11 @@ func TestHash(t *testing.T) {
|
|||||||
t.Log(key + " => " + types.String(h))
|
t.Log(key + " => " + types.String(h))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashString(b *testing.B) {
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
fnv.HashString("abcdefh")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user