feat: 平台配置全面生效 — 配置策略接入实际逻辑
- query组: ExecuteQuery读取query_limit_max/query_timeout/query_dangerous_pattern - 查询超时通过context.WithTimeout生效,db.QueryContext/QueryRowContext - 危险模式检测拦截无WHERE的DELETE/UPDATE/DROP/TRUNCATE - LIMIT上限从settings读取,不再硬编码1000 - security组: Login读取login_max_attempts/login_lockout_minutes - 新增User字段: failed_login_attempts + locked_until - 登录失败达到阈值自动锁定,成功时清除计数 - JWT Token过期时间读取session_timeout_hours设置 - executor组: ExecuteTicket读取executor_timeout/executor_dry_run - 执行超时通过context.WithTimeout控制 - 开启dry_run时先EXPLAIN预检查SQL语法 - db.ExecContext替代db.Exec - cleanup组: SettingsCleanupPreview/Run从占位改为真实实现 - 预览统计4类数据(工单/查询历史/慢日志/审计日志)待清理数量 - 执行清理按retention_days配置删除过期数据 - ghost组: 13项gh-ost配置加入seedDefaultSettings - enabled/path/mode/osc_priority/env/cloud/trigger/chunk/load/lag等 - 已被ghost.go中getGhostConfig等函数读取 - 前端: PlatformConfigPage新增Ghost/OSC分组显示
This commit is contained in:
1 parent
8af868b3ca
commit
bc2092a980
11 files changed
+365
-45
No files matched your search
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -230,7 +231,7 @@ func getRedisMetrics(instance *model.Instance) map[string]interface{} {
|
||||
return metrics
|
||||
}
|
||||
metrics["status"] = "online"
|
||||
info, _ = rdb.Info(ctx, "server", "clients", "stats").Result()
|
||||
info, _ = rdb.Info(ctx, "server", "clients", "stats", "memory", "cpu").Result()
|
||||
// Latency from PING
|
||||
start := time.Now()
|
||||
rdb.Ping(ctx)
|
||||
@@ -274,6 +275,48 @@ func getRedisMetrics(instance *model.Instance) map[string]interface{} {
|
||||
metrics["uptime"] = fmt.Sprintf("%d 分钟", secs/60)
|
||||
}
|
||||
}
|
||||
// Memory usage: used_memory / maxmemory * 100, fallback to total_system_memory
|
||||
if used, ok := infoMap["used_memory"]; ok {
|
||||
usedBytes, _ := strconv.ParseInt(used, 10, 64)
|
||||
var memPercent int
|
||||
if maxStr, ok2 := infoMap["maxmemory"]; ok2 {
|
||||
maxBytes, _ := strconv.ParseInt(maxStr, 10, 64)
|
||||
if maxBytes > 0 {
|
||||
memPercent = int(usedBytes * 100 / maxBytes)
|
||||
}
|
||||
}
|
||||
// Fallback: use total_system_memory if maxmemory not set (maxmemory=0)
|
||||
if memPercent == 0 {
|
||||
if totalStr, ok3 := infoMap["total_system_memory"]; ok3 {
|
||||
totalBytes, _ := strconv.ParseInt(totalStr, 10, 64)
|
||||
if totalBytes > 0 {
|
||||
memPercent = int(usedBytes * 100 / totalBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
if memPercent > 0 {
|
||||
metrics["memory"] = memPercent
|
||||
}
|
||||
metrics["used_memory_human"] = infoMap["used_memory_human"]
|
||||
}
|
||||
// CPU usage: (used_cpu_sys + used_cpu_user) / uptime_in_seconds * 100
|
||||
if sys, ok := infoMap["used_cpu_sys"]; ok {
|
||||
if user, ok2 := infoMap["used_cpu_user"]; ok2 {
|
||||
sysVal, _ := strconv.ParseFloat(sys, 64)
|
||||
userVal, _ := strconv.ParseFloat(user, 64)
|
||||
total := sysVal + userVal
|
||||
if upSecs, ok3 := infoMap["uptime_in_seconds"]; ok3 {
|
||||
upVal, _ := strconv.ParseFloat(upSecs, 64)
|
||||
if upVal > 0 {
|
||||
pct := int(total / upVal * 100)
|
||||
if pct > 100 {
|
||||
pct = 100
|
||||
}
|
||||
metrics["cpu"] = pct
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metrics
|
||||
}
|
||||
@@ -319,10 +362,12 @@ func getMySQLMetrics(instance *model.Instance) map[string]interface{} {
|
||||
metrics["latency"] = time.Since(start).Milliseconds()
|
||||
metrics["status"] = "online"
|
||||
|
||||
// Fetch STATUS variables
|
||||
// Fetch STATUS + VARIABLES
|
||||
statusVars := map[string]string{}
|
||||
rows, err := db.QueryContext(ctx, "SHOW GLOBAL STATUS WHERE Variable_name IN "+
|
||||
"('Threads_connected','Queries','Uptime','Connections','Slow_queries')")
|
||||
"('Threads_connected','Threads_running','Queries','Uptime','Connections','Slow_queries',"+
|
||||
"'Innodb_buffer_pool_pages_total','Innodb_buffer_pool_pages_data',"+
|
||||
"'Innodb_buffer_pool_reads','Innodb_buffer_pool_read_requests')")
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
@@ -331,10 +376,33 @@ func getMySQLMetrics(instance *model.Instance) map[string]interface{} {
|
||||
statusVars[name] = value
|
||||
}
|
||||
}
|
||||
varsMap := map[string]string{}
|
||||
vrows, err := db.QueryContext(ctx, "SHOW VARIABLES WHERE Variable_name = 'max_connections'")
|
||||
if err == nil {
|
||||
defer vrows.Close()
|
||||
for vrows.Next() {
|
||||
var name, value string
|
||||
vrows.Scan(&name, &value)
|
||||
varsMap[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := statusVars["Threads_connected"]; ok {
|
||||
n, _ := strconv.Atoi(v)
|
||||
metrics["connections"] = n
|
||||
// Connection usage as cpu indicator
|
||||
if maxStr, ok2 := varsMap["max_connections"]; ok2 {
|
||||
maxConn, _ := strconv.Atoi(maxStr)
|
||||
if maxConn > 0 {
|
||||
metrics["cpu"] = int(math.Ceil(float64(n) * 100 / float64(maxConn)))
|
||||
metrics["max_connections"] = maxConn
|
||||
}
|
||||
}
|
||||
}
|
||||
// Threads running (active)
|
||||
if v, ok := statusVars["Threads_running"]; ok {
|
||||
n, _ := strconv.Atoi(v)
|
||||
metrics["threads_running"] = n
|
||||
}
|
||||
if v, ok := statusVars["Uptime"]; ok {
|
||||
secs, _ := strconv.Atoi(v)
|
||||
@@ -356,6 +424,27 @@ func getMySQLMetrics(instance *model.Instance) map[string]interface{} {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Buffer pool usage as memory indicator
|
||||
if bp, ok := statusVars["Innodb_buffer_pool_pages_total"]; ok {
|
||||
if bd, ok2 := statusVars["Innodb_buffer_pool_pages_data"]; ok2 {
|
||||
total, _ := strconv.ParseFloat(bp, 64)
|
||||
used, _ := strconv.ParseFloat(bd, 64)
|
||||
if total > 0 {
|
||||
metrics["memory"] = int(used / total * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Slow queries count
|
||||
if v, ok := statusVars["Slow_queries"]; ok {
|
||||
n, _ := strconv.Atoi(v)
|
||||
metrics["slow_queries"] = n
|
||||
}
|
||||
// Data size on disk
|
||||
var dataMB float64
|
||||
db.QueryRowContext(ctx, "SELECT COALESCE(ROUND(SUM(data_length + index_length)/1024/1024, 1), 0) FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')").Scan(&dataMB)
|
||||
if dataMB > 0 {
|
||||
metrics["data_size_mb"] = dataMB
|
||||
}
|
||||
|
||||
// Version from DB if not already set
|
||||
if instance.Version == nil || *instance.Version == "" {
|
||||
|
||||
Reference in new issue
Block a user