优化统计相关程序

This commit is contained in:
刘祥超
2023-03-12 12:19:25 +08:00
parent cc7cf5f8c5
commit 50f3ad641c

View File

@@ -20,6 +20,7 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
) )
@@ -46,7 +47,13 @@ type HTTPRequestStatManager struct {
dailyFirewallRuleGroupMap map[string]int64 // serverId@firewallRuleGroupId@action => count dailyFirewallRuleGroupMap map[string]int64 // serverId@firewallRuleGroupId@action => count
serverCityCountMap map[string]int16 // serverIdString => count cities
serverSystemCountMap map[string]int16 // serverIdString => count systems
serverBrowserCountMap map[string]int16 // serverIdString => count browsers
totalAttackRequests int64 totalAttackRequests int64
locker sync.Mutex
} }
// NewHTTPRequestStatManager 获取新对象 // NewHTTPRequestStatManager 获取新对象
@@ -60,6 +67,10 @@ func NewHTTPRequestStatManager() *HTTPRequestStatManager {
systemMap: map[string]int64{}, systemMap: map[string]int64{},
browserMap: map[string]int64{}, browserMap: map[string]int64{},
dailyFirewallRuleGroupMap: map[string]int64{}, dailyFirewallRuleGroupMap: map[string]int64{},
serverCityCountMap: map[string]int16{},
serverSystemCountMap: map[string]int16{},
serverBrowserCountMap: map[string]int16{},
} }
} }
@@ -79,7 +90,6 @@ func (this *HTTPRequestStatManager) Start() {
} }
}) })
var loopTicker = time.NewTicker(1 * time.Second)
var uploadTicker = time.NewTicker(30 * time.Minute) var uploadTicker = time.NewTicker(30 * time.Minute)
if Tea.IsTesting() { if Tea.IsTesting() {
uploadTicker = time.NewTicker(10 * time.Second) // 在测试环境下缩短Ticker时间以方便我们调试 uploadTicker = time.NewTicker(10 * time.Second) // 在测试环境下缩短Ticker时间以方便我们调试
@@ -87,20 +97,12 @@ func (this *HTTPRequestStatManager) Start() {
remotelogs.Println("HTTP_REQUEST_STAT_MANAGER", "start ...") remotelogs.Println("HTTP_REQUEST_STAT_MANAGER", "start ...")
events.OnKey(events.EventQuit, this, func() { events.OnKey(events.EventQuit, this, func() {
remotelogs.Println("HTTP_REQUEST_STAT_MANAGER", "quit") remotelogs.Println("HTTP_REQUEST_STAT_MANAGER", "quit")
loopTicker.Stop()
uploadTicker.Stop() uploadTicker.Stop()
}) })
for range loopTicker.C {
err := this.Loop() // 上传Ticker
if err != nil { goman.New(func() {
if rpc.IsConnError(err) { for range uploadTicker.C {
remotelogs.Warn("HTTP_REQUEST_STAT_MANAGER", err.Error())
} else {
remotelogs.Error("HTTP_REQUEST_STAT_MANAGER", err.Error())
}
}
select {
case <-uploadTicker.C:
var tr = trackers.Begin("UPLOAD_REQUEST_STATS") var tr = trackers.Begin("UPLOAD_REQUEST_STATS")
err := this.Upload() err := this.Upload()
tr.End() tr.End()
@@ -111,9 +113,20 @@ func (this *HTTPRequestStatManager) Start() {
remotelogs.Warn("HTTP_REQUEST_STAT_MANAGER", "upload failed: "+err.Error()) remotelogs.Warn("HTTP_REQUEST_STAT_MANAGER", "upload failed: "+err.Error())
} }
} }
default:
} }
})
// 分析Ticker
for {
err := this.Loop()
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Warn("HTTP_REQUEST_STAT_MANAGER", err.Error())
} else {
remotelogs.Error("HTTP_REQUEST_STAT_MANAGER", err.Error())
}
}
} }
} }
@@ -149,7 +162,7 @@ func (this *HTTPRequestStatManager) AddRemoteAddr(serverId int64, remoteAddr str
// AddUserAgent 添加UserAgent // AddUserAgent 添加UserAgent
func (this *HTTPRequestStatManager) AddUserAgent(serverId int64, userAgent string, ip string) { func (this *HTTPRequestStatManager) AddUserAgent(serverId int64, userAgent string, ip string) {
if len(userAgent) == 0 { if len(userAgent) == 0 || strings.ContainsRune(userAgent, '@') /** 非常重要,防止后面组合字符串时出现异常 **/ {
return return
} }
@@ -184,24 +197,29 @@ func (this *HTTPRequestStatManager) AddFirewallRuleGroupId(serverId int64, firew
// Loop 单个循环 // Loop 单个循环
func (this *HTTPRequestStatManager) Loop() error { func (this *HTTPRequestStatManager) Loop() error {
var timeout = time.NewTimer(10 * time.Minute) // 执行的最大时间
Loop:
for {
select { select {
case ipString := <-this.ipChan: case ipString := <-this.ipChan:
// serverId@ip@bytes@isAttack // serverId@ip@bytes@isAttack
var pieces = strings.Split(ipString, "@") var pieces = strings.Split(ipString, "@")
if len(pieces) < 4 { if len(pieces) < 4 {
continue return nil
} }
var serverId = pieces[0] var serverId = pieces[0]
var ip = pieces[1] var ip = pieces[1]
var result = iplib.LookupIP(ip) var result = iplib.LookupIP(ip)
if result != nil && result.IsOk() { if result != nil && result.IsOk() {
var key = serverId + "@" + result.CountryName() + "@" + result.ProvinceName() + "@" + result.CityName() var key = serverId + "@" + types.String(result.CountryId()) + "@" + types.String(result.ProvinceId()) + "@" + types.String(result.CityId())
this.locker.Lock()
stat, ok := this.cityMap[key] stat, ok := this.cityMap[key]
if !ok { if !ok {
// 检查数量
if this.serverCityCountMap[key] > 128 { // 限制单个服务的城市数量,防止数量过多
this.locker.Unlock()
return nil
}
this.serverCityCountMap[key]++ // 需要放在限制之后因为使用的是int16
stat = &StatItem{} stat = &StatItem{}
this.cityMap[key] = stat this.cityMap[key] = stat
} }
@@ -212,15 +230,15 @@ Loop:
stat.CountAttackRequests++ stat.CountAttackRequests++
} }
if len(result.ProviderName()) > 0 { if result.ProviderId() > 0 {
this.providerMap[serverId+"@"+result.ProviderName()]++ this.providerMap[serverId+"@"+types.String(result.ProviderId())]++
} }
this.locker.Unlock()
} }
case userAgentString := <-this.userAgentChan: case userAgentString := <-this.userAgentChan:
var atIndex = strings.Index(userAgentString, "@") var atIndex = strings.Index(userAgentString, "@")
if atIndex < 0 { if atIndex < 0 {
continue return nil
} }
var serverId = userAgentString[:atIndex] var serverId = userAgentString[:atIndex]
var userAgent = userAgentString[atIndex+1:] var userAgent = userAgentString[atIndex+1:]
@@ -232,10 +250,21 @@ Loop:
if dotIndex > -1 { if dotIndex > -1 {
osInfo.Version = osInfo.Version[:dotIndex] osInfo.Version = osInfo.Version[:dotIndex]
} }
if len(this.systemMap) < 100_000 { // 限制最大数据,防止攻击 this.locker.Lock()
this.systemMap[serverId+"@"+osInfo.Name+"@"+osInfo.Version]++
var systemKey = serverId + "@" + osInfo.Name + "@" + osInfo.Version
_, ok := this.systemMap[systemKey]
if !ok {
if this.serverSystemCountMap[serverId] < 128 { // 限制最大数据,防止攻击
this.serverSystemCountMap[serverId]++
ok = true
} }
} }
if ok {
this.systemMap[systemKey]++
}
this.locker.Unlock()
}
var browser, browserVersion = result.BrowserName, result.BrowserVersion var browser, browserVersion = result.BrowserName, result.BrowserVersion
if len(browser) > 0 { if len(browser) > 0 {
@@ -243,20 +272,26 @@ Loop:
if dotIndex > -1 { if dotIndex > -1 {
browserVersion = browserVersion[:dotIndex] browserVersion = browserVersion[:dotIndex]
} }
if len(this.browserMap) < 100_000 { // 限制最大数据,防止攻击 this.locker.Lock()
this.browserMap[serverId+"@"+browser+"@"+browserVersion]++
var browserKey = serverId + "@" + browser + "@" + browserVersion
_, ok := this.browserMap[browserKey]
if !ok {
if this.serverBrowserCountMap[serverId] < 256 { // 限制最大数据,防止攻击
this.serverBrowserCountMap[serverId]++
ok = true
} }
} }
if ok {
this.browserMap[browserKey]++
}
this.locker.Unlock()
}
case firewallRuleGroupString := <-this.firewallRuleGroupChan: case firewallRuleGroupString := <-this.firewallRuleGroupChan:
this.locker.Lock()
this.dailyFirewallRuleGroupMap[firewallRuleGroupString]++ this.dailyFirewallRuleGroupMap[firewallRuleGroupString]++
case <-timeout.C: this.locker.Unlock()
break Loop
default:
break Loop
} }
}
timeout.Stop()
return nil return nil
} }
@@ -269,11 +304,31 @@ func (this *HTTPRequestStatManager) Upload() error {
return err return err
} }
// 拷贝数据
this.locker.Lock()
var cityMap = this.cityMap
var providerMap = this.providerMap
var systemMap = this.systemMap
var browserMap = this.browserMap
var dailyFirewallRuleGroupMap = this.dailyFirewallRuleGroupMap
this.cityMap = map[string]*StatItem{}
this.providerMap = map[string]int64{}
this.systemMap = map[string]int64{}
this.browserMap = map[string]int64{}
this.dailyFirewallRuleGroupMap = map[string]int64{}
this.serverCityCountMap = map[string]int16{}
this.serverSystemCountMap = map[string]int16{}
this.serverBrowserCountMap = map[string]int16{}
this.locker.Unlock()
// 上传限制 // 上传限制
var maxCities int16 = 20 var maxCities int16 = 32
var maxProviders int16 = 20 var maxProviders int16 = 32
var maxSystems int16 = 20 var maxSystems int16 = 64
var maxBrowsers int16 = 20 var maxBrowsers int16 = 64
nodeConfig, _ := nodeconfigs.SharedNodeConfig() nodeConfig, _ := nodeconfigs.SharedNodeConfig()
if nodeConfig != nil { if nodeConfig != nil {
var serverConfig = nodeConfig.GlobalServerConfig // 复制是为了防止在中途修改 var serverConfig = nodeConfig.GlobalServerConfig // 复制是为了防止在中途修改
@@ -300,21 +355,21 @@ func (this *HTTPRequestStatManager) Upload() error {
var pbBrowsers = []*pb.UploadServerHTTPRequestStatRequest_Browser{} var pbBrowsers = []*pb.UploadServerHTTPRequestStatRequest_Browser{}
// 城市 // 城市
for k, stat := range this.cityMap { for k, stat := range cityMap {
var pieces = strings.SplitN(k, "@", 4) var pieces = strings.SplitN(k, "@", 4)
var serverId = types.Int64(pieces[0]) var serverId = types.Int64(pieces[0])
pbCities = append(pbCities, &pb.UploadServerHTTPRequestStatRequest_RegionCity{ pbCities = append(pbCities, &pb.UploadServerHTTPRequestStatRequest_RegionCity{
ServerId: serverId, ServerId: serverId,
CountryName: pieces[1], CountryId: types.Int64(pieces[1]),
ProvinceName: pieces[2], ProvinceId: types.Int64(pieces[2]),
CityName: pieces[3], CityId: types.Int64(pieces[3]),
CountRequests: stat.CountRequests, CountRequests: stat.CountRequests,
CountAttackRequests: stat.CountAttackRequests, CountAttackRequests: stat.CountAttackRequests,
Bytes: stat.Bytes, Bytes: stat.Bytes,
AttackBytes: stat.AttackBytes, AttackBytes: stat.AttackBytes,
}) })
} }
if len(this.cityMap) > int(maxCities) { if len(cityMap) > int(maxCities) {
var newPBCities = []*pb.UploadServerHTTPRequestStatRequest_RegionCity{} var newPBCities = []*pb.UploadServerHTTPRequestStatRequest_RegionCity{}
sort.Slice(pbCities, func(i, j int) bool { sort.Slice(pbCities, func(i, j int) bool {
return pbCities[i].CountRequests > pbCities[j].CountRequests return pbCities[i].CountRequests > pbCities[j].CountRequests
@@ -333,16 +388,16 @@ func (this *HTTPRequestStatManager) Upload() error {
} }
// 运营商 // 运营商
for k, count := range this.providerMap { for k, count := range providerMap {
var pieces = strings.SplitN(k, "@", 2) var pieces = strings.SplitN(k, "@", 2)
var serverId = types.Int64(pieces[0]) var serverId = types.Int64(pieces[0])
pbProviders = append(pbProviders, &pb.UploadServerHTTPRequestStatRequest_RegionProvider{ pbProviders = append(pbProviders, &pb.UploadServerHTTPRequestStatRequest_RegionProvider{
ServerId: serverId, ServerId: serverId,
Name: pieces[1], ProviderId: types.Int64(pieces[1]),
Count: count, Count: count,
}) })
} }
if len(this.providerMap) > int(maxProviders) { if len(providerMap) > int(maxProviders) {
var newPBProviders = []*pb.UploadServerHTTPRequestStatRequest_RegionProvider{} var newPBProviders = []*pb.UploadServerHTTPRequestStatRequest_RegionProvider{}
sort.Slice(pbProviders, func(i, j int) bool { sort.Slice(pbProviders, func(i, j int) bool {
return pbProviders[i].Count > pbProviders[j].Count return pbProviders[i].Count > pbProviders[j].Count
@@ -361,7 +416,7 @@ func (this *HTTPRequestStatManager) Upload() error {
} }
// 操作系统 // 操作系统
for k, count := range this.systemMap { for k, count := range systemMap {
var pieces = strings.SplitN(k, "@", 3) var pieces = strings.SplitN(k, "@", 3)
var serverId = types.Int64(pieces[0]) var serverId = types.Int64(pieces[0])
pbSystems = append(pbSystems, &pb.UploadServerHTTPRequestStatRequest_System{ pbSystems = append(pbSystems, &pb.UploadServerHTTPRequestStatRequest_System{
@@ -371,7 +426,7 @@ func (this *HTTPRequestStatManager) Upload() error {
Count: count, Count: count,
}) })
} }
if len(this.systemMap) > int(maxSystems) { if len(systemMap) > int(maxSystems) {
var newPBSystems = []*pb.UploadServerHTTPRequestStatRequest_System{} var newPBSystems = []*pb.UploadServerHTTPRequestStatRequest_System{}
sort.Slice(pbSystems, func(i, j int) bool { sort.Slice(pbSystems, func(i, j int) bool {
return pbSystems[i].Count > pbSystems[j].Count return pbSystems[i].Count > pbSystems[j].Count
@@ -390,7 +445,7 @@ func (this *HTTPRequestStatManager) Upload() error {
} }
// 浏览器 // 浏览器
for k, count := range this.browserMap { for k, count := range browserMap {
var pieces = strings.SplitN(k, "@", 3) var pieces = strings.SplitN(k, "@", 3)
var serverId = types.Int64(pieces[0]) var serverId = types.Int64(pieces[0])
pbBrowsers = append(pbBrowsers, &pb.UploadServerHTTPRequestStatRequest_Browser{ pbBrowsers = append(pbBrowsers, &pb.UploadServerHTTPRequestStatRequest_Browser{
@@ -400,7 +455,7 @@ func (this *HTTPRequestStatManager) Upload() error {
Count: count, Count: count,
}) })
} }
if len(this.browserMap) > int(maxBrowsers) { if len(browserMap) > int(maxBrowsers) {
var newPBBrowsers = []*pb.UploadServerHTTPRequestStatRequest_Browser{} var newPBBrowsers = []*pb.UploadServerHTTPRequestStatRequest_Browser{}
sort.Slice(pbBrowsers, func(i, j int) bool { sort.Slice(pbBrowsers, func(i, j int) bool {
return pbBrowsers[i].Count > pbBrowsers[j].Count return pbBrowsers[i].Count > pbBrowsers[j].Count
@@ -420,7 +475,7 @@ func (this *HTTPRequestStatManager) Upload() error {
// 防火墙相关 // 防火墙相关
var pbFirewallRuleGroups = []*pb.UploadServerHTTPRequestStatRequest_HTTPFirewallRuleGroup{} var pbFirewallRuleGroups = []*pb.UploadServerHTTPRequestStatRequest_HTTPFirewallRuleGroup{}
for k, count := range this.dailyFirewallRuleGroupMap { for k, count := range dailyFirewallRuleGroupMap {
var pieces = strings.SplitN(k, "@", 3) var pieces = strings.SplitN(k, "@", 3)
pbFirewallRuleGroups = append(pbFirewallRuleGroups, &pb.UploadServerHTTPRequestStatRequest_HTTPFirewallRuleGroup{ pbFirewallRuleGroups = append(pbFirewallRuleGroups, &pb.UploadServerHTTPRequestStatRequest_HTTPFirewallRuleGroup{
ServerId: types.Int64(pieces[0]), ServerId: types.Int64(pieces[0]),
@@ -430,14 +485,6 @@ func (this *HTTPRequestStatManager) Upload() error {
}) })
} }
// 重置数据
// 这里需要放到上传数据之前,防止因上传失败而导致统计数据堆积
this.cityMap = map[string]*StatItem{}
this.providerMap = map[string]int64{}
this.systemMap = map[string]int64{}
this.browserMap = map[string]int64{}
this.dailyFirewallRuleGroupMap = map[string]int64{}
// 检查是否有数据 // 检查是否有数据
if len(pbCities) == 0 && if len(pbCities) == 0 &&
len(pbProviders) == 0 && len(pbProviders) == 0 &&