fix(perf): eliminate 50k hosts DNS rules CPU lockup, optimize UI polling & memory limits
This commit is contained in:
@@ -4,7 +4,7 @@ import { logger } from './logger.service';
|
||||
import { applyUiStateToStore } from './uiState.service';
|
||||
|
||||
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;
|
||||
// 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
|
||||
|
||||
@@ -6629,7 +6629,7 @@ function applyUiStateToStore(uiState) {
|
||||
|
||||
// src/tachyon/services/runtimeUiState.service.ts
|
||||
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_HIDDEN_POLL_INTERVAL_MS = 3e4;
|
||||
var runtimeUiStateRefreshPromise = null;
|
||||
|
||||
@@ -857,7 +857,7 @@ function clear_version_caches() {
|
||||
|
||||
function managed_sing_box_service_installed() {
|
||||
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() {
|
||||
@@ -869,7 +869,7 @@ function managed_sing_box_service_text() {
|
||||
"start_service() {\n" +
|
||||
" config_load \"sing-box\"\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" +
|
||||
" [ \"$enabled\" -eq \"1\" ] || return 0\n\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 limits core=\"unlimited\"\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 respawn\n" +
|
||||
" procd_close_instance\n" +
|
||||
|
||||
@@ -2082,7 +2082,7 @@ function managed_sing_box_service_script(marker) {
|
||||
"start_service() {\n" +
|
||||
" config_load \"sing-box\"\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" +
|
||||
" config_get_bool enabled \"main\" \"enabled\" \"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 limits core=\"unlimited\"\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 respawn\n" +
|
||||
" procd_close_instance\n" +
|
||||
|
||||
@@ -2898,25 +2898,12 @@ function run_doctor_checks_impl(repair) {
|
||||
} else if (free_mb >= 0) {
|
||||
issues++;
|
||||
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) {
|
||||
doc_plan(sprintf("scale GOMEMLIMIT to %.2f + service restart", new_scale));
|
||||
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), sprintf("→ WILL FIX (doctor --fix): GOMEMLIMIT будет снижен до %.2f", new_scale));
|
||||
doc_plan("drop OS caches + sing-box restart");
|
||||
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ WILL FIX (doctor --fix): сброс кэшей памяти и перезапуск sing-box");
|
||||
} else {
|
||||
fs.mkdir("/etc/tachyon");
|
||||
let scale_tmp = scale_path + ".tmp";
|
||||
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));
|
||||
command_status("sync; echo 3 > /proc/sys/vm/drop_caches 2>/dev/null; /etc/init.d/sing-box restart >/dev/null 2>&1");
|
||||
doc_check("⚠️", "Free RAM", sprintf("%dMB", free_mb), "→ FIXED: кэши памяти сброшены, sing-box перезапущен");
|
||||
fixed++;
|
||||
}
|
||||
} else {
|
||||
@@ -3013,30 +3000,16 @@ function run_doctor_checks_impl(repair) {
|
||||
issues++;
|
||||
let oom_victim_singbox = index(lc(logread_out), "killed process") >= 0 &&
|
||||
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) {
|
||||
doc_plan(sprintf("scale GOMEMLIMIT to %.2f", new_scale));
|
||||
doc_plan("clear system log + drop OS caches");
|
||||
doc_check("❌", "System OOM checks",
|
||||
oom_victim_singbox ? "OOM detected, sing-box was killed" : sprintf("OOM detected (current scale: %.2f)", scale),
|
||||
sprintf("→ WILL FIX (doctor --fix): GOMEMLIMIT будет снижен до %.2f", new_scale));
|
||||
oom_victim_singbox ? "OOM detected, sing-box was killed" : "OOM detected in system logs",
|
||||
"→ WILL FIX (doctor --fix): очистка логов и сброс кэшей памяти");
|
||||
} else {
|
||||
fs.mkdir("/etc/tachyon");
|
||||
let scale_tmp2 = scale_path + ".tmp";
|
||||
if (fs.writefile(scale_tmp2, sprintf("%.2f", new_scale)) != null)
|
||||
fs.rename(scale_tmp2, scale_path);
|
||||
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");
|
||||
doc_check("❌", "System OOM checks",
|
||||
oom_victim_singbox ? "OOM detected, sing-box was killed" : sprintf("OOM detected (current scale: %.2f)", scale),
|
||||
sprintf("→ FIXED: Scaled GOMEMLIMIT to %.2f", new_scale));
|
||||
oom_victim_singbox ? "OOM detected, sing-box was killed" : "OOM detected in system logs",
|
||||
"→ FIXED: журналы сброшены, кэши памяти освобождены");
|
||||
fixed++;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1053,7 +1053,7 @@ function process_memory_rss_mb(process_name) {
|
||||
if (!pid || match(pid, /^[0-9]+$/) == null)
|
||||
continue;
|
||||
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;
|
||||
let status = fs.readfile("/proc/" + pid + "/status");
|
||||
if (!status)
|
||||
|
||||
@@ -22,7 +22,6 @@ let fixture_uci_data = null;
|
||||
let runtime_settings_cache = null;
|
||||
let runtime_ruleset_folder = runtime_constants.TMP_RULESET_FOLDER;
|
||||
let runtime_supports_xhttp = true;
|
||||
let HOSTS_CACHE_FILE = "/etc/tachyon/hosts-lists/combined.txt";
|
||||
|
||||
let as_string = common.as_string;
|
||||
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)
|
||||
push(dns_rules, rule);
|
||||
for (let rule in [
|
||||
|
||||
@@ -369,7 +369,7 @@ function owner_pid() {
|
||||
|
||||
function managed_service_installed() {
|
||||
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() {
|
||||
@@ -381,7 +381,7 @@ function managed_service_text() {
|
||||
"start_service() {\n" +
|
||||
" config_load \"sing-box\"\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" +
|
||||
" [ \"$enabled\" -eq \"1\" ] || return 0\n\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 limits core=\"unlimited\"\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 respawn\n" +
|
||||
" procd_close_instance\n" +
|
||||
|
||||
Reference in New Issue
Block a user