Wait Events
AngaraBase 0.6.3.9 §S11 — базовая модель wait events. RM-0.6.4.10 добавляет QoS scheduler events. RM-0.6.4.19 Track C C1 добавляет per-session счётчики и per-session запрос
angara_stat_wait_events.
Эта страница описывает taxonomy WaitEvent, которую AngaraBase использует для
классификации блокирующих операций. Для оператора wait events отвечают на вопрос:
“на чём кластер сейчас ждёт?” без strace, ручного разбора stack traces и
инструментации каждого call site.
Зачем нужна модель wait events
Модель похожа на pg_stat_activity.wait_event в PostgreSQL или
sys.dm_os_wait_stats в SQL Server:
- каждый блокирующий участок кода получает конкретную причину ожидания;
- текущий wait виден на уровне session/activity;
- агрегированные метрики дают rate, active count и latency distribution по каждому событию;
- dashboards сравнивают разные классы ожиданий через единый label
event=<variant_snake_case>.
Два слоя observability:
- Текущий wait сессии —
angara_stat_activity.wait_event_typeиangara_stat_activity.wait_event. - Агрегированные метрики Prometheus — counters, gauges и histograms по каждому wait event.
События
WaitEvent — стабильный public API. Добавление variant является non-breaking:
dashboards увидят новый event=... label после upgrade. Удаление, renumbering
или изменение as_str() значения считается breaking change.
| Variant | Label | Wait type | Когда срабатывает |
|---|---|---|---|
RowLock | row_lock | Lock | Ожидание tuple-level lock. |
PageLock | page_lock | Lock | Ожидание page-level latch. |
TableLock | table_lock | Lock | Ожидание relation-level lock для DDL/lock manager. |
TransactionLock | transaction_lock | Lock | Ожидание commit/finish другой транзакции. |
PredicateLockAcquire | predicate_lock_acquire | Lock | Ожидание захвата predicate lock для SSI foundation. |
PredicateConflictCheck | predicate_conflict_check | Lock | Ожидание проверки predicate conflict graph. |
PageRead | page_read | IO | Чтение heap/index page при cache miss. |
PageWrite | page_write | IO | Write-back страницы при checkpoint или eviction. |
WalFlush | wal_flush | IO | WAL flush / fsync path. |
Fsync | fsync | IO | Прочие fsync пути: catalog, FPI и смежные операции. |
WalSync | wal_sync | IO | Strict WAL sync wait в durability path. |
WalGroupCommit | wal_group_commit | IO | Ожидание group commit batch. |
ColumnarCompaction | columnar_compaction | IO | Background compactor ждёт disk I/O или manifest append mutex в compact_l0_to_l1(). |
ClientRead | client_read | Net | Чтение из client socket. |
ClientWrite | client_write | Net | Запись в client socket. |
ReplicaRead | replica_read | Net | Чтение из replica connection. |
ReplicaWrite | replica_write | Net | Запись в replica connection. |
NetRead | net_read | Net | Generic network read. |
NetWrite | net_write | Net | Generic network write. |
CpuRun | cpu_run | CPU | Сессия исполняется на CPU, это не блокировка. |
PageDecompression | page_decompression | CPU | CPU time на decompression страницы при buffer-pool miss. |
PageCompression | page_compression | CPU | CPU time на compression dirty page перед flush. |
AdmissionQueue | admission_queue | Scheduler | Ожидание admission control queue. |
IoSchedulerQueue | io_scheduler_queue | Scheduler | Ожидание I/O scheduler queue. |
MemoryGrantQueue | memory_grant_queue | Scheduler | Ожидание memory grant. |
BufferPoolEviction | buffer_pool_eviction | Scheduler | Сессия ждёт свободный или evictable buffer-pool slot. |
BackpressureThrottle | backpressure_throttle | Scheduler | Unified backpressure coordinator throttles caller. |
DiskRestartHarness | disk_restart_harness | Scheduler | Test harness ждёт re-hydration on-disk state при disk-restart тесте. |
QosQueue | qos_queue | Scheduler | Async task стоит в per-shard DRR queue QoS scheduler до dispatch. |
QosBlocking | qos_blocking | Scheduler | Blocking task ждёт dispatch через QoS blocking path. |
QoS события RM-0.6.4.10
qos_queue означает, что задача уже классифицирована по service level
(critical, interactive, background) и ожидает dispatch в scheduler queue.
Рост этого wait обычно указывает на scheduler saturation или burst нагрузки.
qos_blocking означает, что задача попала в blocking path QoS scheduler.
Смотрите его вместе с gauge angarabase_qos_blocking_inflight и
angarabase_spawn_blocking_max: если blocking wait растёт, а inflight близок к
лимиту, cluster pressure находится не в SQL locks, а в runtime/blocking pool.
В Sprint 2A granularity по service level намеренно coarse: нет отдельных
qos_queue_critical, qos_queue_interactive, qos_queue_background.
Для уровня сервиса используйте QoS counters:
angarabase_qos_queued_*_total и angarabase_qos_rejected_*_total.
Ordinals и compatibility
Ordinals append-only и закреплены в WaitEvent::ordinal():
QosQueueимеет ordinal28;QosBlockingимеет ordinal29.
Массив WaitEvent::ALL используется для рендера всех label values в metrics.
Фиксированный размер metrics array задаётся N_WAIT_EVENT_VARIANTS.
Правила совместимости:
- добавление variant — non-breaking;
- удаление variant — breaking;
- renumbering ordinal — breaking;
- переименование label value из
as_str()— breaking для dashboards и alerts.
Per-session wait events (RM-0.6.4.19 Track C C1)
Начиная с RM-0.6.4.19 angara_stat_wait_events поддерживает per-session режим:
-- Process-wide aggregates (как раньше):
SELECT * FROM angara_stat_wait_events;
-- Per-session счётчики текущей сессии:
SELECT * FROM angara_stat_wait_events WHERE session_id = current_session();
В per-session режиме:
total— суммарное число входов в данный wait event для текущей сессии с момента её запуска.activeиtotal_duration_us— всегда0в phase 1 (per-session histogram deferred to phase 2).- Счётчики инкрементируются через
WaitEventGuard::enterи хранятся вAtomicWaitState::event_counts(per-session registry, indexed by session_id).
Если сессия не совершала ни одного wait event, все total = 0 (пустой wait state возвращает нули).
Метрики
Для каждого события экспортируются три Prometheus series с label
event=<variant_snake_case>:
| Метрика | Тип | Смысл |
|---|---|---|
angarabase_wait_events_total | counter | Сколько раз код входил в ожидание этого типа. |
angarabase_wait_events_active | gauge | Сколько ожиданий этого типа активно прямо сейчас. |
angarabase_wait_event_duration_seconds | histogram | Распределение длительности ожидания. |
Histogram buckets в секундах: 0.001, 0.005, 0.01, 0.05, 0.1,
0.5, 1, 5, +Inf.
PromQL примеры
Top-N wait classes по накопленному времени за 5 минут:
topk(
5,
rate(angarabase_wait_event_duration_seconds_sum[5m])
)
Активные ожидания прямо сейчас:
sum by (event) (angarabase_wait_events_active)
p99 latency для buffer-pool eviction:
histogram_quantile(
0.99,
rate(angarabase_wait_event_duration_seconds_bucket{event="buffer_pool_eviction"}[5m])
)
Backpressure throttle rate:
rate(angarabase_wait_events_total{event="backpressure_throttle"}[1m])
QoS queue wait rate:
rate(angarabase_wait_events_total{event="qos_queue"}[5m])
p95 ожидания в QoS queue:
histogram_quantile(
0.95,
rate(angarabase_wait_event_duration_seconds_bucket{event="qos_queue"}[5m])
)
Активные blocking waits QoS:
angarabase_wait_events_active{event="qos_blocking"}
Alert на длительную очередь QoS:
histogram_quantile(
0.99,
rate(angarabase_wait_event_duration_seconds_bucket{event="qos_queue"}[5m])
) > 0.5
Alert на blocking pool pressure:
angarabase_wait_events_active{event="qos_blocking"} > 0
and
angarabase_qos_blocking_inflight > 0
Корреляция QoS waits с rejections:
rate(angarabase_wait_events_total{event="qos_queue"}[5m])
and
sum(rate({__name__=~"angarabase_qos_rejected_.*_total"}[5m])) > 0
Operator playbook
BufferPoolEviction растёт:
- buffer pool меньше рабочего набора;
- достигнут
max_cached_pages; - проверьте buffer-pool-pressure runbook.
BackpressureThrottle растёт:
- WAL queue или buffer pool exhaustion замедляет клиентов;
- проверьте
angarabase_buffer_pool_uncommitted_pages_ratio; - сопоставьте с WAL group-commit latency.
WalFlush или WalSync p99 выше 100 ms:
- вероятна fsync regression или storage stall;
- используйте wal-fsync-slow runbook.
RowLock имеет высокие duration:
- ищите lock contention и long transactions;
- используйте deadlock-spike runbook.
QosQueue растёт:
- проверьте
angara_stat_qos_queues; - смотрите
angarabase_qos_rejected_*_total; - снизьте concurrency batch jobs;
- переведите тяжёлые jobs в
SET service_level = 'background'; - пересмотрите
ANGARABASE_QOS_WEIGHTSиANGARABASE_QOS_MAX_QUEUED.
QosBlocking растёт:
- проверьте
angarabase_qos_blocking_inflight; - проверьте
angarabase_spawn_blocking_max; - ищите blocking workload, который вытесняет runtime capacity;
- не лечите это увеличением SQL lock timeout: wait находится в scheduler/runtime path.
Source of truth
- Code:
crates/angarabase/src/observability/wait_events.rs - Per-session dispatch:
crates/angarabase/src/virtual_catalog.rs+virtual_catalog/shared_catalog.rs - Metrics:
crates/angarabase/src/metrics/core.rs - Render:
crates/angarabase/src/metrics/render.rs - QoS scheduler:
crates/angarabase/src/qos_manager.rs - RM:
docs/planning/v0.6/RM-0.6.3.9.md§S11,docs/planning/v0.6/RM-0.6.4.10.md,docs/planning/v0.6/RM-0.6.4.19.mdTrack C C1