HTTP API#
When the MP server is started via lmcache server (the recommended entry
point), a FastAPI-based HTTP frontend is exposed alongside the selected ZMQ or
gRPC request endpoint used by vLLM. This HTTP API is intended for operators,
orchestrators (e.g. Kubernetes), and debugging tools — it is not on the
inference data path.
路由的来源#
路由由三个来源组装而成,在启动时由 HTTPAPIRegistry 合并为一个 FastAPI 应用:
MP 原生路由 — 在
lmcache/v1/multiprocess/http_apis/下任何名为*_api.py的模块,如果暴露了模块级的router(一个fastapi.APIRouter),将会被自动发现。这涵盖了运维操作面:状态、缓存控制、L2 管理、配额和运行时重新配置。共享“公共”路由 —
lmcache/v1/multiprocess/http_apis/common_api.py聚合了lmcache/v1/internal_api_server/common/下的每个兼容的 router(跳过任何列在_MP_INCOMPATIBLE_MODULES中的模块,目前为空),并将它们转发到自动发现流水线。这些是与嵌入 vLLM 的 API 服务器共享的跨服务器诊断(/env、/loglevel、/metrics、/threads、/periodic-threads*、/run_script)。在internal_api_server/common下添加新的兼容模块无需在 MP 端进行任何改动。重新导出的版本路由 — 基本信息组
lmcache/v1/multiprocess/http_apis/info_api.py包含来自lmcache/v1/internal_api_server/vllm/version_api.py的路由器,暴露/version、/lmc_version和/commit_id,以及/、/healthcheck和/status。
服务器配置#
参数 |
默认 |
描述 |
|---|---|---|
|
|
绑定 HTTP 服务器的主机。 |
|
|
绑定 HTTP 服务器的端口。 |
|
unset |
Read a bearer API key from a file. Repeat the option to accept multiple keys during rotation. Authentication is disabled when no CLI or environment key source is configured. |
The environment variables LMCACHE_HTTP_API_KEY_FILE and
LMCACHE_HTTP_API_KEY provide deployment-friendly alternatives for one key
file or one key value. Environment sources and repeated
--http-api-key-file options are cumulative, so old and new keys can overlap
during rotation. The /env endpoint redacts LMCACHE_HTTP_API_KEY while
leaving the non-secret key-file path visible.
示例:
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--http-host 0.0.0.0 --http-port 8080 \
--http-api-key-file /run/secrets/lmcache-http-api-key
All examples below assume the server is reachable at
http://localhost:8080. When authentication is enabled, include the key as
Authorization: Bearer <api-key>. The / and /healthcheck routes
remain public for liveness and readiness probes; every other route requires a
valid key. For example:
curl -H "Authorization: Bearer $(cat /run/secrets/lmcache-http-api-key)" \
http://localhost:8080/status
Use a high-entropy value such as openssl rand -hex 32 and restrict the key
file so only the LMCache server process can read it. API-key authentication
does not encrypt traffic; use TLS at a trusted reverse proxy when requests
cross an untrusted network.
端点概述#
下面的路由按目的分组。操作接口(健康检查、状态、缓存和存储控制)位于顶层路径;从共享的 internal_api_server 包继承的路由保持其原始路径,以与嵌入的 vLLM API 服务器兼容。
备注
多个处理程序在响应 主体 中报告失败,而不是通过非 200 状态码(例如 DELETE /cache/objects 返回 200 和 ok=false,而 /periodic-threads-health 返回 200 和 healthy=false)。错误字段名称也不统一:/healthcheck 和 /cache/clear 在失败时使用 reason,而 /status、/config 和 /cache/checksums 使用 error。每个端点的详细信息如下是权威的。
存活性和健康
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
静态存活检测(不触及引擎)。 |
GET |
|
K8s 存活/就绪探针; |
检查和状态
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
用于检查和调试的详细引擎快照(L1、L2、注册的上下文、会话、预取作业)。 |
GET |
|
转储合并的服务器配置对象( |
GET |
|
列出活动缓存适配器( |
GET |
|
组合版本字符串 ( |
GET |
|
LMCache 包版本字符串。 |
GET |
|
构建提交 ID。 |
缓存管理
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
对驻留在某个层/适配器中的对象进行分页(查询: |
DELETE |
|
从 L1、L2 或两者中删除调用者提供的对象键列表(主体: |
POST |
|
通过从 L2 提前加载令牌序列来预热节点的 L1;返回 |
GET |
|
轮询已提交的热预取( |
POST |
|
强制清除某个层的常驻缓存(请求体: |
POST |
|
计算 KV Cache 块的 MD5 校验和(诊断 / 往返完整性检查)。 |
配额管理
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
列出每个注册的 |
PUT |
|
设置或更新 |
GET |
|
读取单个 |
DELETE |
|
移除 |
运行时 L2 重新配置
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
报告一个后端类型的可运行管理 L2 适配器。 (要发现可重新配置的后端,请使用 |
POST |
|
对后端适配器应用一个运行时重新配置操作。 |
Runtime L1 reconfiguration (Device-DAX)
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
Report every Device-DAX L1 arena with usage and lifecycle state. |
POST |
|
Map an additional Device-DAX device. |
POST |
|
Remove one mapped Device-DAX L1 device (currently drain mode only). |
可观察性
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
Prometheus 展示格式。 |
POST |
|
将所有可观察性指标重置为初始状态。 |
诊断与调试
方法 |
路径 |
目的 |
|---|---|---|
GET |
|
列出或检查日志记录器级别;也接受 |
GET |
|
列出活动的 Python 线程及其堆栈跟踪。 |
GET |
|
列出注册的周期性线程及其摘要计数。 |
GET |
|
单个周期线程的详细状态。 |
GET |
|
对关键/高层周期线程的快速健康检查。 |
GET |
|
转储进程环境变量(JSON主体, |
POST |
|
Execute an uploaded Python script in a restricted sandbox.
Disabled by default; requires |
存活性和健康状态#
GET /#
基本的存活检查。返回一个静态负载,指示 HTTP 服务器正在运行;它不会触及缓存引擎。对于还验证引擎是否已初始化的探测,请使用 /healthcheck。
响应 (200 OK):
{
"status": "ok",
"service": "LMCache HTTP API"
}
HTTP 状态码:
200: 服务器正常运行(无条件;不影响引擎)。
示例:
curl -s http://localhost:8080/
GET /healthcheck#
健康检查端点适用于 Kubernetes 的存活和就绪探针。200 响应意味着 HTTP 服务器处于活动状态 并且 MP 缓存引擎对象已连接到 app.state。503 响应表示引擎尚未存在(仍在初始化中,或初始化失败)。该检查验证引擎属性是否已设置;它不会调用引擎以确认更深层次的存活状态。
响应 (200 OK):
{
"status": "healthy"
}
响应 (503 服务不可用):
{
"status": "unhealthy",
"reason": "engine not initialized"
}
HTTP 状态码:
200: 引擎已连接到app.state(正常)。503: 引擎未初始化(仍在启动中,或初始化失败)。
示例:
curl -s http://localhost:8080/healthcheck
Kubernetes 探针代码片段:
livenessProbe:
httpGet:
path: /healthcheck
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthcheck
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
检查和状态#
GET /status#
返回 MP 引擎内部状态的详细快照。有效负载由 MPCacheServer.report_status() 组装:一组固定的引擎级字段、完整的存储管理器状态,以及每个加载模块贡献的键(因此确切的键集取决于哪些模块处于活动状态 — registered_gpu_ids / cache_context_meta 来自传输模块,active_prefetch_jobs 来自查找模块,混合模式添加它们自己的字段)。旨在供操作员和调试使用,而非监控(使用 Prometheus 指标获取时间序列数据 — 参见 可观察性)。
响应 (200 OK):
{
"is_healthy": true,
"engine_type": "MPCacheServer",
"chunk_size": 256,
"hash_algorithm": "builtin-hash",
"active_sessions": 2,
"registered_gpu_ids": [0, 1],
"cache_context_meta": {
"0": {
"model_name": "meta-llama/Llama-3.1-8B-Instruct",
"world_size": 1,
"kv_cache_layout": {
"num_layers": 32,
"num_blocks": 12345,
"cache_size_per_token": 131072,
"kernel_groups": [
{
"kernel_group_idx": 0,
"engine_group_idx": 0,
"object_group_idx": 0,
"num_layers": 32,
"layer_indices": [0, 1, "..."],
"tokens_per_block": 16,
"slots_per_block": 16,
"dtype": "torch.bfloat16",
"engine_kv_concrete_shape": "...",
"is_mla": false,
"engine_kv_format": "...",
"engine_kv_shape": "...",
"attention_backend": "..."
}
]
}
}
},
"active_prefetch_jobs": 0,
"storage_manager": {
"is_healthy": true,
"...": "backend-specific fields"
}
}
响应 (503 服务不可用) 当引擎尚未初始化时:
{
"error": "engine not initialized"
}
HTTP 状态码:
200: 状态快照已返回。503: 引擎尚未在app.state上初始化。
示例:
curl -s http://localhost:8080/status | jq
GET /config#
以单一缩进 JSON 文档返回注册在 app.state.configs 上的全部服务器端配置对象(通常包括 mp、storage_manager 和 observability)。数据类通过 safe_asdict 序列化;其他值通过 make_json_safe 处理。可用于确认进程实际加载的配置内容(含环境变量覆盖),无需重启服务。
响应 (200 OK):
{
"mp": {
"http_host": "0.0.0.0",
"http_port": 8080,
"...": "..."
},
"storage_manager": {
"...": "..."
},
"observability": {
"...": "..."
}
}
响应(503 服务不可用),当配置尚未连接到 app.state 时:
{
"error": "configs not initialized"
}
HTTP 状态码:
200: 配置文档已返回。503: 配置尚未连接到app.state。
示例:
curl -s http://localhost:8080/config | jq
GET /config/adapters#
列出引擎已加载的每个 L2 适配器,按配置顺序排列。加载了哪些存储后端是配置检查的内容,因此它位于配置组中,而不是在 /cache 下。这是唯一的活动适配器列表;它取代了旧的 GET /reconfigure/backends``(可重新配置的后端是 ``type_name 值,其 reconfigurable 标志为 true)。
响应 (200 OK):
{
"adapters": [
{"index": 0, "type_name": "S3L2Adapter", "tier": "l2", "primary": true, "reconfigurable": false},
{"index": 1, "type_name": "dax", "tier": "l2", "primary": false, "reconfigurable": true}
]
}
primary is true only on the first entry. reconfigurable is
true for adapters that accept /reconfigure operations — pass that
adapter's type_name as the {backend} path parameter to
GET /reconfigure/{backend}/l2/status and the reconfigure operations. An
engine that has no L2 backends returns {"adapters": []} (still 200 —
the engine is initialized, it just has no L2 storage).
HTTP 状态码:
200: 成功(包括无适配器的情况)。503: 引擎未初始化。
示例:
curl -s http://localhost:8080/config/adapters | jq
GET /version, GET /lmc_version, GET /commit_id#
版本描述符。每个返回一个裸 JSON 字符串(而不是对象):
GET /version— 来自lmcache.utils.get_version()的组合描述符,格式为\"<version>-<commit_id>\"(例如\"0.3.1-ca79ea33\")。在没有构建时版本元数据的源代码检出中,每个缺失的组件将回退为字面值\"NA\"(因此没有元数据的构建返回\"NA-NA\")。GET /lmc_version— 原始包版本字符串 (lmcache.utils.VERSION);当生成的lmcache._version模块缺失时返回空字符串\"\"。GET /commit_id— 构建中嵌入的 git 提交 ID (lmcache.utils.COMMIT_ID);当不可用时为空字符串\"\"。
这三者都是无条件的 200 OK。
响应 (200 OK):
"0.3.1-ca79ea33"
HTTP 状态码:
200: 返回的版本字符串(对所有三个路由无条件)。
示例:
curl -s http://localhost:8080/version
curl -s http://localhost:8080/lmc_version
curl -s http://localhost:8080/commit_id
缓存管理#
POST /cache/clear#
Clears KV cache data currently held in a tier (today l1). Set
force=true to clear locked objects too.
警告
By default, this endpoint clears only objects that are safe to remove.
With force=true, it is destructive and bypasses read/write locks.
In-flight store or prefetch operations may be corrupted. Use forced
cleanup only when the server is idle, or when recovering from a
known-bad cache state.
请求体: 可选 -- 缺失(或空)体将使用以下默认值。
字段 |
类型 |
描述 |
|---|---|---|
|
字符串 |
可选(默认 |
|
布尔值 |
Optional (default |
响应 (200 OK):
{"status": "ok", "cleared": {"tier": "l1"}}
HTTP 状态码:
200: 层已清除。400: 不支持的tier``(除了 ``l1以外的任何内容)。503: 服务器未初始化 ({\"detail\": \"服务器未初始化\"})。
示例:
# the body is optional; this clears the default tier (l1)
curl -s -X POST http://localhost:8080/cache/clear
POST /cache/checksums#
计算引擎 KV Cache 的 MD5 校验和,每个哈希块分组为 chunk_size 块。MP 模式通过块 ID 原生地访问 KV 存储(与 STORE / RETRIEVE 使用的单位相同),因此该端点完全以块为中心。旨在用于诊断和来自 lmcache bench server 的往返完整性检查——不用于推理数据路径。
请求主体:
字段 |
必需的 |
描述 |
|---|---|---|
|
是 |
引擎块 ID 作为整数的 JSON 列表,例如 |
|
是 |
正整数 — 每个哈希块的块数。 |
|
否(默认 |
引擎上注册的 KV 上下文 ID。 |
|
否(默认 |
如果为 |
响应 (200 OK):
{
"status": "success",
"chunk_size": 2,
"num_chunks": 2,
"chunk_checksums": ["<md5>", "<md5>"],
"layerwise": false,
"block_id_ranges": "0,[2,5],8"
}
当 layerwise=true 时,chunk_checksums 是一个以 "layer_<idx>" 为键的字典,其值是逐层列表。
HTTP 状态码:
200: 成功。400:block_ids为空,或者chunk_size缺失或非正数。404:instance_id未注册,或者注册的 KV 张量为空。501: 引擎没有cache_contexts,或者该端点不支持 KV 格式(页面缓冲融合和跨层布局在真正需要之前被拒绝)。503: 引擎尚未在app.state上初始化。
示例:
curl -s -X POST http://localhost:8080/cache/checksums \
-H 'Content-Type: application/json' \
-d '{"block_ids": [0, 1, 2, 3], "chunk_size": 2}'
缓存对象和预取#
两个端点 — DELETE /cache/objects 和 GET /cache/objects — 允许操作员从配置的缓存后端中清除键并列举当前驻留的内容。(要列举配置的后端本身,请在配置组中使用 GET /config/adapters。)
另一对 — POST /cache/prefetches 和 GET /cache/prefetches/{request_id} — 允许操作员(或协调者)**预热**节点的 L1 以便在流量到来之前从 L2 加载,并轮询加载直到完成;它们在本节末尾有文档说明。协调者提供了一个基于 instance_id 的变体 — 参见 多服务器协调。
两个对象端点都接受一个可选的 adapter 选择器 — 在 GET /cache/objects 上的查询参数(?adapter=<type_name>)和在 DELETE /cache/objects 上的主体字段。省略它将针对 **主要**(首次配置的)适配器。当多个适配器共享同一个 type_name 时,第一个匹配的适配器将生效。使用 GET /config/adapters 来了解有效的选择器。
这两个接口旨在用于操作员/管理员工作流程(“清除该用户的键”,“显示当前驻留的内容”,“在重命名后收集孤儿”)。它们**不**在推理数据路径上。
DELETE /cache/objects 从 L1、L2 或两者中删除,具体取决于其 tier 字段(默认为 l2)。GET /cache/objects 仅列出 L2。
The coordinator's eviction loop uses DELETE /cache/objects automatically (see
多服务器协调 — "L2 usage tracking and eviction"). Manual curl
usage is reserved for ad-hoc operator actions and debugging.
DELETE /cache/objects#
从 L1、L2 或两者(tier)中删除调用者提供的键列表。幂等:缺失的键会被静默跳过。L2 删除会跳过被正在进行的存储/加载任务锁定的键,因此活动传输不会被损坏;L1 删除会跳过被读/写锁定的键,除非设置了 force。阻塞适配器 I/O 在事件循环之外运行。当层级包含 L2 时,必须配置主要(或选择的)L2 适配器,否则返回 503;纯 l1 删除不需要适配器。
Per-key successful L2 deletions fire on_l2_keys_deleted on the
adapter's listeners — when the coordinator is wired (see
--coordinator-event-reporting), the deletions show up at the
coordinator's POST /events as delete events. The
coordinator's eviction + usage trackers learn about the deletion from
that event flow, not from the response of this call.
请求主体:
字段 |
类型 |
描述 |
|---|---|---|
|
列表[编码对象键] |
必填。要删除的对象键(见下方模式)。每个请求的批量限制为 |
|
字符串 |
可选(默认 |
|
布尔值 |
可选(默认 |
|
字符串 |
可选(默认:主,首次配置的适配器)。目标 L2 适配器的 |
每个 EncodedObjectKey 是
{
"chunk_hash_hex": "abc123...",
"model_name": "meta-llama/Llama-3-8B",
"kv_rank": 0,
"object_group_id": 0,
"cache_salt": "user-a"
}
object_group_id``(默认 ``0)和 cache_salt``(默认 ``"")是为了与旧的 wire 负载向后兼容而可选的。
响应 (200 OK):
{
"deleted": 4,
"skipped": 0,
"ok": true
}
deleted 是在请求的层级中移除的总键数(L1 移除加上 L2 批量大小);skipped 是因为被锁定而拒绝的 L1 键(仅限非强制)。在 L2 适配器失败时,响应仍然是 200,并且 ok=false,同时 error 字段携带原因。
HTTP 状态码:
200: 请求已处理(检查ok以获取 L2 适配器的结果)。400: 批量超出限制,或者一个键负载违反了ObjectKey不变式(错误的十六进制,model_name中的@,禁止的cache_salt字符)。404: ``adapter``(主体)与任何已配置的适配器不匹配。422: Pydantic 级别的主体形状失败(缺少keys,字段类型错误)。503: 引擎未初始化,或未配置 L2 适配器(仅当tier包含 L2 时)。
示例: 从两个层级中删除。
curl -s -X DELETE http://localhost:8080/cache/objects \
-H 'Content-Type: application/json' \
-d '{
"tier": "all",
"keys": [
{"chunk_hash_hex": "aa", "model_name": "m",
"kv_rank": 0, "object_group_id": 0, "cache_salt": "user-a"}
]
}'
# -> {"deleted": 2, "skipped": 0, "ok": true}
GET /cache/objects#
分页当前驻留在一个 L2 适配器中的键。
查询参数:
名称 |
默认 |
描述 |
|---|---|---|
|
主适配器 |
目标适配器的 |
|
无 |
将结果限制为与 |
|
|
每页最大条目数。必须在 |
|
无 |
来自上一页的 |
页面令牌是适配器私有的;请勿解析或修改它。支持列出功能的适配器(目前仅通过 ListObjectsV2 的 S3 适配器)保证尽力而为的一致性,而不是快照隔离——在分页遍历期间的并发存储或删除可能导致键出现、消失或在页面之间移动。
响应 (200 OK):
{
"adapter": "S3L2Adapter",
"entries": [
{
"key": {
"chunk_hash_hex": "abc123",
"model_name": "meta-llama/Llama-3-8B",
"kv_rank": 0,
"object_group_id": 0,
"cache_salt": "user-a"
},
"size_bytes": 4194304
}
],
"next_page_token": "opaque-cursor-string"
}
next_page_token 在列出内容耗尽时为 null。
HTTP 状态码:
200: 成功。400: 错误的page_token(适配器级别)。404:?adapter=<name>与任何已配置的适配器不匹配。422:page_size超出[1, 5000]范围。501: 选定的适配器不支持列出。在 v1 中,只有S3L2Adapter支持;由SerdeL2AdapterWrapper包装的适配器继承被包装适配器的行为。503: 引擎未初始化,或未配置 L2 适配器。
示例: 为模型分页每个键。
next=""
while :; do
page=$(curl -s "http://localhost:8080/cache/objects?model_name=meta-llama/Llama-3-8B&page_size=500&page_token=$next")
echo "$page" | jq '.entries[]'
next=$(echo "$page" | jq -r '.next_page_token // empty')
[ -z "$next" ] && break
done
POST /cache/prefetches#
通过从 L2 提前 加载一个令牌序列的块来预热一个节点的 L1,以便使用它们的第一个请求命中 L1,而不是在线支付 L2 获取的费用。当工作负载即将路由到一个节点(流量转移、热共享系统提示)时,这非常有用。
调用者通过 token ids 描述内容,而不是通过内部缓存键(键是内容哈希加上每个排名的布局位图,调用者无法构造)。服务器对 tokens 进行哈希,将每个块扩展到节点的各个排名,并提交一个 warm 预取:加载的块被 保留**(永久)并保持 **解锁 — 没有下游读取器来固定它们,因此后续的真实查找会自行加锁。调用立即返回;加载在存储管理器自己的线程中运行。它在所有配置的 L2 适配器之间合并,因此没有 ?adapter= 选择器。
请求主体:
字段 |
类型 |
描述 |
|---|---|---|
|
字符串 |
提供的模型 ID,完全按照注册的方式(例如 |
|
整数 |
节点的 KV 布局和排名分发中注册的值 vLLM(对于单 GPU,TP=1 部署为 |
|
列表[int] |
提示令牌 ID。必须使用与存储相同的分词器/特殊令牌设置,并且至少包含一个完整的 |
|
字符串 |
每个租户的密钥隔离;必须与存储匹配(默认 |
响应 (202 Accepted):
{"request_id": "abc123", "chunks": 12, "status": "submitted"}
当序列短于一个块时,不会提交任何内容,也没有 request_id 可供轮询:
{"chunks": 0, "status": "noop"}
HTTP 状态码:
202: 已提交(或如上所述的noop)。400:token_ids超过每个请求的上限,或cache_salt违反了其不变性。409: 未为(model_name, world_size)注册布局 — 该模型尚未在此节点上分配 KV Cache(请先启动 vLLM)。422: 请求体未通过字段级验证。503: 引擎未初始化。
示例:
curl -s -X POST http://localhost:8080/cache/prefetches \
-H 'Content-Type: application/json' \
-d '{"model_name": "Qwen/Qwen3-8B", "world_size": 1,
"token_ids": [101, 102, 103], "cache_salt": "user-a"}'
# -> {"request_id": "abc123", "chunks": 1, "status": "submitted"}
GET /cache/prefetches/{request_id}#
轮询已提交的热预取。热预取不持有锁,因此轮询仅报告进度;第一个观察到完成的轮询将删除作业(精确一次),因此对同一 ID 的后续轮询返回 404。
响应 (200 OK) 当负载运行时:
{"status": "pending"}
…并且一旦完成:
{"status": "completed", "found_keys": 12, "total_keys": 12}
found_keys / total_keys 计数仅包括由此请求 从 L2 加载的 块;已经驻留在 L1 的块在 reserve_write 时被跳过且不计入,因此部分驻留的热请求会低估驻留块的数量(冷请求会加载并计算所有内容)。热请求使用间隙容忍的 SPARSE 剪裁策略,因此一个已经驻留的块不会阻止其他块的加载——它会加载每个尚未驻留的块并报告该数量。不计算驻留块是故意的:一个已经存在的条目可能是来自另一个查找的瞬态临时条目,因此将其视为热请求可能会误导。
HTTP 状态码:
200: 状态报告(pending或completed)。404: 未知request_id— 已经完成并消费,或从未提交。503: 引擎未初始化。
示例:
curl -s http://localhost:8080/cache/prefetches/abc123
# -> {"status": "completed", "found_keys": 1, "total_keys": 1}
配额管理#
这些端点管理由 IsolatedLRU 逐出策略(通过 --eviction-policy IsolatedLRU 选择)消耗的每个 cache_salt 存储预算。配额是 软性 的:设置限制并不会拒绝写入 — 任何超出预算的 cache_salt 会在下一个逐出周期(约 1 秒)被逐出。没有注册配额的 cache_salt 有一个有效限制为 0 字节,因此其数据将在下一个周期被清除(白名单语义)。
对于未使用 --eviction-policy IsolatedLRU 启动的引擎,这些端点为空操作:QuotaManager 仍然存在,但 LRU 策略会忽略已注册的配额。
空盐的 URL 转义。 cache_salt=\"\"(无盐/匿名流量)不能出现在 URL 路径参数中,因此 API 接受哨兵 _default 作为替代。PUT /quota/_default 设置 cache_salt=\"\" 的配额,_default 在空盐的响应中被回显。合法存储数据的用户 cache_salt=\"_default\" 不能通过此 HTTP API 与匿名流量区分管理——两者映射到相同的路径参数;选择任何其他值(例如 \"default\")以消除歧义。
PUT /quota/{cache_salt}#
创建或更新配额。
路径参数: cache_salt — 租户标识符(使用 _default 表示空盐;请参阅章节介绍)。
请求主体:
字段 |
类型 |
描述 |
|---|---|---|
|
浮点数 |
必需。配额以 GB 为单位。必须是有限的且非负的。 |
响应 (200 OK):
{"cache_salt": "alice", "limit_gb": 10.0, "status": "ok"}
HTTP 状态码:
200: 配额已设置或更新。400: JSON 格式错误,缺少limit_gb,limit_gb非数字,nan/inf,或负值。503: 引擎未初始化。
示例:
curl -s -X PUT http://localhost:8080/quota/alice \
-H 'Content-Type: application/json' \
-d '{"limit_gb": 10.0}'
GET /quota/{cache_salt}#
读取当前配额和一个 cache_salt 的实时使用情况。
路径参数: cache_salt — 租户标识符(使用 _default 表示空盐)。
响应 (200 OK):
{
"cache_salt": "alice",
"limit_gb": 10.0,
"current_usage_gb": 2.137,
"exists": true
}
exists 为 false 当这个 cache_salt 从未注册过配额时(limit_gb 此时为 0.0,而 current_usage_gb 反映当前为该盐缓存的字节数——这些字节将在下一个周期下逐出 IsolatedLRU)。这个端点对于未知的盐永远不会返回 404。
HTTP 状态码:
200: 返回配额和使用情况(即使盐没有注册配额——此时exists为false;永远不会404)。503: 引擎未初始化。
示例:
curl -s http://localhost:8080/quota/alice | jq
DELETE /quota/{cache_salt}#
删除 cache_salt 的配额条目。任何仍然缓存于此 cache_salt 下的字节将在下一个逐出周期中超出预算(有效限制降至 0),并将被逐出。
路径参数: cache_salt — 租户标识符(使用 _default 表示空盐)。
响应 (200 OK):
{"cache_salt": "alice", "status": "removed"}
当给定的 cache_salt 没有注册配额时,响应为 {\"cache_salt\": \"...\", \"status\": \"not_found\"}(仍然是 200 OK)。
HTTP 状态码:
200: 配额条目已移除 ("removed") 或不存在 ("not_found");永远不会是404。503: 引擎未初始化。
示例:
curl -s -X DELETE http://localhost:8080/quota/alice
GET /quota#
列出每个注册的配额及其实时使用情况。
响应 (200 OK):
{
"users": {
"alice": {"limit_gb": 10.0, "current_usage_gb": 2.137},
"bob": {"limit_gb": 4.0, "current_usage_gb": 0.812}
}
}
只有带有 注册 配额的 cache_salt 值会出现;空盐会在 _default 键下报告。
HTTP 状态码:
200: 返回配额列表 ({\"users\": {}}当没有注册时)。503: 引擎未初始化。
示例:
curl -s http://localhost:8080/quota | jq
运行时 L2 重新配置#
这些端点在服务器具有可运行时重新配置的 L2 适配器时可用。它们仅更改 LMCache 的运行时映射和元数据;后端资源如 DAX 设备路径必须已经存在,并且服务器必须能够读取和写入。该端点将 backend、operation 和 JSON 请求体路由到通用 L2 适配器重新配置 API,而后端特定的验证和迁移语义则保留在适配器内部。
Changed: L2 reconfiguration uses /reconfigure/{backend}/l2/status
and /reconfigure/{backend}/l2/{operation}. The previous
/reconfigure/{backend}/status and /reconfigure/{backend}/{operation}
URLs are removed and return 404.
backend 和 operation 路径段被规范化(去除空格并转为小写)。在请求体内,adapter_index(默认为 0)是 后端本地 的——它仅索引该后端的适配器,而不是整个引擎的适配器列表。如果 L2 适配器被序列化/反序列化包装,后端字符串仍然是配置的 L2 适配器类型,而不是序列化/反序列化包装类型。
备注
这里接受的后端字符串通过 GET /config/adapters 发现:每个 reconfigurable 标志为 true 的适配器都可以通过其 type_name 进行访问。
GET /reconfigure/{backend}/l2/status#
报告一个后端类型的运行时可管理适配器。每个适配器条目的 adapter_index 被重写为其 后端本地 的 0 基索引(在操作请求体中传回的值)。
路径参数: backend — 适配器 type_name``(标准化:去除空格并小写;通过 ``GET /config/adapters 发现有效值)。
响应 (200 OK):
{
"enabled": true,
"backend": "dax",
"num_adapters": 1,
"adapters": [
{"adapter_index": 0, "...": "backend-specific adapter fields"}
]
}
一个未知或空的后端返回 enabled=false,num_adapters=0,adapters=[](这不是 404)。
HTTP 状态码:
200:返回的状态(包括上述未知后端的情况)。400:backend为空。503: 引擎未初始化。
示例:
curl -s http://localhost:8080/reconfigure/dax/l2/status | jq
POST /reconfigure/{backend}/l2/{operation}#
将一个重新配置操作应用于后端适配器。请求体是一个 JSON 对象,其接受的字段取决于后端和操作。200 响应是存储管理器的 reconfigure_l2_adapter 返回的内容(一个后端定义的字典)。
路径参数: backend``(适配器 ``type_name)和 operation``(例如 ``add / remove / resize 用于 dax)。两者都经过标准化(去除空格并转为小写)。
对于 通用 路径(任何后端除了 dax),请求体包含 adapter_index 以及任何特定于后端的字段,这些字段会逐字转发给适配器。
对于 Device-DAX (backend=dax),使用 JSON 请求体,因为 DAX 路径包含斜杠。接受的操作和字段包括:
操作 |
主体字段 |
|---|---|
|
|
|
|
|
|
size 接受一个整数字节数或带有基于 1024 的单位后缀的字符串(b、kib、mib、gib、tib 及其 k/m/g/t 别名),例如 "100GiB";它必须解析为一个正值。
响应 (200 OK):
主体是后端的 reconfigure_l2_adapter 结果(一个后端定义的字典)。成功的 DAX add 看起来像这样:
{
"status": "ok",
"operation": "add",
"adapter_index": 0,
"device": {"device_path": "/dev/dax0.0", "state": "active", "size_bytes": 107374182400}
}
HTTP 状态码:
200: 成功(主体是存储管理器的重新配置结果)。400: 空的backend/operation,不支持的 DAX 操作,或无效的size。404:adapter_index超出后端范围。422: 请求体验证失败(例如,缺少必填字段或 DAX 请求体中的未知字段——DAX 请求体会拒绝额外字段)。503: 引擎未初始化。
示例:
curl -s -X POST http://localhost:8080/reconfigure/dax/l2/add \
-H 'Content-Type: application/json' \
-d '{"device_path": "/dev/dax0.0", "size": "100GiB"}'
有关详细的请求示例、模式语义和验证指导,请参阅 设备-DAX (/dev/dax)。
Runtime L1 Reconfiguration (Device-DAX)#
These routes manage the Device-DAX L1 arena pool configured with
--l1-devdax-path. Devices must already be provisioned, and requests do not
use adapter_index.
GET /reconfigure/dax/l1/status#
响应 (200 OK):
{
"arenas": [
{
"device_path": "/dev/dax1.1",
"size_in_bytes": 17179869184,
"used_bytes": 4294967296,
"free_bytes": 12884901888,
"active_allocations": 2048,
"state": "active",
"is_primary": false
}
]
}
POST /reconfigure/dax/l1/add#
Request body: device_path (string) and size (integer byte count or a
string such as "16GiB").
Response (200 OK): {"added": <arena>}.
示例:
curl -s -X POST http://localhost:8080/reconfigure/dax/l1/add \
-H 'Content-Type: application/json' \
-d '{"device_path": "/dev/dax1.2", "size": "16GiB"}'
POST /reconfigure/dax/l1/remove#
Only drain mode is supported. A draining arena accepts no new allocations and is unmapped after its live allocations are freed. The primary arena cannot be removed. Use the exact device path supplied when adding the arena.
Request body: device_path (string) and optional mode (drain;
default drain).
响应 (200 OK):
{
"removed": {
"device_path": "/dev/dax1.2",
"arenas": [
{
"device_path": "/dev/dax1.2",
"state": "draining",
"active_allocations": 3,
"size_in_bytes": 17179869184,
"used_bytes": 6291456,
"free_bytes": 17173577728,
"is_primary": false
}
]
}
}
HTTP 状态码:
200: 成功。400: invalidsize.404: device is not mapped.409: incompatible L1 or device state, or mapping validation failure.422: invalid request body.500: synchronization or cleanup failure after draining starts.503: 引擎未初始化。
See 多服务器协调 for capacity reporting.
可观察性#
GET /metrics#
默认 prometheus_client 注册表中注册的每个指标的 Prometheus 展示格式 (Content-Type: text/plain)。直接从 Prometheus 抓取此数据。有关导出指标的列表,请参见 可观察性。
响应 (200 OK, text/plain): Prometheus 展示格式的指标主体。
HTTP 状态码:
200:返回的指标。
示例:
curl -s http://localhost:8080/metrics
POST /metrics/reset#
将所有 LMCache 可观察性指标重置为初始状态(reset_observability_metrics)。面向测试框架和基准测试,不适用于生产环境。
响应(200 OK, text/plain):
ok
HTTP 状态码:
200:指标已重置。
示例:
curl -s -X POST http://localhost:8080/metrics/reset
诊断与调试#
GET /loglevel#
在运行时检查或修改 Python 日志记录器级别。所有响应都是 text/plain。该端点有三种模式,由查询参数驱动:
查询 |
行为 |
|---|---|
(无参数) |
列出所有在 |
|
返回指定记录器的有效级别。 |
|
将命名的日志记录器(及其处理程序)设置为 |
传递 level 而不带 logger_name 不匹配任何模式,并返回 200 和一个 null 响应体。
响应 (200 OK, text/plain): 每个注册的日志记录器一行 ``<logger>: <LEVEL>``(列表模式),一个 ``<logger>: <LEVEL>``(读取模式),或更新级别的确认(设置模式)。
HTTP 状态码:
200: 列出、读取或设置的级别(也包括上述的null-body 情况)。400:level不是已知的日志级别。
示例:
# list everything
curl -s http://localhost:8080/loglevel
# read one
curl -s 'http://localhost:8080/loglevel?logger_name=lmcache'
# elevate to DEBUG
curl -s 'http://localhost:8080/loglevel?logger_name=lmcache&level=DEBUG'
GET /threads#
列出服务器进程中活动的 Python 线程及其堆栈跟踪,并提供总计摘要(Content-Type: text/plain)。对于实时调试挂起或失控的工作线程非常有用。
查询 |
行为 |
|---|---|
|
仅保留名称包含 |
|
仅保留 |
警告
响应包含实时堆栈跟踪,并可能泄露内部代码路径和状态。在生产环境中限制对该端点的网络访问。
响应 (200 OK, text/plain):总线程数摘要,后面跟着每个线程的名称、ident 和当前堆栈跟踪。
HTTP 状态码:
200: 返回线程列表。
示例:
curl -s 'http://localhost:8080/threads?name=periodic'
GET /periodic-threads#
返回 PeriodicThreadRegistry 的 JSON 快照:按级别统计以及每个线程的状态(上次运行时间戳、最新摘要等)。
查询 |
行为 |
|---|---|
|
仅包含给定级别的线程。对未知情况返回 |
|
仅包含当前正在运行的线程。 |
|
仅包括被视为活动的线程(最近的滴答)。 |
响应 (200 OK):
{
"summary": {
"total_count": 4,
"running_count": 4,
"active_count": 4,
"by_level": {
"critical": {"total": 1, "running": 1, "active": 1},
"high": {"total": 2, "running": 2, "active": 2},
"medium": {"total": 1, "running": 1, "active": 1},
"low": {"total": 0, "running": 0, "active": 0}
}
},
"threads": [
{
"name": "...",
"level": "high",
"interval": 5.0,
"is_running": true,
"is_active": true,
"last_run_ago": 1.2,
"total_runs": 120,
"failed_runs": 0,
"success_rate": 100.0,
"last_summary": {"...": "..."}
}
]
}
HTTP 状态码:
200: 返回快照。400: 未知level过滤器。
示例:
curl -s 'http://localhost:8080/periodic-threads?level=critical' | jq
GET /periodic-threads/{thread_name}#
单个周期性线程的详细状态(与上面 threads 列表中显示的每个线程对象相同)。
路径参数: thread_name — 注册的周期线程名称。
响应 (200 OK):
{
"name": "storage-flush",
"level": "critical",
"interval": 5.0,
"is_running": true,
"is_active": true,
"last_run_ago": 1.2,
"total_runs": 120,
"failed_runs": 0,
"success_rate": 100.0,
"last_summary": {"...": "..."}
}
响应 (404 Not Found) 当名称未知时:
{"error": "Thread not found: <name>"}
HTTP 状态码:
200: 返回的线程状态。404: 没有名为该名称的周期性线程。
示例:
curl -s http://localhost:8080/periodic-threads/storage-flush | jq
GET /periodic-threads-health#
快速健康检查,仅涵盖 critical 和 high 级别的周期性线程。当线程被标记为运行但在预期间隔内未进行计时时,它会被标记为不健康。始终返回 200 — 健康状态通过 healthy 布尔值传达,而不是通过 HTTP 状态。
响应 (200 OK):
{
"healthy": true,
"unhealthy_count": 0,
"unhealthy_threads": []
}
当出现滞后时:
{
"healthy": false,
"unhealthy_count": 1,
"unhealthy_threads": [
{
"name": "storage-flush",
"level": "critical",
"last_run_ago": 42.5,
"interval": 5.0
}
]
}
HTTP 状态码:
200:健康报告 — 始终为200,即使在不健康时(healthy布尔值为false)。
示例:
curl -s http://localhost:8080/periodic-threads-health
GET /env#
将进程环境变量转储为排序后的美观打印 JSON 文档。响应的 Content-Type 为 text/plain,因此可以直接通过管道传输到终端。
警告
有效负载包含 每个 环境变量,包括通过环境注入的任何秘密。没有任何编辑或身份验证 — 在生产环境中限制对该端点的网络访问。
响应(200 OK, text/plain):
{
"HOME": "/root",
"LMCACHE_LOG_LEVEL": "INFO",
"PATH": "/usr/local/bin:/usr/bin"
}
HTTP 状态码:
200: 环境转储已返回。
示例:
curl -s http://localhost:8080/env
POST /run_script#
备注
This endpoint is disabled by default (requests return 404).
Start the server with --run-script-api-enabled to enable it.
在服务器进程中执行上传的 Python 脚本。脚本作为多部分表单数据上传,字段名称为 script,并在受限的 __builtins__ 下被 exec 执行(仅允许 print、str、int、float、list、dict、tuple、set 和受保护的 __import__)。仅允许导入在 --script-allowed-imports 中列出的模块;运行的 FastAPI app 会注入到脚本的全局变量中。如果脚本赋值给名为 result 的变量,则返回其字符串化值;否则返回正文为 "脚本成功执行"(Content-Type: text/plain)。
请求体: 多部分表单数据,包含一个 script 文件字段(要执行的 Python 源代码)。不是 JSON 格式的请求体。
危险
此端点在进程中运行调用者提供的代码。受限的内置函数不是安全沙箱——结合注入的app对象和任何允许的导入,将其视为完全的远程代码执行。切勿在不受信任的网络上公开它。
响应 (200 OK, text/plain): 如果脚本分配了字符串化的 result 变量,则返回该变量,否则返回 脚本成功执行。
HTTP 状态码:
200: 脚本已执行。400: 未提供script文件。404: the endpoint is disabled (--run-script-api-enablednot set).500: 在导入设置或执行期间引发了异常(主体:"执行脚本时出错:<reason>")。
示例:
curl -s -X POST http://localhost:8080/run_script \
-F 'script=@my_script.py'
添加新端点#
端点会从 lmcache/v1/multiprocess/http_apis/ 自动发现。要添加一个新的仅限 MP 的端点:
在该目录中创建一个名为
<name>_api.py的新模块。定义一个模块级的
router = APIRouter()。使用 FastAPI 装饰器在
router上注册处理程序。通过
request.app.state.engine访问引擎,并检查None情况(引擎尚未初始化)。
HTTPAPIRegistry 将在启动时自动加载模块 — 无需编辑中央注册列表。
如果路由足够通用,可以与嵌入 vLLM 的 API 服务器共享,请将其添加到 lmcache/v1/internal_api_server/common/ 下。它将在 MP 端通过 common_api.py 被加载,除非其模块名称在 _MP_INCOMPATIBLE_MODULES 中列出(该列表保留给需要 vLLM 特定 app.state 属性的模块;当前列表为空)。位于 internal_api_server/vllm/ 下的处理程序仍然可以通过从 http_apis/ 下的组模块中包含其路由器在 MP 服务器上显示(如 info_api.py 对版本端点所做的那样)。
添加新端点时,请在此页面上添加一个对应的章节,说明该端点的用途、请求/响应结构以及一个示例 curl 调用。