Queue Backend
OpenObserve uses an internal message queue for coordinating cluster events, rate limiting, and synchronizing state across nodes. You can choose between two queue backends by setting ZO_QUEUE_STORE.
Choosing a backend
| Backend | Best for |
|---|---|
NATS (nats) | Cluster (HA) deployments with multiple nodes. Requires a running NATS server. |
In-memory (memory) | Local single-process deployments where you want to avoid running a NATS server. Process-local and non-durable. |
When ZO_QUEUE_STORE is left unset, OpenObserve selects the backend automatically:
- Local mode (
ZO_LOCAL_MODE=true): defaults tomemory - Cluster mode (
ZO_LOCAL_MODE=false): defaults tonats
Explicit values are always honored, and unknown values cause a startup error.
Configuration
ZO_QUEUE_STORE
| Value | Description |
|---|---|
nats | Use a NATS JetStream server for queuing. Requires the NATS server to be configured (see NATS configuration). |
memory | Use a bounded, process-local, in-memory queue. Works only in local mode. |
The memory backend is rejected at startup if ZO_LOCAL_MODE is false, since an in-memory queue cannot coordinate across nodes in a cluster deployment.
ZO_MEMORY_QUEUE_MAX_SIZE_MB
| Default | Description |
|---|---|
64 | Aggregate accounted memory limit in megabytes across all queue topics when ZO_QUEUE_STORE=memory. |
Set this to control the maximum memory the in-memory queue can consume across all topics. A value of 0 falls back to the default of 64 MB. The value is validated at startup and converted to bytes internally.
In-memory queue behavior
When ZO_QUEUE_STORE=memory, the queue backend operates with the following characteristics:
- Process scope: All state is held in memory and lost when the process exits. No durability across restarts.
- At-least-once delivery: Messages are guaranteed to be delivered at least once within the process lifetime. FIFO ordering for first delivery.
- Single global budget: The
ZO_MEMORY_QUEUE_MAX_SIZE_MBlimit is shared across all queue topics. Both topic metadata and message payloads count toward the budget. - Publication rejection: Publishing a message that would exceed the budget returns a
QueueFullerror. A message larger than the entire budget returns aMessageTooLargeerror. Unacknowledged messages are never evicted to make room. - Lazy expiration sweep: When the budget is full, expired messages (past their
max_age) are reclaimed from all topics to make room before rejecting the publication. Routine expiration is handled by a background maintenance loop. - One active consumer per topic: A topic supports one active consumer at a time. Re-subscribing after the previous consumer closes is supported.
- Visibility timeout: Unacknowledged messages are redelivered after 30 seconds, matching the default NATS
ack_wait. A stale ack (e.g., from a timed-out delivery) does not affect the newer delivery attempt. - Deliver policies:
All,Last, andNewdeliver policies are supported.Allreplays the full backlog;Lastkeeps only the newest unacknowledged message;Newstarts with messages published after the subscription. max_agesupport: Messages are expired based on their original publication time. Expiration applies to both pending and in-flight messages.- Redelivery: Messages dropped without acknowledgment (e.g., the receiver is dropped) are requeued for redelivery. Messages exceeding the visibility timeout are also requeued.
Limitations
- No durability: all queued messages are lost on process exit.
- Not supported in cluster mode.
- Total message accounting includes per-entry and per-topic overhead (roughly 128 bytes per message and 256 bytes per topic), so empty messages still consume budget.
Metrics
When ZO_QUEUE_STORE=memory, the following Prometheus metrics are exposed on the /metrics endpoint:
| Metric | Labels | Description |
|---|---|---|
queue_memory_used_bytes | backend | Current aggregate accounted bytes across all queue topics |
queue_memory_limit_bytes | backend | Configured aggregate byte limit |
queue_messages | topic, state | Message counts by topic and state (pending, in_flight) |
queue_publish_total | topic, result | Publications by topic and result (accepted, rejected_full, rejected_too_large) |
queue_redelivery_total | topic, reason | Redeliveries by topic and reason (dropped, timeout) |
queue_message_expired_total | topic, state | Messages expired by max_age, by topic and state (pending, in_flight) |
queue_oldest_message_age_seconds | topic | Age in seconds of the oldest pending or in-flight message |
Rate limiting with the in-memory queue
Enterprise rate limiting requires ZO_QUEUE_STORE=nats. Setting ZO_QUEUE_STORE=memory while rate limiting is enabled causes a startup error.
Example: local development setup
# Run in local mode with the in-memory queue (default behavior)
ZO_LOCAL_MODE=true ./openobserve
# Equivalent, with explicit values
ZO_LOCAL_MODE=true ZO_QUEUE_STORE=memory ZO_MEMORY_QUEUE_MAX_SIZE_MB=128 ./openobserve
# Run in local mode but use a local NATS server for the queue
ZO_LOCAL_MODE=true ZO_QUEUE_STORE=nats ZO_NATS_ADDR=localhost:4222 ./openobserveLast updated on
Environment Variables
Configure OpenObserve with flexible environment variables for roles, storage, performance, and scaling across open source and enterprise deployments.
OpenObserve CLI
Manage OpenObserve alerts, pipelines, destinations, functions, and templates from the command line across environments, with CI/CD-ready workflows.