feat: 系统调优 Go 版后端完整源码
- 19 个接口全部实测验收通过 (2026-08-08) - 结构: main.go + core/consts + gsysctl + gtuner + server - 含 build_go.sh 官方部署结构构建脚本 (amd64/arm64 交叉编译) - 数据无缝衔接 Python 版遗留 (快照/state/审计日志) - 备份自 156:/root/goddhv (2026-08-09)
This commit is contained in:
+354
@@ -0,0 +1,354 @@
|
||||
// Package gtuner 提供系统调优核心服务(检测/一键优化/场景预设/TCP加速/Swappiness)。
|
||||
// 对应 Python 版 backend/app/services/tuner.py。
|
||||
package gtuner
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/user_TGPJp0KLpNsa5TAo/ddhv/core/consts"
|
||||
"github.com/user_TGPJp0KLpNsa5TAo/ddhv/gsysctl"
|
||||
)
|
||||
|
||||
// TunerService 系统调优服务
|
||||
type TunerService struct {
|
||||
S *gsysctl.Manager
|
||||
}
|
||||
|
||||
// NewTuner 构造服务
|
||||
func NewTuner() TunerService {
|
||||
return TunerService{S: gsysctl.NewManager()}
|
||||
}
|
||||
|
||||
// ========== 状态持久化 ==========
|
||||
|
||||
// statePath state.json 路径
|
||||
func statePath() string {
|
||||
return filepath.Join(consts.APP_DATA_PATH, "state.json")
|
||||
}
|
||||
|
||||
// SaveState 保存应用状态(当前预设等)
|
||||
func (t TunerService) SaveState(state map[string]any) {
|
||||
path := statePath()
|
||||
os.MkdirAll(filepath.Dir(path), 0o755)
|
||||
if data, err := json.MarshalIndent(state, "", " "); err == nil {
|
||||
os.WriteFile(path, data, 0o644)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadState 读取应用状态
|
||||
func (t TunerService) LoadState() map[string]any {
|
||||
path := statePath()
|
||||
if data, err := os.ReadFile(path); err == nil {
|
||||
var m map[string]any
|
||||
if json.Unmarshal(data, &m) == nil {
|
||||
return m
|
||||
}
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
// GetCurrentPreset 获取当前生效的预设方案
|
||||
func (t TunerService) GetCurrentPreset() (map[string]any, error) {
|
||||
state := t.LoadState()
|
||||
key := ""
|
||||
if v, ok := state["current_preset"].(string); ok {
|
||||
key = v
|
||||
}
|
||||
presets := t.GetPresets()
|
||||
if key != "" {
|
||||
if p, ok := presets[key].(map[string]any); ok {
|
||||
name, _ := p["name"].(string)
|
||||
appliedAt := ""
|
||||
if v, ok := state["preset_applied_at"].(string); ok {
|
||||
appliedAt = v
|
||||
}
|
||||
return map[string]any{"current": key, "name": name, "applied_at": appliedAt}, nil
|
||||
}
|
||||
}
|
||||
return map[string]any{"current": nil, "name": nil, "applied_at": ""}, nil
|
||||
}
|
||||
|
||||
// ========== 系统检测 ==========
|
||||
|
||||
// CheckRoot 检查 root 权限
|
||||
func (t TunerService) CheckRoot() (map[string]any, error) {
|
||||
isRoot := os.Geteuid() == 0
|
||||
return map[string]any{
|
||||
"is_root": isRoot, "proc_writable": isRoot, "ok": isRoot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DetectHardware 检测硬件环境
|
||||
func (t TunerService) DetectHardware() (map[string]any, error) {
|
||||
info := map[string]any{
|
||||
"os": runtime.GOOS + " linux", "arch": runtime.GOARCH,
|
||||
"cpu_cores": runtime.NumCPU(), "memory_gb": 0.0,
|
||||
"disk_type": "unknown", "is_container": false, "virtualization": "none",
|
||||
}
|
||||
// 内存
|
||||
if data, err := os.ReadFile("/proc/meminfo"); err == nil {
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.HasPrefix(line, "MemTotal:") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 2 {
|
||||
if kb, err := strconv.ParseInt(fields[1], 10, 64); err == nil {
|
||||
gb := float64(kb) / 1024 / 1024
|
||||
info["memory_gb"] = float64(int(gb*10+0.5)) / 10
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 磁盘类型
|
||||
for _, dev := range []string{"sda", "vda"} {
|
||||
if data, err := os.ReadFile("/sys/block/" + dev + "/queue/rotational"); err == nil {
|
||||
if strings.TrimSpace(string(data)) == "1" {
|
||||
info["disk_type"] = "hdd"
|
||||
} else {
|
||||
info["disk_type"] = "ssd"
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
// 容器检测
|
||||
if data, err := os.ReadFile("/proc/1/cgroup"); err == nil {
|
||||
c := string(data)
|
||||
if strings.Contains(c, "docker") || strings.Contains(c, "kubepods") || strings.Contains(c, "lxc") {
|
||||
info["is_container"] = true
|
||||
info["virtualization"] = "container"
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat("/.dockerenv"); err == nil {
|
||||
info["is_container"] = true
|
||||
info["virtualization"] = "docker"
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// DetectSwap 检测 swap
|
||||
func (t TunerService) DetectSwap() (map[string]any, error) {
|
||||
enabled := false
|
||||
if data, err := os.ReadFile("/proc/swaps"); err == nil {
|
||||
for _, line := range strings.Split(string(data), "\n")[1:] {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(line, "Filename") && len(strings.Fields(line)) > 0 {
|
||||
enabled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return map[string]any{"swap_enabled": enabled}, nil
|
||||
}
|
||||
|
||||
// DetectTCP 检测 TCP 配置
|
||||
func (t TunerService) DetectTCP() (map[string]any, error) {
|
||||
keys := []string{
|
||||
"net.ipv4.tcp_congestion_control", "net.core.default_qdisc",
|
||||
"net.ipv4.tcp_fastopen", "net.ipv4.tcp_syncookies",
|
||||
"net.ipv4.tcp_rmem", "net.ipv4.tcp_wmem",
|
||||
"net.core.rmem_max", "net.core.wmem_max",
|
||||
"net.core.somaxconn", "net.ipv4.tcp_max_syn_backlog",
|
||||
"net.ipv4.tcp_tw_reuse", "net.ipv4.tcp_slow_start_after_idle",
|
||||
"net.ipv4.tcp_mtu_probing", "net.ipv4.ip_local_port_range",
|
||||
}
|
||||
values, _ := gsysctl.GetValues(keys)
|
||||
// BBR 支持检测
|
||||
result := map[string]any{}
|
||||
for k, v := range values {
|
||||
result[k] = v
|
||||
}
|
||||
bbrAvailable := false
|
||||
if out, err := gsysctl.GetValue("net.ipv4.tcp_available_congestion_control"); err == nil {
|
||||
if strings.Contains(strings.ToLower(out), "bbr") {
|
||||
bbrAvailable = true
|
||||
}
|
||||
}
|
||||
result["bbr_available"] = bbrAvailable
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Detect 综合检测
|
||||
func (t TunerService) Detect() (map[string]any, error) {
|
||||
hw, _ := t.DetectHardware()
|
||||
tcp, _ := t.DetectTCP()
|
||||
swap, _ := t.DetectSwap()
|
||||
preset, _ := t.GetCurrentPreset()
|
||||
root, _ := t.CheckRoot()
|
||||
init, _ := t.InitStatus()
|
||||
return map[string]any{
|
||||
"hardware": hw, "tcp": tcp, "swap": swap, "preset": preset,
|
||||
"root": root, "init": init,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ========== 场景预设 ==========
|
||||
|
||||
// GetPresets 返回可用的调优场景预设
|
||||
func (t TunerService) GetPresets() map[string]any {
|
||||
return map[string]any{
|
||||
"balanced": map[string]any{
|
||||
"name": "均衡模式",
|
||||
"desc": "适合大多数服务器,平衡性能与稳定性",
|
||||
"params": map[string]string{
|
||||
"vm.swappiness": "10",
|
||||
"net.core.default_qdisc": "fq",
|
||||
"net.ipv4.tcp_congestion_control": "bbr",
|
||||
"net.ipv4.tcp_fastopen": "3",
|
||||
"net.ipv4.tcp_slow_start_after_idle": "0",
|
||||
"net.ipv4.tcp_mtu_probing": "1",
|
||||
"net.core.somaxconn": "1024",
|
||||
"net.ipv4.tcp_max_syn_backlog": "4096",
|
||||
},
|
||||
},
|
||||
"performance": map[string]any{
|
||||
"name": "高性能模式",
|
||||
"desc": "追求极限吞吐,适合高并发业务(内存≥4G推荐)",
|
||||
"params": map[string]string{
|
||||
"vm.swappiness": "5",
|
||||
"vm.vfs_cache_pressure": "50",
|
||||
"net.core.default_qdisc": "fq",
|
||||
"net.ipv4.tcp_congestion_control": "bbr",
|
||||
"net.ipv4.tcp_fastopen": "3",
|
||||
"net.ipv4.tcp_slow_start_after_idle": "0",
|
||||
"net.ipv4.tcp_mtu_probing": "1",
|
||||
"net.core.somaxconn": "4096",
|
||||
"net.ipv4.tcp_max_syn_backlog": "8192",
|
||||
"net.core.rmem_max": "16777216",
|
||||
"net.core.wmem_max": "16777216",
|
||||
"net.ipv4.tcp_rmem": "4096 87380 16777216",
|
||||
"net.ipv4.tcp_wmem": "4096 16384 16777216",
|
||||
"net.ipv4.tcp_tw_reuse": "1",
|
||||
},
|
||||
},
|
||||
"conservative": map[string]any{
|
||||
"name": "保守模式",
|
||||
"desc": "最小改动,仅调整最安全的参数",
|
||||
"params": map[string]string{
|
||||
"vm.swappiness": "10",
|
||||
"net.ipv4.tcp_slow_start_after_idle": "0",
|
||||
"net.ipv4.tcp_mtu_probing": "1",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyPreset 应用场景预设
|
||||
func (t TunerService) ApplyPreset(key string) (map[string]any, error) {
|
||||
presets := t.GetPresets()
|
||||
p, ok := presets[key].(map[string]any)
|
||||
if !ok {
|
||||
return nil, gsysctl.NewErrSysctl("未知的预设场景: " + key)
|
||||
}
|
||||
name, _ := p["name"].(string)
|
||||
params, _ := p["params"].(map[string]string)
|
||||
results := gsysctl.SetValues(params, true)
|
||||
okCount, failCount := 0, 0
|
||||
for _, r := range results {
|
||||
if m, ok := r.(map[string]any); ok {
|
||||
if v, ok := m["ok"].(bool); ok && v {
|
||||
okCount++
|
||||
} else {
|
||||
failCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
t.SaveState(map[string]any{
|
||||
"current_preset": key, "preset_applied_at": time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
t.S.LogAction("apply_preset", map[string]any{
|
||||
"preset": key, "preset_name": name, "ok": okCount, "fail": failCount,
|
||||
})
|
||||
return map[string]any{
|
||||
"preset": key, "preset_name": name, "results": results,
|
||||
"ok_count": okCount, "fail_count": failCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InitStatus 检查是否已初始化
|
||||
func (t TunerService) InitStatus() (map[string]any, error) {
|
||||
snaps := t.S.ListSnapshots()
|
||||
for _, s := range snaps {
|
||||
if s.Kind == "init" {
|
||||
return map[string]any{"initialized": true, "snapshot": s}, nil
|
||||
}
|
||||
}
|
||||
return map[string]any{"initialized": false, "snapshot": nil}, nil
|
||||
}
|
||||
|
||||
// InitSnapshot 首次使用初始化快照
|
||||
func (t TunerService) InitSnapshot() (map[string]any, error) {
|
||||
snaps := t.S.ListSnapshots()
|
||||
for _, s := range snaps {
|
||||
if s.Kind == "init" {
|
||||
return map[string]any{"already": true, "snapshot": s}, nil
|
||||
}
|
||||
}
|
||||
meta, err := t.S.CreateSnapshot("首次使用初始化", "init")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.S.LogAction("init", map[string]any{"snapshot": meta.Name, "param_count": meta.ParamCount})
|
||||
return map[string]any{"already": false, "snapshot": meta}, nil
|
||||
}
|
||||
|
||||
// ========== 单独调优项 ==========
|
||||
|
||||
// SetSwappiness 设置 swappiness
|
||||
func (t TunerService) SetSwappiness(value int, persist bool) (map[string]any, error) {
|
||||
if value < 0 || value > 100 {
|
||||
return nil, gsysctl.NewErrSysctl("swappiness 必须在 0-100 之间")
|
||||
}
|
||||
err := gsysctl.SetValue("vm.swappiness", strconv.Itoa(value), persist)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
current, _ := gsysctl.GetValue("vm.swappiness")
|
||||
t.S.LogAction("set_swappiness", map[string]any{"value": value, "persist": persist})
|
||||
return map[string]any{"ok": true, "value": value, "current": current}, nil
|
||||
}
|
||||
|
||||
// EnableBBR 一键开启 BBR
|
||||
func (t TunerService) EnableBBR() (map[string]any, error) {
|
||||
results := gsysctl.SetValues(map[string]string{
|
||||
"net.core.default_qdisc": "fq",
|
||||
"net.ipv4.tcp_congestion_control": "bbr",
|
||||
}, true)
|
||||
current, _ := gsysctl.GetValue("net.ipv4.tcp_congestion_control")
|
||||
t.S.LogAction("enable_bbr", map[string]any{"current": current})
|
||||
return map[string]any{"results": results, "current": current}, nil
|
||||
}
|
||||
|
||||
// DisableBBR 关闭 BBR
|
||||
func (t TunerService) DisableBBR() (map[string]any, error) {
|
||||
results := gsysctl.SetValues(map[string]string{
|
||||
"net.ipv4.tcp_congestion_control": "cubic",
|
||||
}, true)
|
||||
current, _ := gsysctl.GetValue("net.ipv4.tcp_congestion_control")
|
||||
t.S.LogAction("disable_bbr", map[string]any{"current": current})
|
||||
return map[string]any{"results": results, "current": current}, nil
|
||||
}
|
||||
|
||||
// ========== 危险参数解锁 ==========
|
||||
|
||||
// GetDangerousParams 危险参数清单
|
||||
func (t TunerService) GetDangerousParams() map[string]any {
|
||||
return map[string]any{
|
||||
"vm.swappiness": map[string]any{"risk": "danger", "desc": "内存交换策略,过低可能导致内存压力,过高会导致频繁交换"},
|
||||
"vm.vfs_cache_pressure": map[string]any{"risk": "danger", "desc": "内核缓存回收倾向,过高可能导致缓存频繁失效"},
|
||||
"net.core.rmem_max": map[string]any{"risk": "danger", "desc": "最大接收缓冲区,过大可能浪费内存"},
|
||||
"net.core.wmem_max": map[string]any{"risk": "danger", "desc": "最大发送缓冲区,过大可能浪费内存"},
|
||||
"net.ipv4.tcp_rmem": map[string]any{"risk": "danger", "desc": "TCP 接收缓冲动态范围,不当设置影响吞吐"},
|
||||
"net.ipv4.tcp_wmem": map[string]any{"risk": "danger", "desc": "TCP 发送缓冲动态范围,不当设置影响吞吐"},
|
||||
"net.ipv4.tcp_tw_reuse": map[string]any{"risk": "danger", "desc": "TIME_WAIT 复用,NAT 环境下可能引发问题"},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user