kai-server k3s datastore answers every operation in ~190ms at only 9 requests/second #845
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#845
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The k3s datastore on kai-server is roughly 40x slower than a local backend should be, and the latency is nearly identical across operation shapes that should differ enormously. Request volume is low, so this is a latency problem rather than a load problem.
Split out of #839, which was closed because its CPU premise turned out to be a measurement error. This finding is real and independent of that.
Current rate and latency
Measured as a delta between two
/metricsscrapes 79 seconds apart, so these are current values and not lifetime averages:Total load is about 9.4 requests per second. For a local backend, single-digit milliseconds is the expectation.
The uniformity is the interesting part
A point
getand alistWithCountdo completely different amounts of work. Agetis a single indexed row lookup.listWithCountis a scan plus an aggregate. They land 39ms apart, and every operation type sits in a 176ms to 227ms band.That shape does not look like disk seek time or query cost, both of which would spread widely across those operations. It looks like a fixed per-request cost sitting in front of the actual work: a serialization point, a lock, a batching interval, or a round trip.
Not an external datastore
The obvious explanation for a uniform fixed cost would be a network round trip to an external datastore. It is not that. There is no
--datastore-endpointanywhere in this repository, so k3s is on its default local sqlite via kine, on the node's NVMe.Lifetime totals for scale
Lifetime averages are somewhat better than current (135ms vs 176ms for
get), so this may be gradually degrading. Worth confirming rather than assuming, since it rests on two data points.Suggested investigation
coilyco-flight-deck/node-stats-mcp#23.etcd_request_errors_totaland the duration histogram buckets, to see whether this is a uniform shift or a bimodal distribution being flattened by averaging.Why it may not be urgent
Nothing is currently starved. Node CPU pressure stall
fullis 0.00%, andk3s-serverdraws 2.06 cores against a 2.34 core lifetime average. Roughly 1.8 datastore requests are in flight at any moment, which the system absorbs. This is headroom being quietly consumed rather than an active incident, and it would become an incident under a burst.Raw evidence
Recording the underlying counters so the derived numbers above can be checked without re-deriving them.
Method
Two scrapes of the k3s metrics endpoint, 79 seconds apart. Reachable read-only through the guarded surface:
Timestamps:
t1=1786826663,t2=1786826742, sodt=79s.Raw datastore counters
etcd_request_duration_seconds_{sum,count}, aggregated across alltypelabels for eachoperation:Derivation for
get:(2713250.0 - 2713170.0) / (20071052 - 20070597)=80.0 / 455= 175.8ms, over455 / 79= 5.8 req/sec. The other rows follow the same arithmetic.CPU counters, for the record
These belong to the closed #839 but are the basis for the "not CPU-starved" note above, so they are worth keeping next to the latency numbers.
Delta
162.66cpu-seconds over79s= 2.06 cores current. Lifetime3618607 / (now - 1785280297)= 2.34 cores over 17.9 days uptime.I checked the sample ordering explicitly rather than trusting output order, since a monotonic counter appearing to decrease would have meant a process restart and invalidated the whole calculation. File mtimes confirm
m1at 1786826663 andm2at 1786826742, and the counter increases between them.Supporting observations
Concurrent watches by resource, from
apiserver_longrunning_requests:Not investigated
Per the earlier list and deliberately left open: the duration histogram buckets, whether kine compaction is running, and the datastore file and WAL size (still blocked on
coilyco-flight-deck/node-stats-mcp#23).