Skip to content

Metrics Reference

Every series the daemon exposes, grouped by subsystem. All names carry the flexblock_ prefix, which the tables below omit: cache_hits_total is flexblock_cache_hits_total in full. Histograms emit the usual _bucket, _sum and _count series in seconds, with 19 upper bounds from 5 microseconds to 5 seconds plus +Inf (see Metrics Endpoint).

Most series carry no labels. These do:

SeriesLabels
bridge_read_fallbacks_totalreason: chunk_crossing, miss, pages_invalid, raced, writer_active
bridge_write_fallbacks_totalreason: clean_hit, exclusive, miss, page_padding, read_pressure
build_infoversion
cache_policy_infopolicy: lru or twoq-meta
license_infolicense_id, customer, key_id, state: valid, grace, expired, uncovered, pending (unknown before the first grant)

What the filesystem or application on /dev/ublkbN sees.

SeriesTypeDescription
ublk_bytes_discarded_totalcounterBytes covered by guest DISCARD requests
ublk_bytes_read_totalcounterBytes returned to the guest by successful reads
ublk_bytes_written_totalcounterBytes accepted from the guest by successful writes
ublk_bytes_zeroed_totalcounterBytes covered by guest WRITE_ZEROES requests
ublk_discard_duration_secondshistogramGuest-visible DISCARD latency
ublk_discards_failed_totalcounterGuest DISCARD requests completed with an error
ublk_discards_totalcounterGuest DISCARD requests received
ublk_flush_duration_secondshistogramGuest-visible FLUSH latency, including the cache device sync
ublk_flushes_failed_totalcounterGuest FLUSH requests completed with an error
ublk_flushes_totalcounterGuest FLUSH requests received; not the same as flush_attempts_total, which counts uploads to object storage
ublk_fua_writes_totalcounterGuest writes carrying FUA; each is durable before it is acknowledged
ublk_metadata_ops_totalcounterGuest reads and writes the kernel tagged as filesystem metadata; under twoq-meta their chunks go straight to the protected Am tier
ublk_ops_failed_totalcounterGuest requests of every kind completed with an error
ublk_ops_unsupported_totalcounterGuest requests rejected as unsupported; non-zero means the kernel issued an operation the device does not advertise
ublk_read_duration_secondshistogramGuest-visible READ latency, including any license throttling
ublk_reads_failed_totalcounterGuest READ requests completed with an error
ublk_reads_totalcounterGuest READ requests received
ublk_write_duration_secondshistogramGuest-visible WRITE latency, including throttling and FUA syncs
ublk_write_zeroes_duration_secondshistogramGuest-visible WRITE_ZEROES latency
ublk_write_zeroes_failed_totalcounterGuest WRITE_ZEROES requests that failed
ublk_write_zeroes_totalcounterGuest WRITE_ZEROES requests received
ublk_writes_failed_totalcounterGuest WRITE requests that failed, FUA sync failures included
ublk_writes_totalcounterGuest WRITE requests received

Most guest I/O is served on a fast path straight from the cache device. Requests the fast path cannot serve, such as cache misses, are handed to a slower path (the “bridge”). These series show how much I/O takes that path and why.

SeriesTypeDescription
bridge_capacitygaugeMaximum guest requests the slow path serves at once: queues times queue depth
bridge_inflightgaugeGuest requests currently on the slow path
bridge_read_fallbacks_totalcounterGuest reads sent to the slow path, by reason: the request spans chunks, the chunk is not cached, its pages are not valid, a writer was active, or the read raced a writer
bridge_write_fallbacks_totalcounterGuest writes sent to the slow path, by reason: the chunk is cached but clean, a merge or discard needs it exclusively, it is not cached, page padding is needed, or a waiting reader overlaps the write

Hits, misses, occupancy and the cache replacement policy. The am_* and a1out_* series stay zero under the lru policy by design; see Cache Replacement Policy.

SeriesTypeDescription
cache_a1in_admissions_totalcounterChunks admitted to the probationary A1in tier; under lru this is every admission
cache_a1in_evictions_totalcounterChunks evicted from A1in to free a slot; under lru this is every eviction
cache_a1in_removals_totalcounterA1in entries dropped by discard, write rollback or recovery rather than eviction
cache_a1in_restored_totalcounterEntries placed into A1in by crash recovery
cache_a1in_sizegaugeEntries resident in A1in, dirty included
cache_a1out_expirations_totalcounterGhost identities in A1out that aged out without being reused
cache_a1out_forgotten_totalcounterA1out ghosts dropped by discard, removal or recovery
cache_a1out_insertions_totalcounterChunk identities recorded in A1out on eviction from A1in
cache_a1out_meta_hits_totalcounterA1out ghosts consumed by a metadata admission rather than plain reuse
cache_a1out_promotions_totalcounterChunks admitted straight to Am because they were reused while in A1out
cache_a1out_sizegaugeChunk identities in the A1out ghost list (identities only, no data)
cache_am_direct_admissions_totalcounterChunks admitted directly to Am by a filesystem metadata I/O
cache_am_evictions_totalcounterChunks evicted from the protected Am tier to free a slot
cache_am_meta_promotions_totalcounterA1in chunks promoted to Am at eviction time because they hold filesystem metadata
cache_am_removals_totalcounterAm entries dropped by discard, write rollback or recovery rather than eviction
cache_am_restored_totalcounterEntries placed into Am by crash recovery
cache_am_sizegaugeEntries resident in Am, dirty included
cache_dirty_slotsgaugeCache slots holding data not yet uploaded; divide by cache_total_slots for the ratio --max-dirty-ratio and --target-dirty-ratio act on
cache_eviction_waits_totalcounterTimes a cache allocation waited because every eviction candidate was in use
cache_hits_totalcounterReads served from the cache device
cache_lock_read_wait_secondshistogramWait for contended shared access to the cache map; rising millisecond waits mean flushes or discards are holding up guest reads
cache_lock_write_hold_secondshistogramTime the cache map was held exclusively; normally microseconds, and a long tail blocks concurrent readers
cache_lock_write_wait_secondshistogramWait for contended exclusive access to the cache map; scales with --concurrent-uploads
cache_metadata_bit_set_totalcounterChunks marked as holding filesystem metadata
cache_metadata_entriesgaugeResident chunks marked as holding filesystem metadata
cache_misses_totalcounterReads that had to fetch the chunk from object storage
cache_occupied_slotsgaugeCache slots holding a chunk, clean or dirty
cache_oldest_dirty_age_secondsgaugeAge of the oldest dirty chunk: how far the cache lags object storage, and how much acknowledged data a cache device failure would cost; 0 when nothing is dirty
cache_policy_infogaugeActive cache replacement policy, in the policy label
cache_re_dirty_totalcounterWrites that landed on a chunk a concurrent flush had just cleaned, making it dirty again
cache_read_duration_secondshistogramTime per cache read
cache_read_stall_failures_totalcounterGuest reads failed with EIO because a write they waited on did not finish in time; a torn read is refused rather than returned
cache_second_chances_totalcounterEvictions declined because the chunk was used again recently; under lru this is the whole recency mechanism
cache_total_slotsgaugeCache slots laid out on the cache device
cache_unpin_miscount_totalcounterInternal consistency violations; any non-zero value is a bug to report to Paradigm4
cache_write_duration_secondshistogramTime per cache write
cache_write_stalls_totalcounterTimes a write waited for a cache slot because every slot held dirty data
prefetch_completed_totalcounterChunks fetched ahead of a sequential cold read
prefetch_failed_totalcounterPrefetches that failed to fetch or cache their chunk
prefetch_issued_totalcounterChunk prefetches started by sequential cold reads
rmw_merges_totalcounterChunks whose missing pages were fetched from object storage and merged because a read, partial write or zeroing needed them

Uploads of dirty chunks to object storage.

SeriesTypeDescription
flush_attempts_totalcounterChunk uploads issued, failures included
flush_claim_skips_totalcounterChunks a flush pass skipped because another pass already had them
flush_duration_secondshistogramTime per chunk flush attempt, waits and retries included
flush_errors_totalcounterFlush tasks that failed at any stage
flush_eviction_pressure_totalcounterDirty chunks flushed early because a writer needed a slot and found nothing evictable
flush_exhaustedgauge1 after a flush batch exhausted its retry budget with no successful upload since; while set, a write that finds the cache full fails instead of waiting
flush_loop_iterations_totalcounterPasses of the flush loop; if this and flush_slices_total are flat while cache_oldest_dirty_age_seconds climbs, the loop is stuck (unless the ownership lease is lapsed or a data sync failed)
flush_noops_totalcounterFlushes that found nothing to upload
flush_overtaken_totalcounterUploads overtaken by a new write; the chunk stays dirty only for the newer writes
flush_quiet_skips_totalcounterTimes the age-based pass skipped a chunk written within --flush-quiet
flush_skips_totalcounterFlushes that stood down because a write was in flight on the chunk; steady growth means a chunk cannot flush
flush_slices_totalcounterBatches of chunks flushed; keeps climbing while a long pass drains a backlog
flush_wait_for_blocker_permit_duration_secondshistogramWait for a reserved upload slot by an urgent flush that writes are waiting on; compare with flush_wait_for_permit_duration_seconds
flush_wait_for_permit_duration_secondshistogramWait for an upload slot
flush_wait_for_read_permit_duration_secondshistogramWait for a slot to read the chunk from the cache device
flush_write_holds_totalcounterFlushes of an overdue chunk that briefly held off its writes, so a constantly written chunk still flushes
SeriesTypeDescription
obj_blocker_upload_capacitygaugeUpload slots reserved for urgent flushes, on top of obj_upload_capacity
obj_blocker_upload_inflightgaugeReserved urgent upload slots in use
obj_bytes_downloaded_totalcounterCompressed bytes fetched from object storage
obj_bytes_uploaded_totalcounterCompressed bytes uploaded to object storage by flushes
obj_cleanup_inflightgaugeBackground object-storage tasks in flight: discard deletes and their retries, and read prefetch
obj_delete_batches_totalcounterDelete batches issued; each request holds up to 1000 keys (256 on Blob, 100 on GCS)
obj_delete_capacitygaugeMaximum discard operations in flight
obj_delete_discard_batches_inflightgaugeDiscard-driven delete batches in flight or waiting for delete budget
obj_delete_inflightgaugeDiscard operations currently holding a delete slot
obj_delete_keys_per_secondgaugeDelete pace on AWS S3 in keys per second; 0 when unpaced
obj_deletes_totalcounterObjects deleted by discards
obj_download_capacitygaugeMaximum concurrent GETs for misses and prefetch (--concurrent-downloads)
obj_download_inflightgaugeGETs currently in flight for misses and prefetch
obj_downloads_totalcounterSuccessful chunk fetches for any purpose
obj_errors_totalcounterOperations that failed permanently or exhausted their retries (--retry-cutoff)
obj_flush_fetch_capacitygaugeMaximum concurrent GETs by flushes filling in missing pages
obj_flush_fetch_inflightgaugeFlush GETs in flight
obj_get_duration_secondshistogramTime per chunk fetch, retries included
obj_put_duration_secondshistogramTime per chunk upload, retries included
obj_retries_totalcounterRetries after a transient error
obj_upload_capacitygaugeCurrent maximum concurrent PUTs: --concurrent-uploads, raised up to four times that under write-back pressure
obj_upload_inflightgaugeUploads in flight
obj_uploads_totalcounterSuccessful chunk uploads
SeriesTypeDescription
delete_queue_discardgaugeDiscarded chunk keys queued for deletion
discard_deletes_pendinggaugeDiscarded chunks whose object delete has not completed; must reach 0 before detach
discard_redrive_pendinggaugeFailed discard deletes awaiting retry
object_index_entriesgaugeChunks that have an object in the bucket; this index grows in memory as the volume fills
SeriesTypeDescription
device_syncs_totalcounterCache device syncs for guest FLUSH and FUA requests; stays 0 when the device has no volatile write cache and uses direct I/O
meta_bitmap_persist_failures_totalcounterFailed passes writing slot page state to the cache device; unwritten state is lost on a crash
meta_bitmap_persist_pendinggaugeChunks whose page state changed in memory and is not yet on the cache device
meta_bitmap_persist_stale_skips_totalcounterQueued page-state records dropped because the chunk changed before they were written
meta_page_writes_totalcounter4 KiB slot metadata pages written
meta_record_updates_totalcounterSlot metadata record updates; divide by meta_page_writes_total for the batching factor
meta_write_errors_totalcounterSlot metadata page writes that failed
nvme_buffered_reads_totalcounterChunk reads through the page cache; in direct mode, reads that O_DIRECT could not express
nvme_circuit_breaker_opengauge1 while consecutive cache device errors have tripped the circuit breaker and new fast-path I/O is rejected
nvme_dio_stage_totalcounterChunk I/Os copied through an aligned staging buffer to stay on O_DIRECT
nvme_dio_unaligned_totalcounterChunk I/Os that fell back to buffered I/O because they were not 4096-aligned
nvme_direct_reads_totalcounterChunk reads through O_DIRECT
nvme_errors_totalcounterI/O errors on the cache device; 64 in a row open the circuit breaker
nvme_fdatasync_fallback_totalcounterDurable writes done as a write plus fdatasync, because RWF_DSYNC is unsupported or --no-fua is set
nvme_read_duration_secondshistogramTime per cache device chunk read
nvme_write_duration_secondshistogramTime per cache device write (data, metadata, log and superblocks)

The write-ahead log (WAL) is a ring of intents on the cache device that crash recovery replays. These series also cover write-back pacing.

SeriesTypeDescription
wal_active_entriesgaugeDirty intents whose flush has not landed; add discard_deletes_pending and divide by wal_ring_capacity for ring utilization
wal_checkpoint_failures_totalcounterLog checkpoints that failed to persist; recovery scans from the last one that did
wal_head_backstop_flushes_totalcounterUrgent ring-head chunks the main flush loop flushed alongside the dedicated worker
wal_head_flush_batches_totalcounterBatches of ring-head chunks flushed by the dedicated urgent worker
wal_head_flush_duration_secondshistogramTime the urgent worker spent flushing a batch; what a stalled write waits on
wal_head_rotations_totalcounterActive entries moved past the ring head; steady growth means write-back is more than a lap behind, a chunk cannot flush, or a large trim is slow
wal_head_stalls_totalcounterWrites and discards that waited because the whole ring held active entries
wal_mark_completed_failures_totalcounterFailures to persist an entry’s completion; the entry is reclaimed later
wal_orphans_recovered_totalcounterOrphaned entries reclaimed at the ring head; steady growth deserves a look
wal_records_since_checkpointgaugeRecords written since the last checkpoint
wal_ring_capacitygaugeTotal ring entries
writeback_pressuregaugeWrite-back pressure from 0 to 1: 0 at or below --max-dirty-ratio, 1 halfway from there to a full cache
writeback_throttle_chunks_per_secondgaugeRate at which writes may dirty new chunks while write pacing is on; 0 when off
writeback_throttle_wait_seconds_totalcounterSeconds guest writes spent delayed by write pacing
SeriesTypeDescription
compress_bytes_in_totalcounterUncompressed bytes handed to the compressor by flushes
compress_bytes_out_totalcounterCompressed bytes produced, headers included; in over out is the compression ratio
compress_duration_secondshistogramTime per chunk compression
decompress_duration_secondshistogramTime per chunk decompression after a fetch
SeriesTypeDescription
license_expires_at_secondsgaugeUnix time the grant in force expires
license_grace_ends_at_secondsgaugeUnix time the grace period ends and throttling engages
license_infogaugeIdentity and state of the grant in force, in labels
license_reload_failedgauge1 if the last poll could not re-read the grant file and the last good grant is still in use
license_reload_failures_totalcounterPolls that could not re-read the grant file
license_stategauge0 valid, 1 grace, 2 expired, 3 not covered by the grant, 4 not yet in force; 2 and above throttle guest I/O
license_throttle_read_bytes_per_secondgaugeRead bandwidth limit being applied; 0 when unthrottled
license_throttle_wait_seconds_totalcounterSeconds guest I/O spent delayed by license throttling
license_throttle_waits_totalcounterGuest reads and writes delayed by license throttling
license_throttle_write_bytes_per_secondgaugeWrite bandwidth limit being applied; 0 when unthrottled
SeriesTypeDescription
ownership_check_failures_totalcounterOwnership re-checks that could not complete; serving continues, but bucket writes pause once the lease lapses
ownership_lease_heldgauge1 while the ownership lease is held; 0 while bucket writes are paused
ownership_marker_reestablished_totalcounterTimes the ownership marker was missing from the bucket and written back
SeriesTypeDescription
build_infogaugeFlexBlock build serving this device, in the version label
chunk_size_bytesgaugeChunk size of the volume
device_size_bytesgaugeSize of the block device presented to the guest
jemalloc_active_bytesgaugeBytes in active memory pages, per the allocator
jemalloc_allocated_bytesgaugeBytes the daemon has allocated, per the allocator
jemalloc_mapped_bytesgaugeBytes in mapped memory, per the allocator
jemalloc_resident_bytesgaugeBytes in physically resident pages, per the allocator
logical_block_size_bytesgaugeLogical block size the device advertises
start_time_secondsgaugeUnix time this daemon started