IVFFLAT-NPU

1.介绍

本章节主要介绍openGauss数据库DataVec向量引擎IVFFLAT-NPU特性的安装使用步骤,以指导用户顺利完成操作。本特性结合NPU加速ivfflat索引的构建与查询性能。

IVFFLAT-NPU - 图1 限制:IVFFLAT-NPU特性暂时只支持IVFFLAT索引。 IVFFLAT-NPU特性暂时只支持vector数据类型,在其他向量数据类型会导致执行失败。 IVFFLAT-NPU特性暂时只支持910B系列NPU。 IVFFLAT-NPU 特性仅支持在已安装 CANN 架构的容器环境中运行。

2.安装准备

获取openGauss镜像并启动容器

1. docker run -d -it --name <Your_Container_Name>\ 2. --network=host --ipc=host \ 3. --device=/dev/davinci0 \ 4. --device=/dev/davinci_manager --device=/dev/devmm_svm --device=/dev/hisi_hdc --hostname ascend_docker \ 5. -e ASCEND_RUNTIME_OPTIONS=NODRV \ 6. -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ 7. -v /etc/ascend_install.info:/etc/ascend_install.info \ 8. -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ 9. -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \ 10. -v /var/log/npu/conf/slog:/var/log/npu/conf/slog \ 11. -v /var/log/npu/slog:/var/log/npu/slog -v /var/log/npu/profiling:/var/log/npu/profiling \ 12. -v /var/log/npu/dump:/var/log/npu/dump -v /var/log/npu:/usr/slog \ 13. -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ 14. -e GS_PASSWORD=<Your_GS_PASSWORD> -e GS_USERNAME=<Your_GS_USERNAME> -e GS_DB=<Your_GS_DB> opengauss:7.0.0-RC2

这里需要保证宿主机NPU驱动程序安装在/usr/local/Ascend上。

在启动容器后请先切换到omm用户下通过npu-smi info命令查看npu是否可以正常显示相关信息(建议在~/.bashrc中配置npu相关环境变量,环境变量见下一小节,如果正常显示可以继续下一步骤,如果不能正常显示可以根据npu侧报错尝试修改容器启动命令

说明: 1)如果进入omm使用npu-smi info时报dcmi module initialize failed.ret is -8005的错误,可以手动修改/dev下的文件权限,具体命令如下 (需要放到entrypoint.sh文件中生效):

1. chown omm:omm /dev/davinci* 2. chown omm:omm /dev/devmm_svm 3. chown omm:omm /dev/hisi_hdc

2)如果npu-smi info报”device is used”,这是因为openGauss在普通用户omm下运行,如果容器以特权模式启动(特权模式下容器会自动挂载所有npu卡)并且npu卡有其他容器占用,就可能存在这种问题,建议关闭特权模式,并且保证npu卡空闲。

安装CANN框架

  • 详见本文附件获取容器内cann框架安装脚本
  • 容器root下运行安装脚本

1. chmod +x install_cann.sh 2. ./install_cann.sh

配置NPU加速安装包

  • NPU加速库源码位于openGauss-server源码下的子目录openGauss-server/contrib/nputurbo。编译方法:在nputurbo目录下CMakeLists.txt中设置参数SOC_VERSION为对应NPU型号(默认为Ascend910B4,可选Ascend910B4/Ascend910B3);在nputurbo目录下创建一个build目录,并进入该目录,执行‘cmake ../’,再执行‘make’,编译成功后,会生成libnputurbo.so动态加速库。
  • 配置环境变量 在容器内修改环境配置
1. cd /
2. vi entrypoint.sh
1. #添加NPU相关环境变量
2. export ASCEND_TOOLKIT_HOME="/usr/local/Ascend/ascend-toolkit/latest"
3. export LD_LIBRARY_PATH="/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:${LD_LIBRARY_PATH}"
4. export LD_LIBRARY_PATH="${ASCEND_TOOLKIT_HOME}/lib64:${ASCEND_TOOLKIT_HOME}/lib64/plugin/opskernel:${ASCEND_TOOLKIT_HOME}/lib64/plugin/nnengine:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe/op_tiling:${LD_LIBRARY_PATH}"
5. export PYTHONPATH="${ASCEND_TOOLKIT_HOME}/python/site-packages:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe:${PYTHONPATH}"
6. export PATH="${ASCEND_TOOLKIT_HOME}/bin:${ASCEND_TOOLKIT_HOME}/compiler/ccec_compiler/bin:${ASCEND_TOOLKIT_HOME}/tools/ccec_compiler/bin:${PATH}"
7. export ASCEND_HOME_PATH="${ASCEND_TOOLKIT_HOME}"

10. #添加so包环境变量
11. export DATAVEC_NPU_LIB_PATH=<YOUR_SO_PATH>

IVFFLAT-NPU - 图2 YOUR_SO_PATH为libnputurbo.so所在路径。

配置GUC参数

参考第4节在容器内路径/var/lib/opengauss/data/postgresql.conf文件中配置NPU相关的GUC参数。

  • 以上配置完成后重启容器。
1. docker restart <CONTAINER_ID>

说明: 1)如果用户手动编译NPU加速包时出现bisheng:command not found,需要执行source /usr/local/Ascend/ascend-toolkit/latest/bin/setenv.bash。

3.环境要求

IVFFLAT-NPU特性支持ARM架构以及openEuler22.03操作系统。

4.安装与卸载

启用IVFFLAT-NPU特性

  • 必选参数: 设置GUC参数enable_ivfflat_npu = on启用IVFFLAT-NPU特性。
  • 可选参数: GUC参数ivfflat_npubind_info = '1-2'设置使用的NPU卡编号。默认值为0,表示使用第0号NPU卡。 GUC参数cache_data_on_npu = (on|off):表示检索时是否在 NPU 内存中缓存原始向量数据。将其设置为”on”可提升检索性能,而将其设置为”off “则可节省 NPU 内存。默认值为”off”。

关闭IVFFLAT-NPU特性

设置GUC参数enable_ivfflat_npu = off关闭IVFFLAT-NPU特性。

IVFFLAT-NPU特性相关GUC参数详情请参见DataVec向量引擎参数。

5.使用IVFFLAT-NPU

IVFFLAT-NPU

1. openGauss=# set enable_npu = on;
2. openGauss=# CREATE INDEX [INDEX_NAME]
3. ON [TABLE_NAME]
4. USING ivfflat (COLUMN_NAME [TYPE]_[DISTANCE_FUN]_ops)
5. with (lists = <LISTS>);
  • INDEX_NAME - 索引名称
  • TABLE_NAME - 表名
  • COLUMN_NAME - 向量数据列名

IVFFLAT-NPU索引操作符

IVFFLAT索引操作符[TYPE]_[DISTANCE_FUN]_ops 格式:

  • TYPE - 向量类型
  • vector

IVFPQ索引支持向量数据维度:

名称 维度限制
vector 2,000
  • DISTANCE_FUN - 距离函数
  • l2
  • ip
  • cosine

vector 索引操作符

索引操作符 operator 描述
vector_l2_ops <-> L2距离
vector_ip_ops <#> 内积
vector_cosine_ops <=> 余弦距离

索引选项

  • lists - 倒排表(单元格)聚类聚类中心数量(默认为100))
  • parallel_workers - 构建索引并行度 1~32(默认为1并发构建)

示例: 使用带残差的L2距离计算创建IVFPQ索引并设置lists = 200。

1. openGauss=# CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 200);

并行构建向量索引

通过开启并行构建功能来加速向量索引的创建:

1. ALTER TABLE [TABLE_NAME]
2. SET (parallel_workers = <CONCURRENCY_NUM>);

示例: 构建索引并行数设置为8。

1. openGauss=# ALTER TABLE items SET (parallel_workers = 8);

查询选项

  • ivfflat_probe - 查询时候选集的大小(默认为1)。
1. openGauss=# SET ivfflat_probes = 10;
  • enable_seqscan - 查询时使用非向量索引(默认on)
1. openGauss=# SET enable_seqscan = off;

使用索引查询

1. openGauss=# set enable_npu = on;
2. openGauss=# SELECT * FROM [TABLE_NAME] ORDER BY [COLUMN_NAME] [operator] [VALUE];
  • TABLE_NAME - 表名
  • COLUMN_NAME - 列名
  • operator - 距离计算操作符,需要与创建索引时使用距离计算方法相同
  • VALUE - 查询的向量 示例: 通过l2距离从小到大排序,查询items表中embedding这一列中与[1,2,3,4]向量相似的全部向量。
1. openGauss=# SELECT * FROM items ORDER BY embedding <-> '[1,2,3,4]';

NPU释放缓存

  • NPU显存定时查看命令
1. watch -n 0.1 npu-smi info

IVFFLAT-NPU - 图3 可以通过以上命令查看gaussdb进程使用的显存大小。

  • NPU缓存释放场景 当 NPU 进行索引查询时,会自动缓存相应的 lists 计算结果,以便后续查询时直接使用。然而,在增删改操作发生时,聚类结果会变化,因此系统会自动释放缓存。可以使用npu-smi info命令查看缓存释放前后的 NPU 显存大小。 示例:
1. openGauss=# set enable_npu = on;
2. openGauss=# SELECT * FROM items ORDER BY embedding <-> '[1,2,3,4]';

4. openGauss=# INSERT INTO items values(1, '[2,3,4,5]');
5. openGauss=# DELETE FROM items WHERE id = 1;
6. openGauss=# UPDATE items SET id = 0 WHERE id = 1;

6.约束

  • 向量索引仅支持普通行存表,临时表,Toast表,Unlogged表,段页式表等,其他表仅支持对向量数据创建btree和ubtree索引。
  • 若ALTER INDEX后不执行REINDEX,后插入的数据会根据新的索引选项构建索引,而索引中已存在的数据不会因此改变。
  • IVFNPU索引不支持ustore存储。
  • 构建带有向量表时可以使用INDEX子句构建默认btree、ubtree索引,无法指定向量索引。
  • 未指定向量列维度时无法构建向量索引,只支持构建btree、ubtree索引。

附件

安装脚本(需要保证环境是联网状态)

1. #!/bin/bash
2. set -e

4. # 安装系统依赖
5. packages=(
6. gcc gcc-c++ make cmake curl zlib-devel bzip2-devel openssl-devel
7. ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel
8. libpcap-devel xz-devel libev-devel expat-devel libffi-devel
9. systemtap-sdt-devel unzip pciutils net-tools lapack-devel gcc-gfortran
10. util-linux findutils wget
11. )

13. to_install=()
14. for pkg in "${packages[@]}"; do
15. if ! rpm -q $pkg &>/dev/null; then
16. to_install+=("$pkg")
17. fi
18. done

20. if [ ${#to_install[@]} -gt 0 ]; then
21. echo "1-安装以下软件包: ${to_install[*]}"
22. yum update -y
23. yum install -y "${to_install[@]}"
24. yum clean all
25. rm -rf /var/cache/yum
26. rm -rf /tmp/*
27. else
28. echo "1-所有软件包已安装,跳过安装步骤。"
29. fi

31. # 安装Python 3.10.17
32. PYTHON_VERSION="3.10.17"
33. PYTHON_PREFIX="/usr/local/python${PYTHON_VERSION}"

35. export PATH="${PYTHON_PREFIX}/bin:${PATH}"

37. if ! command -v python3 &> /dev/null || \
38. [[ $(python3 -c "import sys; print('.'.join(map(str, sys.version_info[:2])))") != "${PYTHON_VERSION%.*}" ]]; then

40. echo "Python ${PYTHON_VERSION} not found, installing..."

42. mkdir -p "${PYTHON_PREFIX}/lib"
43. curl -fsSL "https://repo.huaweicloud.com/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz" -o "/tmp/Python-${PYTHON_VERSION}.tgz"
44. tar -xf "/tmp/Python-${PYTHON_VERSION}.tgz" -C /tmp
45. cd "/tmp/Python-${PYTHON_VERSION}"

47. ./configure --enable-shared --enable-optimizations LDFLAGS="-Wl,-rpath ${PYTHON_PREFIX}/lib" --prefix="${PYTHON_PREFIX}"

49. make -j $(nproc)
50. make altinstall

52. ln -sf "${PYTHON_PREFIX}/bin/python${PYTHON_VERSION%.*}" "${PYTHON_PREFIX}/bin/python3"
53. ln -sf "${PYTHON_PREFIX}/bin/pip${PYTHON_VERSION%.*}" "${PYTHON_PREFIX}/bin/pip3"
54. ln -sf "${PYTHON_PREFIX}/bin/python3" "${PYTHON_PREFIX}/bin/python"
55. ln -sf "${PYTHON_PREFIX}/bin/pip3" "${PYTHON_PREFIX}/bin/pip"

57. echo "2-Python ${PYTHON_VERSION} 安装成功,安装路径为: ${PYTHON_PREFIX}"
58. else
59. echo "2-Python ${PYTHON_VERSION%.*} 已安装在 $(which python3)"
60. fi

62. export PATH="${PYTHON_PREFIX}/bin:${PATH}"

64. # 安装Python依赖
65. packages=(
66. attrs cython numpy==1.24.0 decorator sympy cffi pyyaml pathlib2
67. psutils protobuf==3.20 scipy requests absl-py
68. )
69. to_install=()
70. for pkg in "${packages[@]}"; do
71. if ! pip show $(echo "$pkg" | cut -d= -f1) &>/dev/null; then
72. to_install+=("$pkg")
73. fi
74. done
75. if [ ${#to_install[@]} -gt 0 ]; then
76. echo "3-安装以下Python依赖: ${to_install[*]}"
77. pip install --no-cache-dir --upgrade pip
78. pip install --no-cache-dir "${to_install[@]}"
79. else
80. echo "3-所有依赖已安装,跳过安装步骤。"
81. fi

83. # 根据架构确定CANN版本
84. ARCH=$(uname -m)
85. case "${ARCH}" in
86. "x86_64") CANN_ARCH="x86_64" ;;
87. "aarch64") CANN_ARCH="aarch64" ;;
88. *) echo "Unsupported architecture: ${ARCH}" && exit 1 ;;
89. esac

91. CANN_TOOLKIT_URL="https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/Milan-ASL/Milan-ASL%20V100R001C22B800TP013/Ascend-cann-toolkit_8.2.RC1.alpha001_linux-${CANN_ARCH}.run"
92. CANN_KERNELS_URL="https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/Milan-ASL/Milan-ASL%20V100R001C22B800TP013/Ascend-cann-kernels-910b_8.2.RC1.alpha001_linux-${CANN_ARCH}.run"
93. CANN_INSTALL_DIR="/usr/local/Ascend"

95. ## 下载CANN安装包
96. if [ ! -f ~/Ascend-cann-toolkit.run ]; then
97. echo "4-下载CANN Toolkit..."
98. wget "${CANN_TOOLKIT_URL}" -O ~/Ascend-cann-toolkit.run --no-check
99. else
100. echo "4-CANN_Toolkit已下载"
101. fi

103. if [ ! -f ~/Ascend-cann-kernels.run ]; then
104. echo "4-下载CANN KERNELS..."
105. wget "${CANN_KERNELS_URL}" -O ~/Ascend-cann-kernels.run --no-check
106. else
107. echo "4-CANN_KERNELS已下载"
108. fi

110. ## 安装CANN Toolkit
111. if [ ! -d "/usr/local/Ascend/ascend-toolkit/latest" ]; then
112. echo "5-CANN Toolkit正在安装..."
113. chmod +x ~/Ascend-cann-toolkit.run
114. ~/Ascend-cann-toolkit.run --quiet --install --install-for-all
115. #rm -f ~/Ascend-cann-toolkit.run

117. chmod +x ~/Ascend-cann-kernels.run
118. ~/Ascend-cann-kernels.run --quiet --install --install-for-all
119. #rm -f ~/Ascend-cann-kernels.run

121. else
122. echo "5-CANN Toolkit 已经安装,跳过安装步骤..."
123. fi

125. # 设置CANN环境变量
126. export ASCEND_TOOLKIT_HOME="${CANN_INSTALL_DIR}/ascend-toolkit/latest"
127. export LD_LIBRARY_PATH="/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:${LD_LIBRARY_PATH}"
128. export LD_LIBRARY_PATH="${ASCEND_TOOLKIT_HOME}/lib64:${ASCEND_TOOLKIT_HOME}/lib64/plugin/opskernel:${ASCEND_TOOLKIT_HOME}/lib64/plugin/nnengine:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe/op_tiling:${LD_LIBRARY_PATH}"
129. export PYTHONPATH="${ASCEND_TOOLKIT_HOME}/python/site-packages:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe:${PYTHONPATH}"
130. export PATH="${ASCEND_TOOLKIT_HOME}/bin:${ASCEND_TOOLKIT_HOME}/compiler/ccec_compiler/bin:${ASCEND_TOOLKIT_HOME}/tools/ccec_compiler/bin:${PATH}"
131. export ASCEND_HOME_PATH="${ASCEND_TOOLKIT_HOME}"

133. # 验证安装
134. echo "===安装完成==="
135. echo "Python版本:$(python --version)"
136. echo "Pip版本:$(pip --version)"
137. echo "CANN工具包路径:${ASCEND_TOOLKIT_HOME}"

139. rm -rf /tmp/*