Files
2026-07-13 12:24:33 +08:00

285 lines
9.5 KiB
ReStructuredText

Observability
=============
LMCache multiprocess mode provides three complementary observability modes:
**metrics** (Prometheus counters via OTel), **logging** (Python logging with
optional OTel log forwarding), and **tracing** (OTel spans for per-request
latency).
All three modes are powered by an internal **EventBus** that decouples
producers (L1Manager, StorageManager, MPCacheServer) from subscribers.
.. contents::
:local:
:depth: 2
Quick Start
-----------
By default, **metrics** and **logging** are enabled; **tracing** is disabled.
No extra flags are needed:
.. code-block:: bash
lmcache server \
--l1-size-gb 100 --eviction-policy LRU
The server then exposes Prometheus metrics at ``/metrics`` on its **HTTP
frontend port** (``--http-port``, default ``8080``):
.. code-block:: bash
curl http://localhost:8080/metrics | grep lmcache_mp_
.. important::
For ``lmcache server``, ``/metrics`` lives on ``--http-port`` (default
``8080``), **not** on ``--prometheus-port``: the HTTP frontend already
serves ``/metrics``, so the standalone Prometheus server is disabled and
``--prometheus-port`` has no effect under this command. ``--prometheus-port``
*is* the metrics endpoint for the frontend-less entrypoints
(``python -m lmcache.v1.multiprocess.server`` and ``lmcache trace replay``)
— see :ref:`mp-obs-metrics-endpoint`. Also note metrics are lazy: a series
only appears *after* the first store/retrieve that produces it, so drive
some traffic before scraping.
To also see L2 (storage-tier) metrics, attach an L2 backend with
``--l2-adapter``. The simplest is the local filesystem:
.. code-block:: bash
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--l2-adapter '{"type": "fs", "base_path": "/data/lmcache/l2"}'
To enable tracing instead of (or alongside) Prometheus pull, supply an OTLP
endpoint — this switches metrics to **push mode** (see
:ref:`mp-obs-grafana`):
.. code-block:: bash
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--enable-tracing --otlp-endpoint http://localhost:4317
.. _mp-obs-metrics-endpoint:
Where ``/metrics`` lives
~~~~~~~~~~~~~~~~~~~~~~~~~~
The pull-mode ``/metrics`` endpoint is served in one of two places depending
on the entrypoint. Entrypoints that embed the uvicorn HTTP frontend serve it
there (and disable the standalone Prometheus server); entrypoints with no
HTTP frontend start the standalone server on ``--prometheus-port`` instead.
.. list-table::
:header-rows: 1
:widths: 40 20 40
* - Entrypoint
- HTTP frontend?
- Pull-mode ``/metrics`` endpoint
* - ``lmcache server``
- yes
- ``--http-port`` (default ``8080``); ``--prometheus-port`` ignored
* - ``python -m lmcache.v1.multiprocess.server``
- no
- ``--prometheus-port`` (default ``9090``)
* - ``lmcache trace replay``
- no
- ``--prometheus-port`` (default ``9090``)
In **push mode** (``--otlp-endpoint`` set) none of these serve ``/metrics``
metrics are pushed to the collector instead.
.. _mp-obs-grafana:
Viewing Metrics in Grafana
--------------------------
There are two ways to get LMCache metrics into Grafana. Pick based on whether
you also want **traces**.
.. list-table::
:header-rows: 1
:widths: 22 20 30 28
* - Path
- Server flags
- What you run
- Gives you
* - **A. Bundled stack**
- ``--otlp-endpoint`` (push)
- ``docker compose up`` in ``examples/observability/``
- Metrics **+ traces**, Grafana with the LMCache dashboard
auto-provisioned
* - **B. Pull mode**
- none (default)
- Your own Prometheus + Grafana scraping ``:8080``
- Metrics only, minimal moving parts, no collector
Path A — bundled Prometheus + Tempo + Grafana
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The repository ships a ready-to-run stack (OpenTelemetry Collector →
Prometheus + Tempo → Grafana) under ``examples/observability/``. Grafana comes
with the **LMCache dashboard and datasources pre-provisioned** and anonymous
access enabled, so there is nothing to click to log in.
.. code-block:: bash
# 1. Start the observability stack (Collector :4320, Prometheus, Tempo,
# Grafana :3000)
cd examples/observability
docker compose up -d
# 2. Start the LMCache server (+ vLLM) pushing OTLP to the collector
MODEL=/path/to/model bash start-server.sh
# 3. Generate traffic, then open Grafana
# http://localhost:3000 -> Dashboards -> "LMCache"
In this path the server pushes to the Collector and **Prometheus scrapes the
Collector**, so you do *not* scrape the server's ``:8080`` directly.
Path B — pull mode (metrics only, no collector)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you only want metrics, skip the collector entirely and have Prometheus
scrape the server's ``/metrics`` endpoint directly. Start the server **without**
``--otlp-endpoint`` (see Quick Start above), then:
.. code-block:: bash
# 1. Prometheus config: scrape the server's HTTP-frontend port (8080)
cat > prometheus.yml <<'YAML'
global:
scrape_interval: 5s
scrape_configs:
- job_name: lmcache
static_configs:
- targets: ["localhost:8080"] # --http-port, NOT --prometheus-port
YAML
# 2. Run Prometheus (:9090) and Grafana (:3000) on the host network so
# they can reach localhost:8080 and each other.
docker run -d --name lmcache-prom --network host \
-v "$PWD/prometheus.yml:/etc/prometheus/prometheus.yml:ro" \
prom/prometheus
docker run -d --name lmcache-grafana --network host \
-e GF_AUTH_ANONYMOUS_ENABLED=true \
-e GF_AUTH_ANONYMOUS_ORG_ROLE=Admin \
grafana/grafana
Then in Grafana (``http://localhost:3000``):
1. **Add a datasource** → Prometheus → URL ``http://localhost:9090`` → Save.
2. **Import the dashboard**: Dashboards → New → Import → upload
``examples/observability/grafana/provisioning/dashboards/lmcache.json``
and select the Prometheus datasource. This is the same dashboard the
bundled stack provisions (cache hit rate, L1/L2 cache ops, L1↔L2
throughput, eviction loop, EventBus health, and more).
Verify the pipeline end to end:
.. code-block:: bash
# target should be "up"
curl -s localhost:9090/api/v1/targets | grep -o '"health":"[a-z]*"'
# after driving traffic, L2 store throughput (GB/s) per backend:
curl -s localhost:9090/api/v1/query --data-urlencode \
'query=sum by (l2_name) (rate(lmcache_mp_l2_store_throughput_GB_per_second_sum[1m]))
/ sum by (l2_name) (rate(lmcache_mp_l2_store_throughput_GB_per_second_count[1m]))'
See :doc:`metrics` for the full metric catalog and more PromQL examples.
.. note::
``--network host`` (used above) is the simplest option on Linux. On Docker
Desktop (macOS/Windows), drop ``--network host``, publish ports with
``-p 9090:9090`` / ``-p 3000:3000``, and set the scrape target to
``host.docker.internal:8080`` and the Grafana datasource URL to
``http://host.docker.internal:9090``.
Configuration
-------------
.. list-table::
:header-rows: 1
:widths: 30 15 55
* - Argument
- Default
- Description
* - ``--disable-observability``
- off
- Master switch: disable the EventBus entirely (no metrics, logging, or
tracing subscribers are registered).
* - ``--disable-metrics``
- off
- Skip metrics subscribers (Prometheus endpoint is not started).
* - ``--disable-logging``
- off
- Skip logging subscribers.
* - ``--enable-tracing``
- off
- Register tracing subscribers. Requires ``--otlp-endpoint``.
* - ``--event-bus-queue-size``
- ``10000``
- Maximum events in the EventBus queue before tail-drop.
* - ``--otlp-endpoint``
- *(none)*
- OTLP gRPC endpoint (e.g. ``http://localhost:4317``). Used for
exporting metrics (push mode) and traces.
* - ``--prometheus-port``
- ``9090``
- Port of the standalone Prometheus ``/metrics`` server. Started only by
frontend-less entrypoints (``python -m lmcache.v1.multiprocess.server``,
``lmcache trace replay``). **Ignored by** ``lmcache server`` — there the
HTTP frontend serves ``/metrics`` on ``--http-port`` instead, so the
standalone server is disabled. See :ref:`mp-obs-metrics-endpoint`.
* - ``--http-port``
- ``8080``
- Port of the HTTP frontend, which serves the Prometheus ``/metrics``
endpoint in pull mode (when ``--otlp-endpoint`` is unset) for
``lmcache server``.
* - ``--metrics-sample-rate``
- ``0.01``
- Fraction of chunks/blocks to track for lifecycle histograms
(0, 1.0]. Counters always count all events. Default is 1%.
* - ``--trace-level``
- *(none)*
- Enable trace recording at the given level. Currently only
``storage`` is supported (records ``StorageManager`` public-API
calls for offline replay). When unset, trace recording is off.
See :ref:`trace-recording` for details.
* - ``--trace-output``
- *(none)*
- Path to write the trace file. If omitted while ``--trace-level``
is set, a timestamped file under ``$TMPDIR`` is minted
(``lmcache-trace-<pid>-<UTC>.lct``) and its path is logged at INFO.
**Environment variables:**
.. list-table::
:header-rows: 1
:widths: 30 15 55
* - Variable
- Default
- Description
* - ``LMCACHE_LOG_LEVEL``
- ``INFO``
- Controls the log level for all LMCache loggers. Valid values:
``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``.
.. toctree::
:maxdepth: 1
metrics
logs
traces