Files
EdgeNode/internal/stats/traffic_stat_manager.go

304 lines
8.3 KiB
Go
Raw Normal View History

2021-01-25 16:40:31 +08:00
package stats
import (
2021-01-25 16:40:31 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
2021-01-25 16:40:31 +08:00
"github.com/TeaOSLab/EdgeNode/internal/events"
"github.com/TeaOSLab/EdgeNode/internal/monitor"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/rpc"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
2024-05-11 09:23:54 +08:00
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/maps"
2021-07-05 11:36:50 +08:00
"github.com/iwind/TeaGo/types"
"sort"
"strconv"
2021-07-05 11:36:50 +08:00
"strings"
"sync"
"time"
)
var SharedTrafficStatManager = NewTrafficStatManager()
2021-06-08 11:24:41 +08:00
type TrafficItem struct {
UserId int64
2021-11-10 14:39:02 +08:00
Bytes int64
CachedBytes int64
CountRequests int64
CountCachedRequests int64
CountAttackRequests int64
AttackBytes int64
2021-11-10 21:51:56 +08:00
PlanId int64
2021-11-10 14:39:02 +08:00
CheckingTrafficLimit bool
2021-06-08 11:24:41 +08:00
}
func (this *TrafficItem) Add(anotherItem *TrafficItem) {
this.Bytes += anotherItem.Bytes
this.CachedBytes += anotherItem.CachedBytes
this.CountRequests += anotherItem.CountRequests
this.CountCachedRequests += anotherItem.CountCachedRequests
this.CountAttackRequests += anotherItem.CountAttackRequests
this.AttackBytes += anotherItem.AttackBytes
}
2021-04-29 16:48:47 +08:00
// TrafficStatManager 区域流量统计
type TrafficStatManager struct {
itemMap map[string]*TrafficItem // [timestamp serverId] => *TrafficItem
domainsMap map[int64]map[string]*TrafficItem // serverIde => { timestamp @ domain => *TrafficItem }
pbItems []*pb.ServerDailyStat
pbDomainItems []*pb.UploadServerDailyStatsRequest_DomainStat
locker sync.Mutex
totalRequests int64
}
2021-04-29 16:48:47 +08:00
// NewTrafficStatManager 获取新对象
func NewTrafficStatManager() *TrafficStatManager {
var manager = &TrafficStatManager{
2021-07-05 11:36:50 +08:00
itemMap: map[string]*TrafficItem{},
domainsMap: map[int64]map[string]*TrafficItem{},
}
return manager
}
2021-04-29 16:48:47 +08:00
// Start 启动自动任务
func (this *TrafficStatManager) Start() {
// 上传请求总数
2022-01-12 20:31:04 +08:00
var monitorTicker = time.NewTicker(1 * time.Minute)
events.OnKey(events.EventQuit, this, func() {
monitorTicker.Stop()
})
goman.New(func() {
2022-01-12 20:31:04 +08:00
for range monitorTicker.C {
if this.totalRequests > 0 {
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemRequests, maps.Map{"total": this.totalRequests})
this.totalRequests = 0
}
2022-01-12 20:31:04 +08:00
}
})
// 上传统计数据
var duration = 5 * time.Minute
if Tea.IsTesting() {
// 测试环境缩短上传时间,方便我们调试
duration = 30 * time.Second
}
2022-01-12 20:31:04 +08:00
var ticker = time.NewTicker(duration)
events.OnKey(events.EventQuit, this, func() {
2021-01-25 16:40:31 +08:00
remotelogs.Println("TRAFFIC_STAT_MANAGER", "quit")
ticker.Stop()
})
2022-05-23 16:15:02 +08:00
remotelogs.Println("TRAFFIC_STAT_MANAGER", "start ...")
for range ticker.C {
err := this.Upload()
if err != nil {
2021-11-10 21:51:56 +08:00
if !rpc.IsConnError(err) {
remotelogs.Error("TRAFFIC_STAT_MANAGER", "upload stats failed: "+err.Error())
} else {
remotelogs.Warn("TRAFFIC_STAT_MANAGER", "upload stats failed: "+err.Error())
}
}
}
}
2021-04-29 16:48:47 +08:00
// Add 添加流量
2023-12-20 11:43:00 +08:00
func (this *TrafficStatManager) Add(userId int64, serverId int64, domain string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64, countAttacks int64, attackBytes int64, countWebsocketConnections int64, checkingTrafficLimit bool, planId int64) {
2022-07-05 20:37:00 +08:00
if serverId == 0 {
return
}
// 添加到带宽
2023-12-20 11:43:00 +08:00
SharedBandwidthStatManager.AddTraffic(serverId, cachedBytes, countRequests, countCachedRequests, countAttacks, attackBytes, countWebsocketConnections)
if bytes == 0 && countRequests == 0 {
return
}
this.totalRequests++
var timestamp = fasttime.Now().UnixFloor(300)
2022-08-07 11:12:29 +08:00
var key = strconv.FormatInt(timestamp, 10) + strconv.FormatInt(serverId, 10)
this.locker.Lock()
2021-07-05 11:36:50 +08:00
// 总的流量
2021-06-08 11:24:41 +08:00
item, ok := this.itemMap[key]
if !ok {
item = &TrafficItem{
UserId: userId,
}
2021-06-08 11:24:41 +08:00
this.itemMap[key] = item
}
item.Bytes += bytes
item.CachedBytes += cachedBytes
item.CountRequests += countRequests
item.CountCachedRequests += countCachedRequests
2021-07-13 11:04:38 +08:00
item.CountAttackRequests += countAttacks
item.AttackBytes += attackBytes
2021-11-10 14:39:02 +08:00
item.CheckingTrafficLimit = checkingTrafficLimit
2021-11-10 21:51:56 +08:00
item.PlanId = planId
2021-07-05 11:36:50 +08:00
// 单个域名流量
2023-11-13 17:07:55 +08:00
if len(domain) < 128 {
var domainKey = types.String(timestamp) + "@" + domain
serverDomainMap, ok := this.domainsMap[serverId]
if !ok {
serverDomainMap = map[string]*TrafficItem{}
this.domainsMap[serverId] = serverDomainMap
}
domainItem, ok := serverDomainMap[domainKey]
if !ok {
domainItem = &TrafficItem{}
serverDomainMap[domainKey] = domainItem
}
domainItem.Bytes += bytes
domainItem.CachedBytes += cachedBytes
domainItem.CountRequests += countRequests
domainItem.CountCachedRequests += countCachedRequests
domainItem.CountAttackRequests += countAttacks
domainItem.AttackBytes += attackBytes
2021-07-05 11:36:50 +08:00
}
this.locker.Unlock()
}
2021-04-29 16:48:47 +08:00
// Upload 上传流量
func (this *TrafficStatManager) Upload() error {
var regionId int64
nodeConfig, _ := nodeconfigs.SharedNodeConfig()
if nodeConfig != nil {
regionId = nodeConfig.RegionId
}
client, err := rpc.SharedRPC()
if err != nil {
return err
}
this.locker.Lock()
2022-07-05 20:37:00 +08:00
var itemMap = this.itemMap
var domainMap = this.domainsMap
// reset
2021-06-08 11:24:41 +08:00
this.itemMap = map[string]*TrafficItem{}
this.domainsMap = map[int64]map[string]*TrafficItem{}
this.locker.Unlock()
2021-07-05 11:36:50 +08:00
// 服务统计
var pbServerStats = []*pb.ServerDailyStat{}
for key, item := range itemMap {
timestamp, err := strconv.ParseInt(key[:10], 10, 64)
if err != nil {
return err
}
serverId, err := strconv.ParseInt(key[10:], 10, 64)
if err != nil {
return err
}
2021-07-05 11:36:50 +08:00
pbServerStats = append(pbServerStats, &pb.ServerDailyStat{
UserId: item.UserId,
2021-11-10 14:39:02 +08:00
ServerId: serverId,
NodeRegionId: regionId,
2021-11-10 14:39:02 +08:00
Bytes: item.Bytes,
CachedBytes: item.CachedBytes,
CountRequests: item.CountRequests,
CountCachedRequests: item.CountCachedRequests,
CountAttackRequests: item.CountAttackRequests,
AttackBytes: item.AttackBytes,
CheckTrafficLimiting: item.CheckingTrafficLimit,
2021-11-10 21:51:56 +08:00
PlanId: item.PlanId,
2021-11-10 14:39:02 +08:00
CreatedAt: timestamp,
})
}
2021-07-05 11:36:50 +08:00
// 域名统计
const maxDomainsPerServer = 20
2021-07-05 11:36:50 +08:00
var pbDomainStats = []*pb.UploadServerDailyStatsRequest_DomainStat{}
for serverId, serverDomainMap := range domainMap {
// 如果超过单个服务最大值则只取前N个
var shouldTrim = len(serverDomainMap) > maxDomainsPerServer
var tempItems []*pb.UploadServerDailyStatsRequest_DomainStat
for key, item := range serverDomainMap {
var pieces = strings.SplitN(key, "@", 2)
if len(pieces) != 2 {
continue
}
2023-07-30 14:49:16 +08:00
// 修正数据
if item.CachedBytes > item.Bytes || item.CountCachedRequests == item.CountRequests {
item.CachedBytes = item.Bytes
}
var pbItem = &pb.UploadServerDailyStatsRequest_DomainStat{
ServerId: serverId,
Domain: pieces[1],
Bytes: item.Bytes,
CachedBytes: item.CachedBytes,
CountRequests: item.CountRequests,
CountCachedRequests: item.CountCachedRequests,
CountAttackRequests: item.CountAttackRequests,
AttackBytes: item.AttackBytes,
CreatedAt: types.Int64(pieces[0]),
}
if !shouldTrim {
pbDomainStats = append(pbDomainStats, pbItem)
} else {
tempItems = append(tempItems, pbItem)
}
}
if shouldTrim {
sort.Slice(tempItems, func(i, j int) bool {
return tempItems[i].CountRequests > tempItems[j].CountRequests
})
pbDomainStats = append(pbDomainStats, tempItems[:maxDomainsPerServer]...)
2021-07-05 11:36:50 +08:00
}
}
// 历史未提交记录
if len(this.pbItems) > 0 || len(this.pbDomainItems) > 0 {
var expiredAt = time.Now().Unix() - 1200 // 只保留20分钟
for _, item := range this.pbItems {
if item.CreatedAt > expiredAt {
pbServerStats = append(pbServerStats, item)
}
}
this.pbItems = nil
for _, item := range this.pbDomainItems {
if item.CreatedAt > expiredAt {
pbDomainStats = append(pbDomainStats, item)
}
}
this.pbDomainItems = nil
}
if len(pbServerStats) == 0 && len(pbDomainStats) == 0 {
return nil
}
2022-08-24 20:04:46 +08:00
_, err = client.ServerDailyStatRPC.UploadServerDailyStats(client.Context(), &pb.UploadServerDailyStatsRequest{
2021-07-05 11:36:50 +08:00
Stats: pbServerStats,
DomainStats: pbDomainStats,
})
if err != nil {
// 加回历史记录
this.pbItems = pbServerStats
this.pbDomainItems = pbDomainStats
return err
}
return nil
}