// 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 环境下可能引发问题"}, } }