feat: configurable traffic threshold and Feishu bot alerts
This commit is contained in:
1 parent
3e6e481b79
commit
1273f226fd
16 files changed
+660
-20
No files matched your search
@@ -10,14 +10,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"vpn-platform/backend/internal/alertnotify"
|
||||
"vpn-platform/backend/internal/model"
|
||||
"vpn-platform/backend/internal/sessionmgr"
|
||||
"vpn-platform/backend/internal/store"
|
||||
)
|
||||
|
||||
// 异常流量阈值:15s 内超过此字节数视为突发(约 50Mbps × 15s ≈ 93MB)
|
||||
const rateAlertThreshold = 90 * 1024 * 1024
|
||||
|
||||
// CheckQuota 检查指定隧道的流量配额,返回超额动作("" 表示未超额或无限额)
|
||||
func CheckQuota(tunnelID uint, deltaRx, deltaTx int64) string {
|
||||
if store.DB == nil {
|
||||
@@ -65,7 +63,7 @@ func ResetIfNeeded(policy *model.TrafficPolicy) {
|
||||
policy.UsedBytes = 0
|
||||
policy.LastResetAt = now
|
||||
store.DB.Model(policy).Updates(map[string]interface{}{
|
||||
"used_bytes": 0,
|
||||
"used_bytes": 0,
|
||||
"last_reset_at": now,
|
||||
})
|
||||
}
|
||||
@@ -74,14 +72,20 @@ func ResetIfNeeded(policy *model.TrafficPolicy) {
|
||||
// CheckRateAbnormal 检查流量速率是否异常(突发流量告警)
|
||||
func CheckRateAbnormal(tunnelID uint, deltaRx, deltaTx int64, interval time.Duration) bool {
|
||||
total := deltaRx + deltaTx
|
||||
if total <= 0 {
|
||||
if total <= 0 || interval <= 0 {
|
||||
return false
|
||||
}
|
||||
ratePerSec := float64(total) / interval.Seconds()
|
||||
// 超过阈值(约 50Mbps)
|
||||
if total > rateAlertThreshold {
|
||||
sessionmgr.LogConnection(tunnelID, "*", "rate_alert", "",
|
||||
fmt.Sprintf("突发流量 %.1f MB(%.0f Mbps),15s 内增量异常", float64(total)/(1024*1024), ratePerSec*8/(1024*1024)))
|
||||
settings, err := alertnotify.Get()
|
||||
threshold := alertnotify.DefaultThreshold
|
||||
if err == nil {
|
||||
threshold = settings.RateThresholdMbps
|
||||
}
|
||||
// Mbps 按十进制 1,000,000 bits/s 计算,使用真实采样间隔。
|
||||
if ratePerSec*8 > float64(threshold)*1_000_000 {
|
||||
detail := fmt.Sprintf("突发流量 %.1f MiB(%.0f Mbps),采样间隔 %.0f 秒", float64(total)/(1024*1024), ratePerSec*8/1_000_000, interval.Seconds())
|
||||
sessionmgr.LogConnection(tunnelID, "*", "rate_alert", "", detail)
|
||||
alertnotify.Notify(tunnelID, "rate_alert", detail)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -91,19 +95,22 @@ func CheckRateAbnormal(tunnelID uint, deltaRx, deltaTx int64, interval time.Dura
|
||||
func HandleExceed(tunnelID uint, action string, tunnelName string) {
|
||||
switch action {
|
||||
case "warn":
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "",
|
||||
fmt.Sprintf("隧道「%s」流量配额已用尽(仅告警)", tunnelName))
|
||||
detail := fmt.Sprintf("隧道「%s」流量配额已用尽(仅告警)", tunnelName)
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "", detail)
|
||||
alertnotify.Notify(tunnelID, "quota_exceed", detail)
|
||||
case "block":
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "",
|
||||
fmt.Sprintf("隧道「%s」流量配额已用尽,自动停止", tunnelName))
|
||||
detail := fmt.Sprintf("隧道「%s」流量配额已用尽,自动停止", tunnelName)
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "", detail)
|
||||
alertnotify.Notify(tunnelID, "quota_exceed", detail)
|
||||
// 由调用方执行 Stop(避免循环依赖,只返回信号)
|
||||
case "throttle":
|
||||
// 降速到 1Mbps
|
||||
var policy model.TrafficPolicy
|
||||
if store.DB.Where("tunnel_id = ?", tunnelID).First(&policy).Error == nil {
|
||||
ApplyRateLimit(tunnelID, 1)
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "",
|
||||
fmt.Sprintf("隧道「%s」流量配额已用尽,限速至 1 Mbps", tunnelName))
|
||||
detail := fmt.Sprintf("隧道「%s」流量配额已用尽,限速至 1 Mbps", tunnelName)
|
||||
sessionmgr.LogConnection(tunnelID, "*", "quota_exceed", "", detail)
|
||||
alertnotify.Notify(tunnelID, "quota_exceed", detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user