存储插件#

LMCache 支持开箱即用的存储后端,如 Mooncake、S3 和 NIXL。LMCache 存储插件系统提供通过动态加载或即插即用能力添加自定义存储后端的功能。换句话说,可以在不修改核心代码的情况下扩展缓存存储能力。

后端定义要求#

  1. 继承自 StoragePluginInterface

  2. 实现 StoragePluginInterface 的父接口 StorageBackendInterface 的所有抽象方法。

  3. 打包为可安装的 Python 模块

备注

接口构造函数是 LMCache 加载系统在加载自定义存储后端时使用的实例化契约。如果您希望实现一个构造函数,它应该具有相同的参数签名并调用接口构造函数。

如何将后端与 LMCache 集成#

  1. 在 LMCache 环境中安装您的后端包

  2. storage_plugins 及其相关的 module_pathclass_name 添加到 LMCache 配置的 extra_config 部分,如下所示:

chunk_size: 64
local_cpu: False
max_local_cpu_size: 5
storage_plugins: <backend_name>
extra_config:
  storage_plugin.<backend_name>.module_path: <module_path>
  storage_plugin.<backend_name>.class_name: <class_name>

日志后端的示例配置如下:

chunk_size: 64
local_cpu: False
max_local_cpu_size: 5
storage_plugins: "log_backend"
extra_config:
  storage_plugin.log_backend.module_path: lmc_external_log_backend.lmc_external_log_backend
  storage_plugin.log_backend.class_name: ExternalLogBackend

备注

  • 存储后端在 LMCache 启动时按顺序初始化 - 较早的后端在缓存查找中具有更高的优先级

  • storage_plugin.<backend_name> 区分不同的动态加载后端

后端实现示例#

可以在 https://github.com/opendataio/lmc_external_log_backend/ 查看一个示例自定义后端实现。

MP-模式 L2 适配器插件 (plugin)#

上述描述的存储插件系统适用于 **非 MP 模式**(单进程)。对于 **MP 模式**(多进程),LMCache 提供了 plugin L2 适配器类型,该类型在运行时动态加载第三方 L2AdapterInterface 实现。

概述#

plugin 适配器类型允许您将完整的 L2 适配器作为 单独的、可通过 pip 安装的包 进行发布。在启动时,LMCache 导入您的模块,实例化您的适配器类,并像使用内置适配器一样使用它 -- 无需对 LMCache 源代码进行修改。

备注

如果您的存储后端是一个原生的 C++ 连接器(使用 pybind 封装),请考虑使用 native_plugin 类型(请参见 添加本地连接器)。它重用了内置的桥接逻辑,因此您只需实现 6 个连接器方法,而不是完整的 L2AdapterInterface

配置#

{
  "type": "plugin",
  "module_path": "my_plugin.adapter",
  "class_name": "MyL2Adapter",
  "adapter_params": {
    "host": "localhost",
    "capacity": 1000
  }
}
PluginL2AdapterConfig 字段#

字段

类型

必需的

描述

module_path

str

适配器类所在模块的点分 Python 导入路径。

class_name

str

module_path 中实现 L2AdapterInterface 的类的名称。

adapter_params

dict

转发到适配器类构造函数(作为类型化配置或原始字典)。

config_class_name

str

显式配置类名称;当省略时,工厂会自动发现它。

配置类自动发现#

工厂会自动使用以下优先级链解析适配器的配置类(第一个匹配的优先):

  1. 显式 config_class_name 字段在 JSON 配置中。

  2. 约定:适配器类名 + "Config" 后缀(例如 MyL2Adapter 查找 MyL2AdapterConfig)。

  3. 属性: config_class_name 属性在适配器类本身上。

  4. 后备: 未找到配置类 -- 传递原始 adapter_params 字典。

每个候选项都会在加载的模块中查找,并验证为 L2AdapterConfigBase 子类。这意味着大多数遵循命名约定的插件将 自动 接收一个类型化的配置实例,而无需任何额外的配置。

插件合同#

插件适配器类 必须

  1. lmcache.v1.distributed.l2_adapters.base 子类化 L2AdapterInterface

  2. 实现所有抽象方法:submit_store_taskpop_completed_store_taskssubmit_lookup_and_lock_taskquery_lookup_and_lock_resultsubmit_unlocksubmit_load_taskquery_load_resultclose,以及所有三个事件文件描述符获取器。

  3. 提供 **三个不同的事件 fd**(存储 / 查找 / 加载)。控制器构建 fd -> 适配器 映射;重复会导致事件错误路由。

  4. 确保 线程安全StoreControllerPrefetchController 从不同线程并发调用适配器方法。

  5. 在``__init__``中接受``**kwargs``以保持向前兼容。

插件适配器类 应该

  1. 如果需要异步 I/O,则应创建自己的 asyncio 事件循环和后台线程。

  2. 使用 lmcache.v1.platform 中的 create_event_notifier() 来处理三个事件文件描述符(跨平台:在 Linux 上使用 os.eventfd,在其他地方使用 os.pipe 作为后备)。

  3. close() 中清理所有资源(事件文件描述符、线程、连接)。

加载流程#

CLI / config JSON
  |
  v
PluginL2AdapterConfig.from_dict(d)
  |  validates module_path, class_name, adapter_params
  |
  v
_create_plugin_adapter(config, ...)
  |
  +-- importlib.import_module(config.module_path)
  +-- getattr(module, config.class_name)
  +-- issubclass check against L2AdapterInterface
  |
  +-- _resolve_config_class(module, config, adapter_cls)
  |   +-- 1. config.config_class_name (explicit)
  |   +-- 2. class_name + "Config" (convention)
  |   +-- 3. adapter_cls.config_class_name (attribute)
  |   +-- 4. None (fall back to raw dict)
  |
  +-- [if config class found]
  |   +-- adapter_cls(cfg_cls.from_dict(adapter_params))
  |
  +-- [otherwise]
      +-- adapter_cls(adapter_params)
          |
          v
  L2AdapterInterface instance (ready for use)

最小示例#

# my_plugin/adapter.py
import asyncio
import threading

from lmcache.native_storage_ops import Bitmap
from lmcache.v1.distributed.l2_adapters.base import (
    L2AdapterInterface,
    L2TaskId,
)
from lmcache.v1.platform import create_event_notifier


class MyL2Adapter(L2AdapterInterface):
    def __init__(self, params, **_kw):
        self._store_efd = create_event_notifier()
        self._lookup_efd = create_event_notifier()
        self._load_efd = create_event_notifier()
        # ... set up connection, background thread, etc.

    # implement all abstract methods ...

    def close(self) -> None:
        self._store_efd.close()
        self._lookup_efd.close()
        self._load_efd.close()

通过 CLI 启动:

--l2-adapter '{
  "type": "plugin",
  "module_path": "my_plugin.adapter",
  "class_name": "MyL2Adapter",
  "adapter_params": {"host": "localhost"}
}'

参考实现#

请参阅 examples/lmc_external_l2_adapter/ 以获取完整的、可通过 pip 安装的示例插件 (InMemoryL2Adapter),该插件演示了:

  • 可配置容量的 FIFO 逐出。

  • 用于现实测试的模拟带宽延迟。

  • 后台 asyncio 事件循环及其正确关闭。

  • 全面的测试套件,涵盖存储、查找、加载、批量操作和逐出行为。

附加资源#

  • 插件适配器源代码:lmcache/v1/distributed/l2_adapters/plugin_l2_adapter.py

  • 原生插件适配器: lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py

  • 设计文档:lmcache/v1/distributed/l2_adapters/design_docs/plugin.md

  • L2 适配器基础接口: lmcache/v1/distributed/l2_adapters/base.py