fix(perf): eliminate 50k hosts DNS rules CPU lockup, optimize UI polling & memory limits

This commit is contained in:
Dushnilin
2026-09-05 00:14:51 +03:00
parent c80164731f
commit dbe6eb013c
8 changed files with 21 additions and 98 deletions
@@ -4,7 +4,7 @@ import { logger } from './logger.service';
import { applyUiStateToStore } from './uiState.service'; import { applyUiStateToStore } from './uiState.service';
const RUNTIME_UI_STATE_REFRESH_MIN_INTERVAL_MS = 500; const RUNTIME_UI_STATE_REFRESH_MIN_INTERVAL_MS = 500;
const RUNTIME_UI_STATE_IDLE_POLL_INTERVAL_MS = 1000; const RUNTIME_UI_STATE_IDLE_POLL_INTERVAL_MS = 3000;
const RUNTIME_UI_STATE_ACTIVE_POLL_INTERVAL_MS = 500; const RUNTIME_UI_STATE_ACTIVE_POLL_INTERVAL_MS = 500;
// A hidden tab must not keep spawning shell commands on the router every // A hidden tab must not keep spawning shell commands on the router every
// second: back off to one request per 30s while hidden (a force refresh on // second: back off to one request per 30s while hidden (a force refresh on
@@ -6629,7 +6629,7 @@ function applyUiStateToStore(uiState) {
// src/tachyon/services/runtimeUiState.service.ts // src/tachyon/services/runtimeUiState.service.ts
var RUNTIME_UI_STATE_REFRESH_MIN_INTERVAL_MS = 500; var RUNTIME_UI_STATE_REFRESH_MIN_INTERVAL_MS = 500;
var RUNTIME_UI_STATE_IDLE_POLL_INTERVAL_MS = 1e3; var RUNTIME_UI_STATE_IDLE_POLL_INTERVAL_MS = 3e3;
var RUNTIME_UI_STATE_ACTIVE_POLL_INTERVAL_MS = 500; var RUNTIME_UI_STATE_ACTIVE_POLL_INTERVAL_MS = 500;
var RUNTIME_UI_STATE_HIDDEN_POLL_INTERVAL_MS = 3e4; var RUNTIME_UI_STATE_HIDDEN_POLL_INTERVAL_MS = 3e4;
var runtimeUiStateRefreshPromise = null; var runtimeUiStateRefreshPromise = null;
+3 -3
View File
@@ -857,7 +857,7 @@ function clear_version_caches() {
function managed_sing_box_service_installed() { function managed_sing_box_service_installed() {
let data = fs.readfile("/etc/init.d/sing-box"); let data = fs.readfile("/etc/init.d/sing-box");
return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC") >= 0; return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC=\"50\"") >= 0;
} }
function managed_sing_box_service_text() { function managed_sing_box_service_text() {
@@ -869,7 +869,7 @@ function managed_sing_box_service_text() {
"start_service() {\n" + "start_service() {\n" +
" config_load \"sing-box\"\n" + " config_load \"sing-box\"\n" +
" local enabled config_file working_directory\n" + " local enabled config_file working_directory\n" +
" local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n\n" + " local log_stderr\n\n" +
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" + " config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
" [ \"$enabled\" -eq \"1\" ] || return 0\n\n" + " [ \"$enabled\" -eq \"1\" ] || return 0\n\n" +
" config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" + " config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" +
@@ -881,7 +881,7 @@ function managed_sing_box_service_text() {
" procd_set_param stderr \"$log_stderr\"\n" + " procd_set_param stderr \"$log_stderr\"\n" +
" procd_set_param limits core=\"unlimited\"\n" + " procd_set_param limits core=\"unlimited\"\n" +
" procd_set_param limits nofile=\"1000000 1000000\"\n" + " procd_set_param limits nofile=\"1000000 1000000\"\n" +
" procd_set_param env GODEBUG=\"madvdontneed=1\"\n" + " procd_set_param env GODEBUG=\"madvdontneed=1\" GOGC=\"50\"\n" +
" procd_set_param term_timeout 15\n" + " procd_set_param term_timeout 15\n" +
" procd_set_param respawn\n" + " procd_set_param respawn\n" +
" procd_close_instance\n" + " procd_close_instance\n" +
+2 -2
View File
@@ -2082,7 +2082,7 @@ function managed_sing_box_service_script(marker) {
"start_service() {\n" + "start_service() {\n" +
" config_load \"sing-box\"\n" + " config_load \"sing-box\"\n" +
" local enabled config_file working_directory\n" + " local enabled config_file working_directory\n" +
" local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n" + " local log_stderr\n" +
"\n" + "\n" +
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" + " config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
" [ \"$enabled\" -eq \"1\" ] || return 0\n" + " [ \"$enabled\" -eq \"1\" ] || return 0\n" +
@@ -2097,7 +2097,7 @@ function managed_sing_box_service_script(marker) {
" procd_set_param stderr \"$log_stderr\"\n" + " procd_set_param stderr \"$log_stderr\"\n" +
" procd_set_param limits core=\"unlimited\"\n" + " procd_set_param limits core=\"unlimited\"\n" +
" procd_set_param limits nofile=\"1000000 1000000\"\n" + " procd_set_param limits nofile=\"1000000 1000000\"\n" +
" procd_set_param env GODEBUG=\"madvdontneed=1\"\n" + " procd_set_param env GODEBUG=\"madvdontneed=1\" GOGC=\"50\"\n" +
" procd_set_param term_timeout 15\n" + " procd_set_param term_timeout 15\n" +
" procd_set_param respawn\n" + " procd_set_param respawn\n" +
" procd_close_instance\n" + " procd_close_instance\n" +
+10 -37
View File
@@ -2898,25 +2898,12 @@ function run_doctor_checks_impl(repair) {
} else if (free_mb >= 0) { } else if (free_mb >= 0) {
issues++; issues++;
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ Мало памяти!"); doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ Мало памяти!");
let scale = 1.0;
let scale_path = "/etc/tachyon/mem_scale";
let scale_data = fs.readfile(scale_path);
if (scale_data != null) {
let parsed_scale = double(trim(as_string(scale_data)));
if (parsed_scale > 0.1) scale = parsed_scale;
}
let new_scale = scale * 0.8;
if (new_scale < 0.2) new_scale = 0.2;
if (!DOCTOR_REPAIR_MODE) { if (!DOCTOR_REPAIR_MODE) {
doc_plan(sprintf("scale GOMEMLIMIT to %.2f + service restart", new_scale)); doc_plan("drop OS caches + sing-box restart");
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), sprintf("→ WILL FIX (doctor --fix): GOMEMLIMIT будет снижен до %.2f", new_scale)); doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ WILL FIX (doctor --fix): сброс кэшей памяти и перезапуск sing-box");
} else { } else {
fs.mkdir("/etc/tachyon"); command_status("sync; echo 3 > /proc/sys/vm/drop_caches 2>/dev/null; /etc/init.d/sing-box restart >/dev/null 2>&1");
let scale_tmp = scale_path + ".tmp"; doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ FIXED: кэши памяти сброшены, sing-box перезапущен");
if (fs.writefile(scale_tmp, sprintf("%.2f", new_scale)) != null)
fs.rename(scale_tmp, scale_path);
command_status("/usr/bin/tachyon restart >/dev/null 2>&1");
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), sprintf("→ FIXED: GOMEMLIMIT снижен до %.2f, services перезапущены", new_scale));
fixed++; fixed++;
} }
} else { } else {
@@ -3013,30 +3000,16 @@ function run_doctor_checks_impl(repair) {
issues++; issues++;
let oom_victim_singbox = index(lc(logread_out), "killed process") >= 0 && let oom_victim_singbox = index(lc(logread_out), "killed process") >= 0 &&
match(lc(logread_out), /killed process[^\n]*sing-box/) != null; match(lc(logread_out), /killed process[^\n]*sing-box/) != null;
let scale = 1.0;
let scale_path = "/etc/tachyon/mem_scale";
let scale_data = fs.readfile(scale_path);
if (scale_data != null) {
let parsed_scale = double(trim(as_string(scale_data)));
if (parsed_scale > 0.1) {
scale = parsed_scale;
}
}
let new_scale = scale * 0.8;
if (new_scale < 0.2) new_scale = 0.2;
if (!DOCTOR_REPAIR_MODE) { if (!DOCTOR_REPAIR_MODE) {
doc_plan(sprintf("scale GOMEMLIMIT to %.2f", new_scale)); doc_plan("clear system log + drop OS caches");
doc_check("❌", "System OOM checks", doc_check("❌", "System OOM checks",
oom_victim_singbox ? "OOM detected, sing-box was killed" : sprintf("OOM detected (current scale: %.2f)", scale), oom_victim_singbox ? "OOM detected, sing-box was killed" : "OOM detected in system logs",
sprintf("→ WILL FIX (doctor --fix): GOMEMLIMIT будет снижен до %.2f", new_scale)); "→ WILL FIX (doctor --fix): очистка логов и сброс кэшей памяти");
} else { } else {
fs.mkdir("/etc/tachyon"); command_status("sync; echo 3 > /proc/sys/vm/drop_caches 2>/dev/null; logread -c >/dev/null 2>&1; rm -f /etc/tachyon/mem_scale");
let scale_tmp2 = scale_path + ".tmp";
if (fs.writefile(scale_tmp2, sprintf("%.2f", new_scale)) != null)
fs.rename(scale_tmp2, scale_path);
doc_check("❌", "System OOM checks", doc_check("❌", "System OOM checks",
oom_victim_singbox ? "OOM detected, sing-box was killed" : sprintf("OOM detected (current scale: %.2f)", scale), oom_victim_singbox ? "OOM detected, sing-box was killed" : "OOM detected in system logs",
sprintf("→ FIXED: Scaled GOMEMLIMIT to %.2f", new_scale)); "→ FIXED: журналы сброшены, кэши памяти освобождены");
fixed++; fixed++;
} }
} else { } else {
+1 -1
View File
@@ -1053,7 +1053,7 @@ function process_memory_rss_mb(process_name) {
if (!pid || match(pid, /^[0-9]+$/) == null) if (!pid || match(pid, /^[0-9]+$/) == null)
continue; continue;
let cmd = fs.readfile("/proc/" + pid + "/cmdline"); let cmd = fs.readfile("/proc/" + pid + "/cmdline");
if (cmd && index(cmd, "check") >= 0) if (cmd && (index(cmd, "check") >= 0 || (process_name == "sing-box" && index(cmd, "run") < 0)))
continue; continue;
let status = fs.readfile("/proc/" + pid + "/status"); let status = fs.readfile("/proc/" + pid + "/status");
if (!status) if (!status)
@@ -22,7 +22,6 @@ let fixture_uci_data = null;
let runtime_settings_cache = null; let runtime_settings_cache = null;
let runtime_ruleset_folder = runtime_constants.TMP_RULESET_FOLDER; let runtime_ruleset_folder = runtime_constants.TMP_RULESET_FOLDER;
let runtime_supports_xhttp = true; let runtime_supports_xhttp = true;
let HOSTS_CACHE_FILE = "/etc/tachyon/hosts-lists/combined.txt";
let as_string = common.as_string; let as_string = common.as_string;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
@@ -459,55 +458,6 @@ function base_config(settings, service_address, runtime_context) {
} }
} }
let hosts_cache_st = fs.stat(HOSTS_CACHE_FILE);
if (hosts_cache_st != null && int(hosts_cache_st.size) > 0) {
let fh = null;
try {
fh = fs.open(HOSTS_CACHE_FILE, "r");
if (fh != null) {
let line;
while ((line = fh.read("line")) != null) {
line = trim(line);
if (line == "" || substr(line, 0, 1) == "#")
continue;
let parts = split(line, /[ \t]+/);
if (length(parts) >= 2) {
let p1 = parts[0];
let p2 = parts[1];
if (core_ip.valid_ip(p1)) {
let ip = p1;
let rr_type = index(ip, ":") != -1 ? "AAAA" : "A";
for (let i = 1; i < length(parts); i++) {
let d = parts[i];
if (d != "" && substr(d, 0, 1) != "#" && index(d, ":") == -1) {
push(dns_hosts_predefined, {
action: "predefined",
domain: [d],
answer: [d + ". 60 IN " + rr_type + " " + ip]
});
}
}
} else if (core_ip.valid_ip(p2)) {
let domain = p1;
let ip = p2;
if (index(domain, ":") == -1) {
let rr_type = index(ip, ":") != -1 ? "AAAA" : "A";
push(dns_hosts_predefined, {
action: "predefined",
domain: [domain],
answer: [domain + ". 60 IN " + rr_type + " " + ip]
});
}
}
}
}
}
} catch(e) {
warn("Error reading hosts cache: ", as_string(e), "\n");
}
if (fh) fh.close();
}
for (let rule in dns_config.rules) for (let rule in dns_config.rules)
push(dns_rules, rule); push(dns_rules, rule);
for (let rule in [ for (let rule in [
+3 -3
View File
@@ -369,7 +369,7 @@ function owner_pid() {
function managed_service_installed() { function managed_service_installed() {
let data = fs.readfile("/etc/init.d/sing-box"); let data = fs.readfile("/etc/init.d/sing-box");
return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC") >= 0; return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC=\"50\"") >= 0;
} }
function managed_service_text() { function managed_service_text() {
@@ -381,7 +381,7 @@ function managed_service_text() {
"start_service() {\n" + "start_service() {\n" +
" config_load \"sing-box\"\n" + " config_load \"sing-box\"\n" +
" local enabled config_file working_directory\n" + " local enabled config_file working_directory\n" +
" local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n\n" + " local log_stderr\n\n" +
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" + " config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
" [ \"$enabled\" -eq \"1\" ] || return 0\n\n" + " [ \"$enabled\" -eq \"1\" ] || return 0\n\n" +
" config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" + " config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" +
@@ -393,7 +393,7 @@ function managed_service_text() {
" procd_set_param stderr \"$log_stderr\"\n" + " procd_set_param stderr \"$log_stderr\"\n" +
" procd_set_param limits core=\"unlimited\"\n" + " procd_set_param limits core=\"unlimited\"\n" +
" procd_set_param limits nofile=\"1000000 1000000\"\n" + " procd_set_param limits nofile=\"1000000 1000000\"\n" +
" procd_set_param env GODEBUG=\"madvdontneed=1\"\n" + " procd_set_param env GODEBUG=\"madvdontneed=1\" GOGC=\"50\"\n" +
" procd_set_param term_timeout 15\n" + " procd_set_param term_timeout 15\n" +
" procd_set_param respawn\n" + " procd_set_param respawn\n" +
" procd_close_instance\n" + " procd_close_instance\n" +