快速开始#

我们以轻量级模型 Qwen/Qwen2.5-1.5B-Instruct 开始,演示vLLM和SGLang环境下CT-HPKV的使用。在启动推理引擎服务之前,我们需要对环境做一些简单配置:

准备工作#

KV Cache存储路径#

CT-HPKV支持将KV Cache数据卸载到内存(DRAM)和高性能存储(SSD/HPFS)中,存储侧KV Cache文件的读写使用标准的POSIX接口。因 此,如果我们需要(默认开启)将KV Cache卸载到存储系统,需要显式指定KV Cache文件的存储路径。在CT-HPKV中,我们通过设置环境变 量或配置文件来达到该目的:

  • 环境变量

# 假设将KV Cache文件存储到"/mnt/hpkv/storage"目录
(base) hpkv@ctyunos:~$ export HPKV_KV_STORAGE_PATH="/mnt/hpkv/storage"

重要

  • 若未显式设置HPKV_KV_STORAGE_PATH,默认路径为"~/.cache/hpkv/storage";

  • 确保当前用户对HPKV_KV_STORAGE_PATH指定的路径有读写权限;

  • HPKV_KV_STORAGE_PATH指定的路径需要是高速存储设备,如SSD、HPFS等,不建议NAS、HDD等低速存储;

  • 配置文件

如果我们的推理引擎业务模式相对固定,或者部署工程师更喜欢配置文件的形式,我们可以将所有的配置信息写入配置文件中,然后在启动 HPKV Server时,让程序自行读取其中的配置项。CT-HPKV配置文件采用 .ini 格式,以键值对的形式进行保存。以配置KV Cache 文件存储路径为例,我们可以在 .ini 文件中添加如下内容:

# 假设在"~/config.ini"中添加如下配置
HPKV_KV_STORAGE_PATH=~/.cache/hpkv/storage

CT-HPKV应用默认会读取 ~/.config/hpkv/config.ini 配置文件的内容,如果配置文件不存在或者配置项不存在,会再尝试读取 环境变量的值;如果环境变量也没有,则使用默认值。因此,我们可以将上述编写的 config.ini 文件移动到 ~/.config/hpkv 路 径下,或在启动CT-HPKV应用时,通过环境变量显式指定配置文件路径:

# 显式指定配置文件路径
(base) hpkv@ctyunos:~$ export VLLM_ENABLE_HPKV=1     \
         export HPKV_CONFIG_FILE_PATH="~/config.ini" \
         vllm serve ...

文件系统类型#

CT-HPKV在设计时,为了提高内存性能,不允许操作系统将内存池的内存交换到磁盘空间。我们采用将共享内存文件存放于ramfs文件系统路径下, 并将内存池注册为锁页内存(Pin Memory)的方式提升性能。因此,我们在使用CT-HPKV前,需要选择一个空的目录,将其文件系统类型挂载为 ramfs类型:

# 文件系统类型挂载(假设挂载到"/mnt/hpkv")
(base) hpkv@ctyunos:~$ mount -t ramfs nodev /mnt/hpkv


# 确认文件系统类型挂载成功
(base) hpkv@ctyunos:~$ mount | grep ramfs
ramfs on /mnt/hpkv type ramfs (rw,nosuid,nodev,noexec,relatime,mode=700)

重要

  • mount 挂载命令通常需要管理员权限;

  • 确保当前用户对挂载的路径有读写权限;

  • 如果操作系统内核版本为5.15+, 需要挂载为 tempfs 类型;

  • 启动推理引擎时,需要使用 export HPKV_SHARE_MEM_FILE_PATH="/mnt/hpkv" 方式指定该路径;

至此,所有准备工作就绪。

推理服务启动#

vLLM启动#

# 配置vLLM启用CT-HPKV
(base) hpkv@ctyunos:~$ export VLLM_ENABLE_HPKV=1

# 配置使用的内存池大小 (8G大小)
(base) hpkv@ctyunos:~$ export HPKV_KV_MEM_POOL_SIZE=8g

# 配置共享内存文件路径
(base) hpkv@ctyunos:~$ export HPKV_SHARE_MEM_FILE_PATH="/mnt/hpkv"

# 配置KV Cache文件存储路径
(base) hpkv@ctyunos:~$ export HPKV_KV_STORAGE_PATH="/mnt/hpkv/storage"

# 启动vLLM
(base) hpkv@ctyunos:~$ vllm serve /mnt/data/models/Qwen/Qwen2.5-1.5B-Instruct \
                    --host 0.0.0.0  --port 8505  --trust-remote-code          \
                    --served-model-name qwen2.5-1.5b --block-size 32          \
                    --max-num-batched-tokens 8192                             \
                    --gpu-memory-utilization 0.8                              \
                    --enable-prefix-caching                                   \
                    --kv-transfer-config '{"kv_connector":"HpkvConnectorV1", "kv_role":"kv_both"}' \
                    --disable-log-requests

重要

由于vLLM V1性能远超V0,且在较新的vLLM版本中已将V0废弃,因此CT-HPKV只适配了vLLM V1。

此时,我们尝试发送一个较长的提示词请求,查看 /mnt/hpkv/storage 路径下的变化,会发现有对应的KV Cache文件生成。

重要

CT-HPKV Server中,有一项名为 VLLM_HPKV_TOKEN_THRESHOLD 的配置,其含义为:在启用CT-HPKV功能时,如果 CT-HPKV命中的词元数量大于等于该值,本次推理请求才从CT-HPKV中加载对应的KV Cache数据到显存,供本次推理复用。如果 命中的词元数量小于该值,则考虑使用AI进行Prefill重计算,而不采用CT-HPKV中缓存的KV Cache数据。该项配置着重考虑计算 与内存加载的平衡。CPU与AI芯片之间通常通过PCIe协议互联,以常见的PCIe Gen 4.0 x16(单向单宽32GB/s)和Gen5.0 x16 (单向带宽64GB/s)为例,数据从内存加载到显存需要一定的时间,如果加载时间甚至超过GPU计算对应词元的时间,则采用计算的 方式更划算。该阈值默认值为1204。用户可根据模型种类、PCIe带宽、实际场景等情况自行调整。

重要

Ascend NPU环境下, vLLM启动方式与上述一致。

SGLang启动#

NVIDIA GPU#

# 配置使用的内存池大小 (8G大小)
(base) hpkv@ctyunos:~$ export HPKV_KV_MEM_POOL_SIZE=8g

# 配置共享内存文件路径
(base) hpkv@ctyunos:~$ export HPKV_SHARE_MEM_FILE_PATH="/mnt/hpkv"

# 配置KV Cache文件存储路径
(base) hpkv@ctyunos:~$ export HPKV_KV_STORAGE_PATH="/mnt/hpkv/storage"

# 对应的命令行调用方式
(base) hpkv@ctyunos:~$ sglang serve --model-path  --enable-ct-hpkv \
                    /mnt/data/models/Qwen/Qwen2.5-1.5B-Instruct    \
                    --host 0.0.0.0 --port 8000 --page-size 64      \
                    --served-model-name qwen2.5-1.5b

Ascend NPU#

# Ascend相关配置
(base) hpkv@ctyunos:~$ export SGLANG_SET_CPU_AFFINITY=1
(base) hpkv@ctyunos:~$ export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
(base) hpkv@ctyunos:~$ export STREAMS_PER_DEVICE=32

# 配置使用的内存池大小 (8G大小)
(base) hpkv@ctyunos:~$ export HPKV_KV_MEM_POOL_SIZE=8g

# 配置共享内存文件路径
(base) hpkv@ctyunos:~$ export HPKV_SHARE_MEM_FILE_PATH="/mnt/hpkv"

# 配置KV Cache文件存储路径
(base) hpkv@ctyunos:~$ export HPKV_KV_STORAGE_PATH="/mnt/hpkv/storage"

# 对应的命令行调用方式
(base) hpkv@ctyunos:~$ sglang serve --model-path  --enable-ct-hpkv \
                    /mnt/data/models/Qwen/Qwen2.5-1.5B-Instruct    \
                    --host 0.0.0.0 --port 8000 --page-size 64      \
                    --served-model-name qwen2.5-1.5b               \
                    --device npu --attention-backend ascend

内存命中#

默认情况下,一个请求推理结束后,对应Prefill和Decode阶段词元的KV Cache信息会保存在显存Prefix Cache、内存和存储中。 如果一个新的推理请求进来,KV Cache匹配的优先级是显存 > 内存 > 存储。因此,如果我们想查看对应层级的KV Cache命中 时的推理,我们需要将上一级的KV Cache数据清除。假设我想查看内存KV Cache命中的结果,我需要将显存中的KV Cache数据清除。 恰好,vLLM在服务的端点中提供了一个名为 reset_prefix_cache 的接口,我们通过提交Post请求,显式清除显存中的所有 KV Cache数据。在SGLang中提供了 flush_cache 接口实现同样的功能。不同的是,SGLang的 flush_cache 接口 在默认情况下就开启,vLLM则需要启动调试模式,reset_prefix_cache 接口才可见,如下:

# vLLM 开启调试模式
(base) hpkv@ctyunos:~$ export VLLM_SERVER_DEV_MODE=1

# 其余启动配置不变
# 配置vLLM启用CT-HPKV
(base) hpkv@ctyunos:~$ export VLLM_ENABLE_HPKV=1

# 配置使用的内存池大小 (8G大小)
(base) hpkv@ctyunos:~$ export HPKV_KV_MEM_POOL_SIZE=8g

# 配置共享内存文件路径
(base) hpkv@ctyunos:~$ export HPKV_SHARE_MEM_FILE_PATH="/mnt/hpkv"

# 配置KV Cache文件存储路径
(base) hpkv@ctyunos:~$ export HPKV_KV_STORAGE_PATH="/mnt/hpkv/storage"

# 启动vLLM
(base) hpkv@ctyunos:~$ vllm serve /mnt/data/models/Qwen/Qwen2.5-1.5B-Instruct \
                    --host 0.0.0.0  --port 8505  --trust-remote-code          \
                    --served-model-name qwen2.5-1.5b --block-size 32          \
                    --max-num-batched-tokens 8192                             \
                    --gpu-memory-utilization 0.8                              \
                    --enable-prefix-caching                                   \
                    --kv-transfer-config '{"kv_connector":"HpkvConnectorV1", "kv_role":"kv_both"}' \
                    --disable-log-requests

此时,我们可以先发送一个长请求,待推理完成后确保该请求对应词元的KV Cache信息已经卸载到CT-HPKV,然后分别使用如下请求清除 vLLM和SGLang显存中的KV Cache数据:

# vLLM 清除显存KV Cache
(base) hpkv@ctyunos:~$ curl --location --request POST 'http://localhost:8000/reset_prefix_cache'


# SGLang 清除显存KV Cache
(base) hpkv@ctyunos:~$ curl --location --request POST 'http://localhost:8000/flush_cache'

此时,显存中的KV Cache数据已经清除,重复发送一个上一个长请求, 推理引擎将尝试从内存中加载对应的KV Cache数据到显存并执行推理。

存储命中#

要测试存储命中,则需要保证显存和内存中同时不存在发送请求对应词元的KV Cache数据。显存KV Cache数据可以调用接口清除,内存侧没有 相应的清除接口,我们可以采用重启推理引擎的方式来实现(二次启动的KV Cache存储路径要与之前保持一致)。