# SPDX-License-Identifier: Apache-2.0

设备-DAX (/dev/dax)#

概述#

DAX 存储插件通过 mmap(MAP_SHARED) 映射 /dev/dax 设备,并将映射区域用作 KV Cache 块的固定大小区域。典型的 /dev/dax 设备包括持久内存、CXL 附加内存和其他字节可寻址内存设备。

存储在 DAX 设备上的数据可能在进程重启后仍然存在,但不保证其持久性。

KV Cache 数据作为后端存储流程的一部分存储在 DAX 区域。读取操作会将数据复制回 CPU 内存对象。

配置#

local_cpu: true
max_local_cpu_size: 80

storage_plugins: ["dax"]
extra_config:
  storage_plugin.dax.module_path: lmcache.v1.storage_backend.plugins.dax_backend
  storage_plugin.dax.class_name: DaxBackend

  dax.device_path: "/dev/dax1.0"
  dax.max_dax_size: 100
  dax.restore_workers: 8
  dax.restore_max_regions: 8
  dax.retrieve_staging_slab_bytes: 268435456

多进程模式#

在 LMCache 多进程模式下,Device-DAX 被配置为名为 dax 的内置 L2 适配器。MP 适配器使用正常的 L2 适配器 submit -> event fd -> query 合同;不需要 vLLM 连接器协议的更改。

lmcache server \
  --l1-size-gb 80 \
  --eviction-policy LRU \
  --l2-adapter '{
    "type": "dax",
    "device_path": "/dev/dax1.0",
    "max_dax_size_gb": 100,
    "slot_bytes": 268435456,
    "num_store_workers": 1,
    "num_lookup_workers": 1,
    "num_load_workers": 4
  }'

--l2-adapter JSON 接受以下字段:

  • device_path: 必须可读写的 DAX 设备路径。

  • max_dax_size_gb: 必需的映射大小,以 GiB 为单位。当可以通过 fstat 确定容量时,值必须适合设备容量。

  • slot_bytes: 所需的固定槽大小(以字节为单位)。它必须足够大,以容纳一个完整的 LMCache 块。

  • num_store_workers: 可选的存储工作线程数量,默认值为 1

  • num_lookup_workers: 可选查找工作线程数量,默认为 1

  • num_load_workers: 可选的加载工作线程数量,默认 min(4, os.cpu_count())

  • persist_enabled: 被通用 MP L2 解析接受,但在此版本中被 dax 忽略。

MP DAX 在内存中存储不透明的 ObjectKey 值,并且在此版本中仅为易失性。关闭并重新打开同一路径上的服务器时,索引将为空,因此之前写入的字节在重启后无法被发现。

MP DAX 每个 LMCache 服务器使用一个映射的设备路径。它不添加每个 TP 的 DAX 分区、多设备条带、设备内元数据或重启恢复。容量管理和逐出是基于插槽的:即使存储对象的有效负载小于 slot_bytes,它仍占用一个插槽。

使用批量恢复路径#

当前的 DAX 优化是一个分阶段的批量恢复路径,用于检索。只要配置了 DAX 后端,它会自动启用。无需额外的功能标志。

检索流程是:

  1. 保留一组可读的 DAX 块。

  2. LocalCPUBackend 分配 CPU 恢复缓冲区。

  3. 将 DAX 数据复制到后端拥有的固定暂存块中的合并区域。

  4. 从暂存块复制到最终的 CPU MemoryObj 输出。

  5. 通过正常的 GPU 连接器路径上传这些 CPU 输出。

存储流程保持不变:KV 数据仍然通过 CPU 内存进行暂存,然后写入 DAX 区域。

新的 DAX 调优控制批量恢复路径的旋钮:

  • dax.restore_workers: 用于并行执行恢复区域的持久工作线程数量。

  • dax.restore_max_regions: 一次波次中最大恢复区域的数量。较大的值会增加并行性,但也会增加 slab 空间的需求。

  • dax.retrieve_staging_slab_bytes: 可重用的固定检索块的总大小(以字节为单位)。这必须足够大,以容纳每个配置的恢复区域的一个完整块。

对于第一次尝试,从以下开始:

  • dax.restore_workers 等于您希望用于 DAX 恢复的 CPU 工作线程数量

  • dax.restore_max_regions 等于 dax.restore_workers

  • dax.retrieve_staging_slab_bytes 至少为 dax.restore_max_regions * full_chunk_size,如果批量恢复较大,则向上调整。

如果提取吞吐量较低,首先增加块大小,然后一起增加工作线程和区域数量。如果 CPU 压力较高,减少 dax.restore_workersdax.restore_max_regions

运行时要求#

  • extra_config['dax.device_path'] 是必需的,并且必须指向一个可读写的 DAX 设备。

  • 该进程必须对 DAX 设备具有读写访问权限(例如,通过适当的权限或组成员资格)。

  • LocalCPUBackend 必须启用,因为 DAX 读取返回的是 CPU 支持的内存对象。

验证和当前限制#

  • 当前张量并行性仅限于 TP=1 (metadata.world_size == 1)。

  • 仅支持单张量块布局。多张量放置请求将被拒绝。

  • 批量恢复使用后端拥有的检索暂存块和持久恢复执行器。可以通过 dax.restore_workersdax.restore_max_regionsdax.retrieve_staging_slab_bytes 调整暂存块和区域数量。

  • 阻塞批量恢复保留了位置输出语义,而异步批量恢复仅返回连续的命中前缀。