基于鲲鹏服务器的Milvus数据库调优参考实践
发表于 2026/06/30
0
1 非商用声明
该文档提供的内容为参考实践,仅供用户参考使用,可参考实践文档构建自己的软件,按需进行安全、可靠性加固。
2 方案概述
2.1 背景
鲲鹏920新型号服务器是华为新一代高性能服务器,相比鲲鹏920服务器,它支持开启超线程,通过开启超线程模式,可以虚拟出两倍物理核的CPU,拥有更高的并发性能。
Milvus是一款高性能、易扩展的开源向量数据库,专为海量向量数据的相似性搜索和人工智能应用而设计。同时,Milvus作为业界主流的开源向量数据库,被广大ISV伙伴及客户所采用,支持Witty RAG方案对接Milvus数据库。
鲲鹏BoostKit加速库对于向量数据库Milvus开发了一些特性支持如鲲鹏KBest索引算法、鲲鹏KScaNN算法,通过使能这些特性,能达到提升Milvus数据库性能的效果。
2.2 方案简介
Witty RAG Core是openEuler社区开源的企业级Agent知识处理组件,Witty RAG部署指导可参考链接中3.3章节,本参考实践以鲲鹏920新型号为计算底座,为支持Witty RAG方案等解决方案场景提供Milvus数据库在鲲鹏平台上的性能调优指导。
本参考实践的部署方案是用容器部署Milvus数据库,涉及到的软硬件信息如下表所示:
表1 硬件信息
| 类别 | 硬件描述 |
|---|---|
| CPU | 鲲鹏7270Z |
| 内存 | 16*32GB DDR5 |
| 硬盘 | 3.5TB NVMe硬盘 |
表2 软件信息
| 软件名称 | 版本 | 获取地址 |
|---|---|---|
| milvus | 2.4.5 | 获取链接 |
| KSL | BoostKit-ksl_2.4.0.zip | 获取链接 |
| KScaNN | BoostKit-SRA_Recall-1.2.0.zip | 获取链接 |
| 0001-milvus-add-kbest-kscann.patch(milvus补丁) | / | 获取链接 |
| 0001-knowhere-add-kbest-kscann.patch (milvus-knowhere补丁) | / | 获取链接 |
3 调优参考实践
本章按照系统优化、鲲鹏BoostKit加速套件、BIOS优化的顺序展开。其中,系统侧优化(如绑核等)通常只需调整运行环境与启动参数;鲲鹏BoostKit加速套件(如Milvus KBest优化、Milvus KScaNN优化等)需要重新编译二进制包;BIOS优化(如SMT超线程、CPU高性能模式、CPU预取等)则需要重启服务器。
表1 调优手段总览
| 序号 | 归类 | 调优手段 | 说明 |
|---|---|---|---|
| 1 | 系统优化 | 绑核与NUMA亲和 | 将进程与内存约束在同一NUMA或同一socket,减少跨NUMA访问内存;鲲鹏多NUMA场景下可优先验证。 |
| 2 | 网卡中断绑核 | 处理网卡中断的CPU核和网卡不在一个NUMA时,会触发跨NUMA访问内存,通过绑核可减少跨NUMA的内存访问所带来的额外开销,提升网络处理性能。 | |
| 3 | 磁盘IO调度策略调整 | none调度策略是采用多队列块层调度器,它本质上不做任何排序,直接将I/O请求转发给设备驱动。 | |
| 4 | 鲲鹏BoostKit加速套件 | Milvus KBest优化 | KBest是鲲鹏自研的高效的图索引算法,通过量化、向量指令等方法优化了最近邻搜索的性能和精度,提供了对标开源Faiss HNSW算法的检索能力。 约束:该优化用于替换HNSW索引算法的场景。 |
| 5 | Milvus KScaNN优化 | KScaNN(Kunpeng Scalable Nearest Neighbors)是一种基于倒排索引,并针对鲲鹏芯片架构进行了深度优化索引布局、算法流程和计算流程的向量检索算法,旨在充分利用芯片潜力。 | |
| 6 | BIOS优化 | SMT超线程 | 每个物理核分为两个逻辑核,提升整机性能。 |
| 7 | CPU高性能模式 | 设置CPU运行固定运行在标称频率,无动态调频,最大化CPU性能。 | |
| 8 | CPU预取 | 使能硬件预取功能,提升内存访问效率。 |
3.1 系统优化
3.1.1 绑核与NUMA亲和
1. 优化思路
NUMA架构下,处理器访问本地内存快于访问远端节点内存,跨NUMA会带来额外延迟与调度开销。鲲鹏服务器常见多socket/多NUMA,若Milvus数据库进程在不同NUMA间迁移,易出现跨访问内存、缓存失效与尾延迟抖动等现象。
亲和性(Affinity)是进程要在某个给定的CPU上尽量长时间地运行而不被迁移到其他处理器的倾向性。在多核运行的机器上,每个核本身自己会有缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他核上,CPU Cache命中率就低了,当绑定核后,程序就会一直在指定的核跑,不会由操作系统调度到其他核上。这样能够大大提高CPU Cache的命中率,提高性能。
绑核的原则是优先将进程使用的CPU约束在同一NUMA;若所需核数超过单个NUMA,则尽量约束在同一颗CPU(同一socket)上。虚拟化场景下,还可结合平台的CPU独占、vNUMA/NUMA调度等能力,使vCPU与本地内存对齐。
2. 优化示例
步骤1 查看NUMA拓扑与CPU编号
需先安装工具:
yum install numactl执行以下命令查看NUMA拓扑:
numactl --hardware如下所示代表NUMA node0对应的cpu编号是0-63,CPU型号是7270Z(开启超线程),故一个NUMA有64个逻辑核:
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63步骤2 根据容器所需资源,将容器绑核到同一NUMA上,如下所示,在创建Milvus容器时,增加--cpuset-cpus参数进行绑核(建议其他进程也进行绑核,避免资源竞争):
docker run -d \
--name milvus-standalone \
--network witty-rag-net \
-p 19530:19530 \
-p 9091:9091 \
-e ETCD_ENDPOINTS=milvus-etcd:2379 \
-e MINIO_ADDRESS=milvus-minio:9000 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
-v /opt/milvus/volumes/milvus:/var/lib/milvus \
--security-opt seccomp=unconfined \
--cpuset-cpus="0-23" \
milvusdb/milvus:v2.4.18 milvus run standalone3.1.2 网卡中断绑核
1. 优化思路
当网卡收到大量请求时,会产生大量的中断,通知内核有新的数据包,然后内核调用中断处理程序响应,把数据包从网卡拷贝到内存。当网卡只存在一个队列时,同一时间数据包的拷贝只能由某一个core处理,无法发挥多核优势,因此引入了网卡多队列机制,这样同一时间不同core可以分别从不同网卡队列中取数据包。
在网卡开启多队列时,操作系统通过Irqbalance服务来确定网卡队列中的网络数据包交由哪个CPU core处理,但是当处理中断的CPU core和网卡不在一个NUMA时,会触发跨NUMA访问内存。因此,我们可以将处理网卡中断的CPU core设置在网卡所在的NUMA上,从而减少跨NUMA的内存访问所带来的额外开销,提升网络处理性能。
图1 自动绑定:中断绑定随机,出现跨NUMA访问内存

图2 NUMA绑定:中断绑定到指定核,避免跨NUMA访问内存

2. 优化示例
步骤1 停止irqbalance服务。
systemctl stop irqbalance.service步骤2 关闭irqbalance服务开机自启(可选)。
systemctl disable irqbalance.service步骤3 查看irqbalance服务状态是否已关闭,若状态为inactive即为关闭。
systemctl status irqbalance.service步骤4 网卡中断绑核。
执行以下命令查看UP状态的网卡:
ip link show | grep "UP mode"以网卡enp65s0f1为例,如下是网卡中断绑核流程:
执行以下命令查看中断数量:
ethtool -l enp65s0f1 | grep Combined执行以下命令查看网卡所在NUMA,建议网卡中断绑定的CPU与网卡在同一个NUMA:
cat /sys/class/net/enp65s0f1/device/numa_node执行以下命令查看NUMA节点对应的CPU:
numactl --hardware执行以下命令查看的网卡的总线信息:
ethtool -i enp65s0f1 | grep bus-info根据以下内容创建irq.sh脚本,并将脚本中第十行修改为上述命令查询到的网卡总线信息,然后执行以下命令进行网卡中断绑核:
sh irq.sh bind enp65s0f1 64 '160-191'注:此处的enp65s0f1为网卡名称,64为中断数量,'160-191' 为要用于绑定网卡中断的CPU编号,与网卡在同一个NUMA。
#!/bin/bashs
# chkconfig: - 50 50
# description: auto irq
# 使用举例:
# sh irq.sh 默认将192.168网卡队列深度设置为48并绑定到网卡所在cpu前48core
# sh irq.sh check eth1 读取网卡绑核信息
# sh irq.sh bind enp65s0f1 64 '160-191' 完整参数,将eth1队列深度修改为64,并循环绑定到160-191'32个核上,其中cpu支持范围参数,如'1-3,6,7-9'
bus_info=""
#获取网卡所在cpu
function get_default_cpu(){
eth_numa_node=`cat /sys/class/net/${eth}/device/numa_node`
numa_nodes=`lscpu | grep node\(s | awk '{print $NF}'`
cpus=`lscpu | grep CPU\(s | head -1 | awk '{print $NF}'`
sockets=`lscpu | grep Socket\(s | awk '{print $NF}'`
cpus_per_socket=`lscpu | grep Core\(s | awk '{print $NF}'`
numa_per_socket=$((${numa_nodes} / ${sockets}))
eth_socket=$((${eth_numa_node} / ${numa_per_socket}))
first_cpu=$[$[$[${cpus_per_socket}*${eth_socket}]]]
last_cpu=$[$[${cpus_per_socket}*$[${eth_socket}+1]]-1]
cpurange="${first_cpu}-${last_cpu}"
}
#根据参数获取cpu队列
function get_cpu_list(){
IFS_bak=$IFS
IFS=','
cpurange=($1)
IFS=${IFS_bak}
cpulist_arr=()
n=0
for i in ${cpurange[@]};do
start=`echo $i | awk -F'-' '{print $1}'`
stop=`echo $i | awk -F'-' '{print $NF}'`
for x in `seq $start $stop`;do
cpulist_arr[$n]=$x
let n++
done
done
}
#中断绑核
function bind(){
echo ${cnt}
ethtool -L ${eth} combined ${cnt}
#irq=`cat /proc/interrupts| grep ${eth} | awk -F ':' '{print $1}'`
irq=`cat /proc/interrupts| grep "$bus_info" | awk -F ':' '{print $1}'`
i=0
for irq_i in $irq
do
if [ $i -ge ${#cpulist_arr[*]} ]; then
i=0
fi
echo ${cpulist_arr[${i}]} "->" $irq_i
echo ${cpulist_arr[${i}]} > /proc/irq/$irq_i/smp_affinity_list
let i++
done
}
#读取网卡绑定cpu信息
function check(){
ethtool -l $eth
#irq=`cat /proc/interrupts | grep ${eth} | awk -F ':' '{print $1}'`
irq=`cat /proc/interrupts| grep "$bus_info" | awk -F ':' '{print $1}'`
for irq_i in $irq
do
cat /proc/irq/$irq_i/smp_affinity_list
done
}
[[ $2 ]] && eth=$2 || eth=`ifconfig | grep -B 1 "192.168" | head -1 | awk -F":" '{print $1}'`
echo "$eth"
[[ $3 ]] && cnt=$3 || cnt=48
[[ $4 ]] && cpurange=$4 || get_default_cpu
get_cpu_list $cpurange
[[ $1 ]] && $1 || bind3.1.3 磁盘IO调度策略调整
1. 优化思路
磁盘调度策略根据不同场景设置,在固态硬盘场景下,建议使用none,deadline次之。在固态硬盘场景下,空调度(none)通过消除请求重排与调度开销,充分利用SSD无寻道延迟的特性,显著降低延迟并节约CPU资源。
2. 优化示例
执行以下命令查询磁盘:
lsblk以NVMe盘nvme0n1为例,执行以下命令修改:
echo none > /sys/block/nvme0n1/queue/scheduler3.2 鲲鹏BoostKit加速套件
3.2.1 Milvus KBest优化
1. 优化思路
在Milvus支持的所有索引算法中,基于图的索引算法是HNSW(Hierarchical Navigable Small World),它能进行快速查询,取得较高的召回率,但是消耗的内存资源较大。为了扩展基于图的索引算法,在保证高召回率的前提下,尽可能加速查询效率,鲲鹏BoostKit提出了KBest(Kunpeng Blazing-fast embedding similarity search thruster)鲲鹏图检索算法。
KBest是鲲鹏自研的高效的图索引算法,通过量化、向量指令等方法优化了最近邻搜索的性能和精度,提供了对标开源Faiss HNSW算法的检索能力。
本特性以patch文件的方式实现,将KBest算法接入开源的Milvus数据库中,无缝使用新的图索引算法。
约束:该优化用于替换HNSW索引算法的场景。
支持的参数如下图所示:

2. 优化示例
步骤1 算法库安装。
下载鲲鹏召回算法库放在主目录(~)下,解压并安装。
获取路径请参见2.2方案简介中表2的BoostKit-SRA_Recall-1.2.0.zip获取路径,执行以下命令解压和安装。
cd ~
unzip BoostKit-SRA_Recall-1.2.0.zip
rpm -ivh boostkit-sra_recall-1.2.0-1.aarch64.rpm步骤2 milvus源码获取及补丁应用。
(1)使用git克隆Milvus并切换到2.4.5版本,放在主目录(~)下。获取路径请参见2.2方案简介中表2,并参见《Milvus 安装指南》完成Milvus的编译安装。
git clone https://gitee.com/milvus-io/milvus.git
cd milvus
# 查看所有标签,确认 v2.4.5 是否存在, 若返回v2.4.5则为存在
git tag -l "v2.4.5"
# 如果存在,直接切换
git checkout v2.4.5(2)获取优化特性的补丁文件,将其上传到主目录(~)下。
获取路径请参见2.2方案简介中表2。
(3)合入补丁。
cd ~/milvus
git apply --whitespace=nowarn < ~/0001-milvus-add-kbest-kscann.patch
cd ~/milvus/cmake_build/thirdparty/knowhere/knowhere-src/
git apply --whitespace=nowarn < ~/0001-knowhere-add-kbest-kscann.patch合入补丁后可以使用git status检查补丁是否打上。
注意:在(1)编译Milvus的时候有可能会存在组件冲突,通常会在internal/core/conanfile.py明确thrift组件使用的版本来解决,"0001-milvus-add-kbestkscann.patch"补丁中也包含对该文件的修改以及明确thrift组件这一项,在应用补丁时要注意有可能自身代码修改与补丁代码冲突导致补丁应用失败,最好回退该文件中对于thrift组件使用的版本的修改,直接应用补丁的改动。
步骤3 编译milvus及验证。
(1)进入milvus目录执行编译。
cd ~/milvus
make milvus(2)验证kbest及kscann索引已编译进milvus。
nm -C /home/cjy/rp3/milvus-optimize/milvus/internal/core/output/lib64/libknowhere.so | grep -i "kbest\|kscann"返回包含Kbest及Kscann则编译成功。

步骤4 适配应用。
(1)修改应用源码包的配置文件。
vim /home/euler-copilot-rag/rag_core/database/db_vector/milvus/engine.py(2)将所有index_type="HNSW"改为index_type="KBEST",参数也需要调整:
#原来HNSW:index_type="HNSW"
params={"M":32, "efConstruction": 200},
#改为 KBEST:index_type="KBEST"
params={"R":50,100, "build_index_type": "SSG"}
(3)修改源码后重新打包镜像,启动容器,参考链接中3.3.1.2镜像获取章节以及3.3.1.3启动容器章节。
3.2.2 Milvus KScaNN优化
1. 优化思路
Milvus数据库支持ScaNN索引算法。ScaNN(Scalable Nearest Neighbors)是由Google发布的高效向量相似性检索开源算法库,基于IVFPQ原理,通过x86上的4bit SIMD深度优化和各向异性量化损失函数优化,实现了极高的检索性能。然而,由于鲲鹏芯片的架构差异,ScaNN算法的软硬件协同优势在鲲鹏服务器上无法完全发挥,因此推出KScaNN优化特性,用于优化ScaNN类算法在鲲鹏服务器上的性能表现。KScaNN(Kunpeng Scalable Nearest Neighbors)是一种基于倒排索引,并针对鲲鹏芯片架构进行了深度优化索引布局、算法流程和计算流程的向量检索算法,旨在充分利用芯片潜力。KScaNN接口基于ScaNN开源接口进行了扩展及修改,提供了与开源ScaNN相当的完整检索能力。
此功能以patch文件的形式实现,将KScaNN算法集成到开源的Milvus数据库中,以实现对新的图索引算法的无缝支持。
约束:该优化用于替换ScaNN索引算法的场景。
支持的参数如下表所示:

2. 优化示例
步骤1 算法库及KScaNN依赖安装。
(1)下载鲲鹏召回算法库放在主目录(~)下,解压并安装。
获取路径请参见2.2方案简介中表2的KScaNN获取路径,执行以下命令解压和安装。
cd ~
unzip BoostKit-SRA_Recall-1.2.0.zip
rpm -ivh boostkit-sra_recall-1.2.0-1.aarch64.rpm(2)下载鲲鹏系统库放在主目录(~)下,解压并安装。
获取路径请参见2.2方案简介中表2的KSL获取路径,执行以下命令解压和安装。
cd ~
unzip BoostKit-ksl_2.4.0.zip
rpm -ivh boostkit-ksl-2.4.0-1.aarch64.rpm步骤2 milvus源码获取及补丁应用。
(1)使用git克隆Milvus并切换到2.4.5版本,放在主目录(~)下。获取路径请参见2.2方案简介中表2,并参见《Milvus 安装指南》完成Milvus的编译安装。
git clone https://gitee.com/milvus-io/milvus.git
cd milvus
# 查看所有标签,确认 v2.4.5 是否存在, 若返回v2.4.5则为存在
git tag -l "v2.4.5"
# 如果存在,直接切换
git checkout v2.4.5(2)获取优化特性的补丁文件,将其上传到主目录(~)下。
获取路径请参见2.2方案简介中表2。
(3)合入补丁。
cd ~/milvus
git apply --whitespace=nowarn < ~/0001-milvus-add-kbest-kscann.patch
cd ~/milvus/cmake_build/thirdparty/knowhere/knowhere-src/
git apply --whitespace=nowarn < ~/0001-knowhere-add-kbest-kscann.patch合入补丁后可以使用git status检查补丁是否打上。
注意:在(1)编译Milvus的时候有可能会存在组件冲突,通常会在internal/core/conanfile.py明确thrift组件使用的版本来解决,"0001-milvus-add-kbestkscann.patch"补丁中也包含对该文件的修改以及明确thrift组件这一项,在应用补丁时要注意有可能自身代码修改与补丁代码冲突导致补丁应用失败,最好回退该文件中对于thrift组件使用的版本的修改,直接应用补丁的改动。
步骤3 编译KScaNN的动态库文件。
(1)安装编译所需依赖包。
yum install python python3-pip python3-devel java-11-openjdk java-11-openjdk-devel rsync libomp hdf5 hdf5-devel gtest-devel libuuid-devel
yum install gcc-toolset-12*(2)编译安装编译软件bazel-5.3.0。
cd ~
wget https://github.com/bazelbuild/bazel/releases/download/5.3.0/bazel-5.3.0-dist.zip --no-check-certificate
unzip bazel-5.3.0-dist.zip -d bazel-5.3.0
cd bazel-5.3.0
env EXTRA_BAZEL_ARGS="--tool_java_runtime_version=local_jdk" bash ./compile.sh
export PATH=~/bazel-5.3.0/output:$PATH(3)编译OpenScann的动态库文件libscann_cc.so。
设置环境变量 使用gcc12进行编译。
export PATH=/opt/openEuler/gcc-toolset-12/root/usr/bin/:$PATH
export LD_LIBRARY_PATH=/opt/openEuler/gcc-toolset-12/root/usr/lib64/:$LD_LIBRARY_PATH下载OpenScann源码。
cd ~
wget https://gitee.com/openeuler/sra_scann_adapter/repository/archive/v1.1.0.zip --no-check-certificate
unzip v1.1.0.zip -d OpenScann
cd OpenScann/sra_scann_adapter-v1.1.0激活Python虚拟环境之后,编译libscann_cc.so。
conda activate milvus
sh project.sh -ag #鲲鹏920新型号使用-ag参数, 鲲鹏920使用-ah参数步骤4 编译milvus。
(1)回退gcc版本,使用默认的gcc 10.3.1进行编译。
# 撤销 PATH(去掉 gcc12 那一段)
export PATH=$(echo "$PATH" | sed 's|/opt/openEuler/gcc-toolset-12/root/usr/bin:||g')
# 撤销 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$(echo "$LD_LIBRARY_PATH" | sed 's|/opt/openEuler/gcc-toolset-12/root/usr/lib64/:||g')或者使用重新打开新终端的方式回退到默认的gcc。
(2)安装依赖软件eigen-3.3.7。
git clone https://gitlab.com/libeigen/eigen.git
cd eigen
git checkout 33d0937c6bdf5ec999939fb17f2a553183d14a74
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/eigen-3.3.7
make -sj && make install(3)激活Python虚拟环境,安装Python依赖。
conda activate milvus
pip install treelite==4.2.1
pip install tl2cgen
conda install pybind11(4)编译milvus。
cd ~/milvus
make milvus(5)验证kbest及kscann索引已编译进milvus。
nm -C /home/cjy/rp3/milvus-optimize/milvus/internal/core/output/lib64/libknowhere.so | grep -i "kbest\|kscann"返回包含Kbest及Kscann则编译成功。

步骤5 适配应用。
(1)修改应用源码包的配置文件。
vim /home/euler-copilot-rag/rag_core/database/db_vector/milvus/engine.py(2)若默认使用的索引为HNSW, 则推荐使用KBest优化, KScaNN优化适用于原来使用ScaNN索引的场景。
index_type="KSCANN"
#其余参数配置见说明中KScaNN支持的参数,按照实际业务需求进行配置
(3)修改源码后重新打包镜像,启动容器,参考链接中3.3.1.2镜像获取章节以及3.3.1.3启动容器章节。
3.3 BIOS优化
3.3.1 SMT超线程
1. 优化思路
开启SMT超线程,每个物理核分为两个逻辑核,提升整机性能。
注意:该调优项仅适用于鲲鹏920新型号服务器,对于其他鲲鹏服务器暂不支持该配置。
2. 优化示例
1)服务器重启,进入BIOS,依次选择“BIOS->Advanced->Power And Performance Configuration->CPU PM Control”。
2)设置“SMT2”选项为“Enabled”,按F10保存BIOS配置。

3.3.2 CPU高性能模式
1. 优化思路
CPU性能模式通常指将CPU频率固定在最高值,以最大化其性能的设置,开启CPU性能模式,无动态调频,固定在标称频率,可以提升事务处理性能。
说明:Power Policy会受Performance Profile联动配置的影响,即Performance Profile配置后,可能导致Power Policy发生变化,但支持手动修改,配置BIOS时注意保存前检查配置是否符合预期。
2. 优化示例
1)服务器重启,进入BIOS,依次选择“BIOS->Advanced->Power And Performance Configuration”。
2)设置“Power Policy”选项为“Performance”,按F10保存BIOS配置。

3.3.3 CPU预取
1. 优化思路
CPU将内存中的数据读到CPU的高速缓存时,会根据局部性原理,除了读取本次要访问的数据,还会预取本次数据的周边数据到Cache中,如果预取的数据是下次要访问的数据,那么性能会提升,如果预取的数据不是下次要访问的数据,那么会浪费内存带宽。
对于数据比较集中的场景,预取的命中率高,适合打开CPU预取,反之对于数据不集中的场景则需要关闭CPU预取。
2. 优化示例
1)服务器重启,进入BIOS,依次选择“BIOS->Advanced->Power And Performance Configuration->CPU PM Control”。
2)设置CPU Prefetching为Enabled。



