-
perf(metrics): scan the OS once per tick; cache every static fact the collectors used to re-read
Release / version (push) Canceled after 0sRelease / frontend (push) Canceled after 0sRelease / linux (amd64) (push) Canceled after 0sRelease / linux (arm64) (push) Canceled after 0sRelease / windows (push) Canceled after 0sRelease / macos (push) Canceled after 0sRelease / release (push) Canceled after 0sBuild and Push Docker Image / build-and-push (push) Canceled after 0sreleased this
2026-09-08 21:09:46 +03:00 | 64 commits to main since this releaseThe metrics tick collected every module twice on persist cycles (CollectAndSave
per module, then CollectAllCurrent for the live fan-out) and the collectors
re-derived static facts on every pass. Measured under strace on Linux: 208
traced syscalls per tick before, 26 after, with the same payloads.Pipeline
- One system.Snapshot per tick: history asks the system service for a single
parallel pass and hands the same value to the DB writer (persist ticks), the
SSE broker, the cluster metric stream and the Prometheus exporter. Concurrent
CollectSnapshot calls coalesce (ticker + on-demand GET /metrics/current), so
two passes can no longer interleave inside the network/CPU rate baselines. - GET /metrics/current serves the latest snapshot while younger than one tick.
- The SSE body is marshaled once from the struct (no marshal→unmarshal→marshal
to inject collecting_host_id); the host row comes from the last registration
instead of two GetCurrentHost round-trips (8 SELECTs) per tick. - WireGate hashes the docker inventory off the struct; on an idle tick the
docker payload is never marshaled for the wire at all. - Prometheus exports the tick's snapshot instead of re-sampling every collector
(which also reset the SSE stream's network rate baseline).
Collectors
- cpu: cpu.Info (1 + N-cpus file opens, only [0] used) cached, 10-min refresh.
- memory: host paths resolved once; the sysfs memory-block walk (one file per
128 MB block) cached 10 min; swap reuses the meminfo parse. - disk: mount table cached 60 s; pseudo filesystems skipped BEFORE statfs
(node_exporter's default exclude lists); statfs behind a watchdog with a
stuck-mount set so a dead network mount can't wedge the tick; Linux reads
/proc/diskstats directly and refreshes serial/label (two udev scans per
device per call in gopsutil) every 10 min. - network + hosts: addresses/MACs/primary route from a shared 60-s topology
cache (hostnet.CurrentTopology) with early refresh when a new interface name
appears; gopsutil's net.Interfaces was one netlink dump per interface per tick.
Counter rollback (interface re-created) re-baselines instead of wrapping. - hosts: OS identity (host.Info forks lsb_release and lists /proc) cached an
hour; boot time cached via gopsutil's opt-in. - sensors: new internal/platform/hwsensors — one cached, time-bounded read per
tick shared by the cpu collector and the sensors endpoint (the cpu collector
also retried the identical call on a warning). Linux discovers the hwmon file
set once and re-reads only temp*_input with a fixed-buffer read(2).
Docker
- Inspect details cached per container (key = state|created, 5-min resync):
one ContainerList + one one-shot stats per running container per tick
instead of N extra inspects for values fixed per container lifecycle. - Image-check targets built only when the hourly check is due; gateway route
source read at most every 30 s; debug dump loops gated on the log level.
Verified on the native macOS binary, a Docker instance on the rebuilt image
(host-mounted /proc,/sys,/ paths) and the live nsdemo stack: one collection per
10 s in the logs, REST/SSE payloads unchanged, the machines/stats/containers/
application pages render and update live over SSE.Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com
Downloads
- One system.Snapshot per tick: history asks the system service for a single