Observability#
This document describes how to monitor and observe a running Mooncake Store deployment.
Master Metrics Log#
When started, the Mooncake master periodically prints a metrics summary log every 10 seconds (configurable via kMetricReportIntervalSeconds). This log provides a comprehensive snapshot of the master’s runtime state.
Log Format#
I0512 15:03:30.321475 239489 rpc_service.cpp:269] Master Admin Metrics: role=leader, state=serving, service_ready=true, master={...}, ha={...}, leader=127.0.0.1:50051, view_version=1
Each log line contains:
GLog header: timestamp, thread ID, source file and line number
role: HA role —
leaderorstandbystate: HA runtime state —
serving,starting,stopping, etc.service_ready: whether the gRPC service is accepting requests
master: master metrics block (see below)
ha: HA metrics block
leader: (only when available) the current leader address and view version
Master Metrics Block#
A typical master={...} block looks like this:
Mem Storage: 94.09 MB / 100.00 MB (94.1%) | SSD Storage: 0 B / 0 B | Keys: 16058 (soft-pinned: 0) | Clients: 1 | Requests (Success/Total per sec): PutStart=0.00/0.00, PutEnd=0.00/0.00, PutRevoke=0.00/0.00, Get=0.00/0.00, Exist=0.00/0.00, Del=0.00/0.00, DelAll=0.00/0.00, Ping=1.00/1.00, CopyStart=0.00/0.00, CopyEnd=0.00/0.00, CopyRevoke=0.00/0.00, MoveStart=0.00/0.00, MoveEnd=0.00/0.00, MoveRevoke=0.00/0.00, EvictDiskReplica=0.00/0.00 | Batch Requests (per sec, Req=Success/PartialSuccess/Total, Item=Success/Total): PutStart:(Req=0.00/0.00/0.00, Item=0.00/0.00), PutEnd:(Req=0.00/0.00/0.00, Item=0.00/0.00), PutRevoke:(Req=0.00/0.00/0.00, Item=0.00/0.00), Get:(Req=0.00/0.00/0.00, Item=0.00/0.00), ExistKey:(Req=0.00/0.00/0.00, Item=0.00/0.00), QueryIp:(Req=0.00/0.00/0.00, Item=0.00/0.00), Clear:(Req=0.00/0.00/0.00, Item=0.00/0.00), CreateMoveTask:(Req=0.00/0.00), CreateCopyTask:(Req=0.00/0.00), QueryTask:(Req=0.00/0.00), FetchTasks:(Req=0.00/0.00), MarkTaskToComplete:(Req=0.00/0.00) | Eviction: Success/Attempts=0/0, AllocFail=0, keys=0, size=0 B | Discard: Released/Total=0/0, StagingSize=0 B | Snapshots: Success=0, Fail=0
Request counters are reported as rates per second over the time window between two consecutive log outputs (10 seconds by default). Real-time state values (storage, key count, client count, discard staging size) are not rate-limited and reflect the current value at log time.
The metrics block consists of the following sections:
Storage#
Field |
Description |
|---|---|
|
Current memory usage / total memory capacity, with percentage |
|
Current SSD-backed storage usage / total SSD capacity |
Keys and Clients#
Field |
Description |
|---|---|
|
Total number of keys managed by the master |
|
Number of keys with active soft-pin leases (protected from eviction) |
|
Number of currently connected clients |
Requests (Success/Total per sec)#
Rate counters for individual (non-batch) RPC requests over the last time window. Each shows <success_rate>/<total_rate> in requests per second:
Counter |
Description |
|---|---|
|
Put object allocation requests |
|
Put object commit requests |
|
Put object cancellation requests |
|
Get replica list requests |
|
Key existence check requests |
|
Single key deletion requests |
|
Delete-all objects requests |
|
Client heartbeat/ping requests |
|
Copy object allocation requests |
|
Copy object commit requests |
|
Copy object cancellation requests |
|
Move object allocation requests |
|
Move object commit requests |
|
Move object cancellation requests |
|
Evict disk replica requests |
Batch Requests (per sec)#
Batch operations aggregate multiple items into a single RPC. Rates are per second over the last time window. Format: Req=<success>/<partial_success>/<total>, Item=<success_items>/<total_items>:
Counter |
Description |
|---|---|
|
Batch put object allocation requests |
|
Batch put object commit requests |
|
Batch put object cancellation requests |
|
Batch get replica list requests |
|
Batch key existence check requests |
|
Batch query IP requests |
|
Batch replica clear requests |
A request is considered “partial success” when it succeeds for some items but not all.
Task Operations#
Counter |
Description |
|---|---|
|
Move task creation requests |
|
Copy task creation requests |
|
Task status query requests |
|
Pending task fetch requests (polled by store clients) |
|
Task completion acknowledgement requests |
Eviction & Discard#
Eviction counters are deltas between two consecutive log outputs — they show what happened in the time window, not cumulative totals.
Field |
Description |
|---|---|
|
Eviction rounds that succeeded at least partially vs. total attempts in this window |
|
Number of PutStart/UpsertStart failures caused by replica allocation failure (triggers eviction) in this window |
|
Number of keys evicted in this window |
|
Total size of evicted data in this window |
|
Released (cleaned up) vs. total discarded PutStart staging replicas (live values) |
|
Current size of discarded but not-yet-released staging buffers (live value) |
Prometheus Metrics Endpoint#
Mooncake master exposes Prometheus-format metrics at the HTTP admin endpoint. This allows integration with Prometheus, Grafana, or any Prometheus-compatible monitoring stack.
Endpoints#
The admin HTTP server runs on metrics_port (default: 9003) and exposes the following endpoints:
Endpoint |
Content-Type |
Description |
|---|---|---|
|
|
All metrics in Prometheus exposition format |
|
|
Human-readable summary (same content as the periodic log) |
|
|
Health check with role, HA state, and service readiness |
|
|
Master version ( |
|
|
Current HA role ( |
|
|
Current HA runtime state ( |
Usage#
Scrape the /metrics endpoint with Prometheus:
Add a scrape config to your prometheus.yml:
scrape_configs:
- job_name: 'mooncake-master'
static_configs:
- targets: ['<master-host>:9003']
metrics_path: '/metrics'
Quick check with curl:
# Get Prometheus metrics
curl http://<master-host>:9003/metrics
# Get human-readable summary
curl http://<master-host>:9003/metrics/summary
# Check health
curl http://<master-host>:9003/health
# Check version
curl http://<master-host>:9003/version
Configuration#
The admin HTTP server is configured in the master config file (master.json or master.yaml):
{
"enable_metric_reporting": true,
"metrics_port": 9003,
...
}
Set enable_metric_reporting to false to disable the periodic metrics log. HTTP endpoints (/metrics, /health, etc.) remain available regardless of this setting.
Process and Allocator Memory Metrics#
Both /metrics endpoints export the resident set size of the serving process,
so memory growth can be read from Mooncake itself rather than correlated
against a container-level metric.
Metric |
Type |
Source |
|---|---|---|
|
gauge |
|
|
gauge |
|
|
gauge |
|
|
gauge |
|
|
gauge |
|
These come from /proc/self/status and are exported whichever allocator the
binary is linked against, so they stay comparable across an allocator change.
When the binary is built with -DSTORE_USE_JEMALLOC=ON (see below),
mooncake_jemalloc_enabled reports 1 and the allocator’s own accounting is
exported alongside: allocated / active / metadata / resident /
retained / mapped / dirty / muzzy bytes, arena and background-thread
counts, the opt.dirty_decay_ms and opt.muzzy_decay_ms settings, and
cumulative purge counters (mooncake_jemalloc_dirty_purge_runs_total,
..._dirty_madvises_total, and the muzzy equivalents). Dirty and muzzy are
reported separately because jemalloc decays them on separate paths.
mooncake_jemalloc_resident_bytes / mooncake_jemalloc_allocated_bytes is the
ratio to watch: it is how much memory the allocator holds beyond what the
application asked for. To attribute that ratio to a specific allocation size,
mooncake_jemalloc_bin_regs, ..._bin_slabs, ..._bin_used_bytes and
..._bin_slab_bytes break it down per small size class, labelled by
size_class. A slab is returned to the OS only once every region in it is
free, so a class with low bin_used_bytes / bin_slab_bytes occupancy is
holding pages it cannot release.
Note that mooncake_jemalloc_resident_bytes is the allocator’s own upper
estimate over the extents it maps and can exceed mooncake_process_rss_bytes;
compare the two for divergence rather than subtracting them.
When the binary is not built with jemalloc, mooncake_jemalloc_enabled reports
0, no mooncake_jemalloc_* values or per-size-class series are emitted, and
the process series above still export.
Building with jemalloc#
STORE_USE_JEMALLOC is off by default. It links jemalloc into the
mooncake_master and mooncake_client executables only, never into
libmooncake_store, so the Python extension keeps its host process’s
allocator:
cmake .. -DSTORE_USE_JEMALLOC=ON
Both executables are stripped at link time, so each logs the jemalloc version,
background_thread state and both decay settings at startup. That line is the
way to confirm on a release binary that the allocator was actually replaced.
Client Metrics Endpoint#
Mooncake clients can also expose a client-local HTTP endpoint for health checks and client metrics. This is separate from the master admin endpoint above and is disabled by default for Python/programmatic clients.
Enable it through the Python setup arguments:
store.setup(
local_hostname,
metadata_server,
global_segment_size,
local_buffer_size,
protocol,
rdma_devices,
master_server_addr,
enable_client_http_server=True,
client_http_port=9300,
)
For mooncake.mooncake_store_service, set
MOONCAKE_ENABLE_CLIENT_HTTP_SERVER=true and optionally
MOONCAKE_CLIENT_HTTP_PORT=<port>. For the standalone mooncake_client, use
--enable_http_server=true --http_port=<port>.
Endpoint |
Content-Type |
Description |
|---|---|---|
|
|
Client health check |
|
|
Prometheus-format client metrics |
|
|
Human-readable client metrics summary |
|
|
Client version ( |
curl http://<client-host>:9300/health
curl http://<client-host>:9300/metrics
curl http://<client-host>:9300/metrics/summary
curl http://<client-host>:9300/version
{"version":"2.0.0","display_version":"0.3.12.post1 (git: f9e8311f)"}
/version does not depend on client metric collection or on a fully
initialized client, so it stays available whenever the client HTTP server is
running.
Set MC_STORE_CLIENT_METRIC=0 to disable client metric collection. If the
client HTTP server remains enabled while metrics are disabled, /metrics and
/metrics/summary return HTTP 503 with metrics not available.
Master heartbeat observations#
Clients running the storage heartbeat expose two gauges through /metrics:
Metric |
Meaning |
|---|---|
|
Last observed Ping status: |
|
Client-side Unix receive time, in seconds, of the same observation. |
Both samples carry the existing client labels. They are absent before the first
valid heartbeat, after a failed heartbeat or an unsupported status, and while
reconnecting. Late responses from an older connection cannot restore the
observation. A successful remount alone does not set the status to 1; a later
Ping must return OK.
A client without storage may never start this heartbeat. Memory or LocalDisk
mounts and DFS backend activation start the storage control plane; creating a
request-only client does not. Missing samples mean unknown or inapplicable,
not NEED_REMOUNT. Disabling client metrics also disables these observations.
The timestamp is an observation value, not a Prometheus sample timestamp. An
in-flight Ping can leave the previous observation visible until it completes,
so check its age as well as its status. For example, for targets expected to
run a storage heartbeat, this query selects a recent NEED_REMOUNT observation
using an illustrative 10-second freshness limit:
(mooncake_client_master_heartbeat_status_ok == 0)
and
((time() - mooncake_client_master_heartbeat_observation_timestamp_seconds) < 10)
Choose the freshness limit for the heartbeat/RPC timeouts and scrape interval
in your deployment, and account for clock skew. Do not replace missing status
samples with zero. Prometheus up describes the HTTP scrape, not Master Ping
success; missing or stale observations need separate handling.
This is a sampled control-plane response. OK does not prove that every
segment is mounted, that transfer metadata or SSD recovery is complete, or
that data RPCs and RDMA transfers are healthy. The existing /health check
can remain healthy when a successful Ping returns NEED_REMOUNT.