优化内存统计

This commit is contained in:
imengying committed 2026-09-10 17:19:38 +08:00
1 parent 1edc6de499
commit 1c3217f72c
10 files changed
+595 -123

No files matched your search

+26 -23
View File
@@ -62,28 +62,25 @@ cleanup_agent_install() {
if [ "$rollback_agent" = true ]; then
rollback_agent=false
log "安装未完成,正在恢复上一版本"
case "$init_system" in
systemd) systemctl stop "$SERVICE_NAME" 2>/dev/null || true ;;
openrc) rc-service "$SERVICE_NAME" stop 2>/dev/null || true ;;
esac
stop_agent || { printf '错误:旧服务未停止,回滚备份已保留在 %s\n' "$STATE_DIR" >&2; return 1; }
if [ "$had_agent" = true ]; then
cp -p "$backup_agent" "$AGENT_FILE" 2>/dev/null || true
cp -p "$backup_agent" "$AGENT_FILE" || return 1
else
rm -f "$AGENT_FILE"
rm -f "$AGENT_FILE" || return 1
fi
service_path=$SERVICE_FILE
[ "$init_system" != openrc ] || service_path=$OPENRC_FILE
if [ "$had_service" = true ]; then
cp -p "$backup_service" "$service_path" 2>/dev/null || true
cp -p "$backup_service" "$service_path" || return 1
else
rm -f "$service_path"
rm -f "$service_path" || return 1
fi
case "$init_system" in
systemd)
systemctl daemon-reload 2>/dev/null || true
[ "$had_agent" != true ] || systemctl restart "$SERVICE_NAME" 2>/dev/null || true
systemctl daemon-reload || return 1
[ "$had_service" != true ] || systemctl restart "$SERVICE_NAME" || return 1
;;
openrc) [ "$had_agent" != true ] || rc-service "$SERVICE_NAME" restart 2>/dev/null || true ;;
openrc) [ "$had_service" != true ] || rc-service "$SERVICE_NAME" restart || return 1 ;;
esac
fi
[ -z "$temporary" ] || rm -f "$temporary"
@@ -143,6 +140,22 @@ ensure_not_agent_service() {
done < "/proc/$$/cgroup"
}
stop_agent() {
case "$init_system" in
systemd)
[ -f "$SERVICE_FILE" ] || return 0
systemctl stop "$SERVICE_NAME" || return 1
stopped_pid=$(systemctl show -p MainPID --value "$SERVICE_NAME") || return 1
[ "$stopped_pid" = 0 ]
;;
openrc)
[ -f "$OPENRC_FILE" ] || return 0
rc-service "$SERVICE_NAME" stop || return 1
! rc-service "$SERVICE_NAME" status >/dev/null 2>&1
;;
esac
}
verify_agent_started() {
started_pid=$(systemctl show -p MainPID --value "$SERVICE_NAME") || return 1
case "$started_pid" in ''|*[!0-9]*|0) return 1 ;; esac
@@ -329,19 +342,8 @@ install_agent() {
cp -p "$service_path" "$backup_service"
had_service=true
fi
stop_agent || fail "无法停止已有 Agent 服务,未替换程序"
rollback_agent=true
case "$init_system" in
systemd)
systemctl stop "$SERVICE_NAME" 2>/dev/null || {
[ "$had_service" = false ] || fail "无法停止已有 Agent 服务,未替换程序"
}
;;
openrc)
rc-service "$SERVICE_NAME" stop 2>/dev/null || {
[ "$had_service" = false ] || fail "无法停止已有 Agent 服务,未替换程序"
}
;;
esac
mv "$temporary" "$AGENT_FILE"
log "正在启动 $init_system 服务"
if [ "$init_system" = "systemd" ]; then
@@ -467,6 +469,7 @@ uninstall_agent() {
log "正在停止并移除 Agent 服务"
init_system=$(detect_init_system)
ensure_not_agent_service
stop_agent || fail "无法停止已有 Agent 服务,已取消卸载"
case "$init_system" in
systemd) systemctl disable --now "$SERVICE_NAME" 2>/dev/null || true ;;
openrc)
+15 -9
View File
@@ -39,17 +39,17 @@ cleanup_agent_install() {
if [ "$rollback_agent" = true ]; then
rollback_agent=false
log "安装未完成,正在恢复上一版本"
service "$SERVICE_NAME" stop 2>/dev/null || true
stop_agent || { printf '错误:旧服务未停止,回滚备份已保留在 %s\n' "$STATE_DIR" >&2; return 1; }
if [ "$had_agent" = true ]; then
cp -p "$backup_agent" "$AGENT_FILE" 2>/dev/null || true
cp -p "$backup_agent" "$AGENT_FILE" || return 1
else
rm -f "$AGENT_FILE"
rm -f "$AGENT_FILE" || return 1
fi
if [ "$had_service" = true ]; then
cp -p "$backup_service" "$SERVICE_FILE" 2>/dev/null || true
service "$SERVICE_NAME" start 2>/dev/null || true
cp -p "$backup_service" "$SERVICE_FILE" || return 1
service "$SERVICE_NAME" start || return 1
else
rm -f "$SERVICE_FILE"
rm -f "$SERVICE_FILE" || return 1
fi
fi
[ -z "$temporary" ] || rm -f "$temporary"
@@ -57,6 +57,13 @@ cleanup_agent_install() {
[ -z "$backup_service" ] || rm -f "$backup_service"
}
stop_agent() {
[ -f "$SERVICE_FILE" ] || return 0
service "$SERVICE_NAME" onestatus >/dev/null 2>&1 || return 0
service "$SERVICE_NAME" onestop || return 1
! service "$SERVICE_NAME" onestatus >/dev/null 2>&1
}
usage() {
cat <<'EOF'
NodeFlare Agent FreeBSD 安装脚本
@@ -269,10 +276,9 @@ if [ -f "$SERVICE_FILE" ]; then
cp -p "$SERVICE_FILE" "$backup_service"
had_service=true
fi
rollback_agent=true
log "正在启动 FreeBSD rc.d 服务"
service "$SERVICE_NAME" stop 2>/dev/null || true
stop_agent || fail "无法停止已有 Agent 服务,未替换程序"
rollback_agent=true
mv "$temporary" "$AGENT_FILE"
cat > "$SERVICE_FILE" <<EOF
#!/bin/sh
+14 -8
View File
@@ -38,17 +38,17 @@ cleanup_agent_install() {
if [ "$rollback_agent" = true ]; then
rollback_agent=false
log "安装未完成,正在恢复上一版本"
launchctl bootout system "$PLIST_FILE" 2>/dev/null || true
stop_agent || { printf '错误:旧服务未停止,回滚备份已保留在 %s\n' "$STATE_DIR" >&2; return 1; }
if [ "$had_agent" = true ]; then
cp -p "$backup_agent" "$AGENT_FILE" 2>/dev/null || true
cp -p "$backup_agent" "$AGENT_FILE" || return 1
else
rm -f "$AGENT_FILE"
rm -f "$AGENT_FILE" || return 1
fi
if [ "$had_service" = true ]; then
cp -p "$backup_service" "$PLIST_FILE" 2>/dev/null || true
launchctl bootstrap system "$PLIST_FILE" 2>/dev/null || true
cp -p "$backup_service" "$PLIST_FILE" || return 1
launchctl bootstrap system "$PLIST_FILE" || return 1
else
rm -f "$PLIST_FILE"
rm -f "$PLIST_FILE" || return 1
fi
fi
[ -z "$temporary" ] || rm -f "$temporary"
@@ -56,6 +56,12 @@ cleanup_agent_install() {
[ -z "$backup_service" ] || rm -f "$backup_service"
}
stop_agent() {
launchctl print "system/$LABEL" >/dev/null 2>&1 || return 0
launchctl bootout system "$PLIST_FILE" || return 1
! launchctl print "system/$LABEL" >/dev/null 2>&1
}
usage() {
cat <<'EOF'
NodeFlare Agent macOS 安装脚本
@@ -247,9 +253,9 @@ if [ -f "$PLIST_FILE" ]; then
cp -p "$PLIST_FILE" "$backup_service"
had_service=true
fi
rollback_agent=true
log "正在启动 macOS LaunchDaemon 服务"
launchctl bootout system "$PLIST_FILE" 2>/dev/null || true
stop_agent || fail "无法停止已有 Agent 服务,未替换程序"
rollback_agent=true
mv "$temporary" "$AGENT_FILE"
cat > "$PLIST_FILE" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
+49 -27
View File
@@ -32,6 +32,7 @@ $HadPreviousConfig = $false
$HadPreviousLauncher = $false
$PreviousTaskXml = $null
$InstallChanged = $false
$KeepBackup = $false
function Write-Step([string]$Message) {
Write-Host $Message
@@ -41,6 +42,19 @@ function Write-InstallError([string]$Message) {
throw "错误:$Message"
}
function Stop-Agent {
$Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if ($null -ne $Task) { Stop-ScheduledTask -TaskName $TaskName -ErrorAction Stop }
for ($Attempt = 0; $Attempt -lt 30; $Attempt++) {
$Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
$Running = @(Get-CimInstance Win32_Process -Filter "Name = 'agent.exe'" -ErrorAction Stop |
Where-Object { $_.ExecutablePath -eq $AgentFile })
if (($null -eq $Task -or $Task.State -ne "Running") -and $Running.Count -eq 0) { return }
Start-Sleep -Milliseconds 500
}
Write-InstallError "旧 Agent 进程未退出,已停止操作,未替换程序"
}
function Show-InstallResult {
Write-Host ""
if ($Update -or $HadPreviousAgent) {
@@ -116,7 +130,7 @@ function Assert-Mirror([string]$Value) {
if ($Uninstall) {
Write-Step "正在停止并移除 Agent 服务"
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
Stop-Agent
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $AgentFile -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $LauncherFile -Force -ErrorAction SilentlyContinue
@@ -214,8 +228,8 @@ try {
if ($HadPreviousLauncher) { Copy-Item -LiteralPath $LauncherFile -Destination $PreviousLauncher -Force }
$ExistingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if ($null -ne $ExistingTask) { $PreviousTaskXml = Export-ScheduledTask -TaskName $TaskName }
Stop-Agent
$InstallChanged = $true
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
Move-Item -LiteralPath $Temporary -Destination $AgentFile -Force
$AgentConfig = [ordered]@{
@@ -245,7 +259,7 @@ exit $LASTEXITCODE
Write-Step "正在注册并启动 Windows 计划任务"
$TaskAction = New-ScheduledTaskAction -Execute $PowerShell -Argument $TaskArguments
$Trigger = New-ScheduledTaskTrigger -AtStartup
$Settings = New-ScheduledTaskSettingsSet -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit (New-TimeSpan -Days 3650)
$Settings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit (New-TimeSpan -Days 3650)
$Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName $TaskName -Action $TaskAction -Trigger $Trigger -Settings $Settings -Principal $Principal -Force | Out-Null
Start-ScheduledTask -TaskName $TaskName
@@ -261,34 +275,42 @@ exit $LASTEXITCODE
$InstallChanged = $false
Show-InstallResult
} catch {
$InstallError = $_
if ($InstallChanged) {
Write-Warning "安装未完成,正在恢复上一版本"
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
if ($HadPreviousAgent) {
Copy-Item -LiteralPath $PreviousAgent -Destination $AgentFile -Force
} else {
Remove-Item -LiteralPath $AgentFile -Force -ErrorAction SilentlyContinue
}
if ($HadPreviousConfig) {
Copy-Item -LiteralPath $PreviousConfig -Destination $ConfigFile -Force
} else {
Remove-Item -LiteralPath $ConfigFile -Force -ErrorAction SilentlyContinue
}
if ($HadPreviousLauncher) {
Copy-Item -LiteralPath $PreviousLauncher -Destination $LauncherFile -Force
} else {
Remove-Item -LiteralPath $LauncherFile -Force -ErrorAction SilentlyContinue
}
if ($null -ne $PreviousTaskXml) {
Register-ScheduledTask -TaskName $TaskName -Xml $PreviousTaskXml -Force | Out-Null
Start-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
try {
Stop-Agent
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
if ($HadPreviousAgent) {
Copy-Item -LiteralPath $PreviousAgent -Destination $AgentFile -Force
} else {
Remove-Item -LiteralPath $AgentFile -Force -ErrorAction SilentlyContinue
}
if ($HadPreviousConfig) {
Copy-Item -LiteralPath $PreviousConfig -Destination $ConfigFile -Force
} else {
Remove-Item -LiteralPath $ConfigFile -Force -ErrorAction SilentlyContinue
}
if ($HadPreviousLauncher) {
Copy-Item -LiteralPath $PreviousLauncher -Destination $LauncherFile -Force
} else {
Remove-Item -LiteralPath $LauncherFile -Force -ErrorAction SilentlyContinue
}
if ($null -ne $PreviousTaskXml) {
Register-ScheduledTask -TaskName $TaskName -Xml $PreviousTaskXml -Force | Out-Null
Start-ScheduledTask -TaskName $TaskName -ErrorAction Stop
}
} catch {
$KeepBackup = $true
Write-Warning "自动回滚未完成,备份已保留:$PreviousAgent,$PreviousConfig,$PreviousLauncher;$_"
}
}
throw
throw $InstallError
} finally {
Remove-Item -LiteralPath $Temporary -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $PreviousAgent -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $PreviousConfig -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $PreviousLauncher -Force -ErrorAction SilentlyContinue
if (-not $KeepBackup) {
Remove-Item -LiteralPath $PreviousAgent -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $PreviousConfig -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $PreviousLauncher -Force -ErrorAction SilentlyContinue
}
}
+112 -14
View File
@@ -679,9 +679,52 @@ fn mem_value(contents: &str, key: &str) -> i64 {
.lines()
.find(|line| line.starts_with(key))
.and_then(|line| line.split_whitespace().nth(1))
.and_then(|value| value.parse::<i64>().ok())
.unwrap_or(0)
.saturating_mul(1024)
.and_then(|value| value.parse::<u64>().ok())
.map_or(0, |value| u64_to_i64(value.saturating_mul(1024)))
}
#[cfg(target_os = "linux")]
struct MemorySample {
total: i64,
used: i64,
swap_total: i64,
swap_used: i64,
}
#[cfg(target_os = "linux")]
fn memory_sample(contents: &str) -> MemorySample {
let total = mem_value(contents, "MemTotal:");
let free = mem_value(contents, "MemFree:");
let reclaimable = free
.saturating_add(mem_value(contents, "Cached:"))
.saturating_add(mem_value(contents, "SReclaimable:"))
.saturating_add(mem_value(contents, "Buffers:"));
// Komari's default Linux/htop calculation excludes reclaimable caches but
// includes shared memory. MemAvailable uses a different kernel estimate.
let used = total
.saturating_sub(if reclaimable <= total {
reclaimable
} else {
free
})
.saturating_add(mem_value(contents, "Shmem:"))
.clamp(0, total);
let swap_total = mem_value(contents, "SwapTotal:");
let swap_free = mem_value(contents, "SwapFree:");
let swap_deductions = swap_free.saturating_add(mem_value(contents, "SwapCached:"));
let swap_used = swap_total
.saturating_sub(if swap_deductions <= swap_total {
swap_deductions
} else {
swap_free
})
.clamp(0, swap_total);
MemorySample {
total,
used,
swap_total,
swap_used,
}
}
#[cfg(target_os = "linux")]
@@ -1402,7 +1445,6 @@ fn average_gpu_usage(gpus: &[GpuMetric]) -> f64 {
}
}
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "freebsd"))]
fn u64_to_i64(value: u64) -> i64 {
value.min(i64::MAX as u64) as i64
}
@@ -1543,11 +1585,7 @@ impl Collector {
}
self.public_ip.refresh();
let mem = text("/proc/meminfo");
let mem_total = mem_value(&mem, "MemTotal:");
let mem_used = mem_total.saturating_sub(mem_value(&mem, "MemAvailable:"));
let swap_total = mem_value(&mem, "SwapTotal:");
let swap_used = swap_total.saturating_sub(mem_value(&mem, "SwapFree:"));
let memory = memory_sample(&text("/proc/meminfo"));
let loads = text("/proc/loadavg")
.split_whitespace()
.take(3)
@@ -1579,10 +1617,10 @@ impl Collector {
load1: loads.first().copied().unwrap_or(0.0),
load5: loads.get(1).copied().unwrap_or(0.0),
load15: loads.get(2).copied().unwrap_or(0.0),
mem_used,
mem_total,
swap_used,
swap_total,
mem_used: memory.used,
mem_total: memory.total,
swap_used: memory.swap_used,
swap_total: memory.swap_total,
disk_used,
disk_total,
net_in: per_second(io_now.rx.saturating_sub(io_before.rx), elapsed),
@@ -1788,7 +1826,11 @@ impl Collector {
load1: load.one,
load5: load.five,
load15: load.fifteen,
mem_used: u64_to_i64(self.system.used_memory()),
mem_used: u64_to_i64(
self.system
.total_memory()
.saturating_sub(self.system.available_memory()),
),
mem_total: u64_to_i64(self.system.total_memory()),
swap_used: u64_to_i64(self.system.used_swap()),
swap_total: u64_to_i64(self.system.total_swap()),
@@ -3857,6 +3899,62 @@ mod tests {
assert!(!super::excluded_filesystem("btrfs", "/var"));
}
#[cfg(target_os = "linux")]
#[test]
fn memory_matches_komari_default_including_shared_memory_and_swap_cache() {
let memory = super::memory_sample(
"MemTotal: 1000000 kB\nMemFree: 100000 kB\nMemAvailable: 750000 kB\n\
Cached: 300000 kB\nSReclaimable: 50000 kB\nBuffers: 25000 kB\n\
Shmem: 25000 kB\nSwapTotal: 100000 kB\nSwapFree: 60000 kB\nSwapCached: 20000 kB\n",
);
assert_eq!(memory.total, 1_000_000 * 1024);
assert_eq!(memory.used, 550_000 * 1024);
assert_eq!(memory.swap_total, 100_000 * 1024);
assert_eq!(memory.swap_used, 20_000 * 1024);
}
#[cfg(target_os = "linux")]
#[test]
fn filling_file_cache_does_not_inflate_reported_memory() {
let before = super::memory_sample(
"MemTotal: 1000 kB\nMemFree: 400 kB\nCached: 300 kB\n\
Buffers: 50 kB\nSReclaimable: 50 kB\nShmem: 100 kB\n",
);
let after = super::memory_sample(
"MemTotal: 1000 kB\nMemFree: 200 kB\nCached: 500 kB\n\
Buffers: 50 kB\nSReclaimable: 50 kB\nShmem: 100 kB\n",
);
assert_eq!(before.used, 300 * 1024);
assert_eq!(after.used, before.used);
}
#[cfg(target_os = "linux")]
#[test]
fn memory_handles_missing_and_inconsistent_kernel_counters() {
let memory = super::memory_sample(
"MemTotal: 1000 kB\nMemFree: 200 kB\nCached: 1000 kB\n\
Shmem: 100 kB\nSwapTotal: 100 kB\nSwapFree: 20 kB\nSwapCached: 100 kB\n",
);
assert_eq!(memory.used, 900 * 1024);
assert_eq!(memory.swap_used, 80 * 1024);
for contents in ["", "MemTotal: invalid kB\n", "MemTotal: -1 kB\n"] {
let memory = super::memory_sample(contents);
assert_eq!(
(
memory.total,
memory.used,
memory.swap_total,
memory.swap_used
),
(0, 0, 0, 0)
);
}
let memory = super::memory_sample(
"MemTotal: 100 kB\nMemFree: 1000 kB\nSwapTotal: 100 kB\nSwapFree: 1000 kB\n",
);
assert_eq!((memory.used, memory.swap_used), (0, 0));
}
#[cfg(target_os = "linux")]
#[test]
fn reads_local_mounts_and_decodes_escaped_paths_once() {