5

从零开始构建向量数据库:Milvus 的源码编译安装(二)

 2 years ago
source link: https://soulteary.com/2022/07/15/building-a-vector-database-from-scratch-source-code-compilation-and-installation-of-milvus-2.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

从零开始构建向量数据库:Milvus 的源码编译安装(二)

2022年07月15日阅读Markdown格式11778字24分钟阅读

本篇文章接上一篇,继续聊聊向量数据库领域,知名的开源技术项目:Milvus,在不同 CPU 架构的 macOS 环境下的编译安装。

如果你在寻找如何从源码编译安装,如何在 x86 和 ARM 两种架构的 macOS 上折腾 Milvus,那么这篇文章应该是最为详细的教程向参考内容啦。

关于 Milvus 这个项目的背景知识,以及项目目前的一些现存问题,我在上一篇文章《从零开始构建向量数据库:Milvus 的源码编译安装(一)》中有提到过。所以,就不再做展开了,如果你希望做一些了解,可以自行翻阅之前的内容。

目前,软件可以在 Linux、macOS、Windows 上完成编译,考虑到不少工程师都是使用(或被迫选择)macOS 作为图形界面系统,所以本篇文章仅介绍如何在 macOS 环境下从源码构建 Milvus。

接下来,我们还是先从编译入手,从零到一的开始了解这个项目。

在正式折腾编译构建之前,还是先分别从操作系统、开发环境、源码获取等几个方面来展开聊聊要做哪些准备工作。

本文选择的 macOS 版本是最新版 12.4,一般情况下,我们只要打开系统更新,然后让设备自己更新到最新版本,就完成了 80% 的系统环境相关的准备工作啦。

如果你希望在一个全新的环境中进行安装,避免所有的潜在干扰,可以参考苹果官方文档对系统进行重装(绝大多数情况下,不需要这样操作):

对于完成剩余 20% 的工作,我们需要借助 Homebrew。由于 Homebrew 使用了海外的 CDN 服务,所以我们在国内进行软件下载,可能会受到一些网络因素的影响,导致软件下载过程中断或失败。

如果你希望能够避免这类网络的影响,可以尝试使用国内的“清华源镜像”来尝试安装这些软件。

如果你能够直接完成依赖和工具的下载,那么就不需要配置“镜像”,因为镜像的同步机制,存在数据同步不完整的情况,在这个情况下,我们进行依赖安装,可能会出现部分依赖失败。解决这个问题也很简单,只需要在安装进行不下去的时候,“unset” 掉“镜像”,切换为官方源即可。

Golang 和 C++ 开发环境

在上一篇文章中,我们就提到过,Milvus 中绝大多数代码是由 Golang 编写的,但是核心的部分又包含了一大堆 C++ 的内容(internal/core/src),所以我们需要同时确保两种语言的运行环境。

为了让 Golang 环境的折腾能省点劲,我曾写过两篇文章介绍简单可行的方案:

经过实际测试,只需要按照文章中的步骤,一步一步 “CTRL+C / CTRL+V”,这个方案一定能够让你在十分钟内,快速的用上新鲜热乎的 Golang。

关于 C++ 环境的准备,我们会在下文中详细的展开,这里就先不赘述啦。

关于如何快速获取源代码,以及避免因为代码仓库过大,容易受到一些国内经常会遇到的网络质量影响而“拉(pull)”不下来数据的问题,我在上一篇文章中的相同的小节“源码获取”小节中有提到过,你可以直接参考文中提到的解决方案。为了节约篇幅,这里就不再展开啦。

准备基础依赖库:OpenBLAS

OpenBLAS 作为泛 AI 领域中,经常能够看到的科学计算开源库,自然也是要安装的。(据说未来版本中,会变成可选项)

在之前的文章《走进向量计算:从源码编译 OpenBLAS》中,我详细的介绍了如何进行 OpenBLAS 的编译安装,你可以参考文中的内容,来获取 OpenBLAS 的编译产物,并自行完成编译产物的有效性验证。

如果你是使用 brew 安装的:

openblas is keg-only, which means it was not symlinked into /usr/local,
because macOS provides BLAS in Accelerate.framework.

For compilers to find openblas you may need to set:
  export LDFLAGS="-L/usr/local/opt/openblas/lib"
  export CPPFLAGS="-I/usr/local/opt/openblas/include"

For pkg-config to find openblas you may need to set:
  export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"

准备构建依赖:cmake

想要构建包含 C++ 组件的项目,CMake 必不可少。

Milvus 官方项目要求 CMake 的版本是大于等于 3.18,在上一篇文章中,我们有提到了“尽量和官方构建使用相同版本”的建议,不过因为下面的现实问题,完全保持一致的版本比较难,也没有意义:

  • Mac M1 芯片设备退出时间点较晚,Milvus 立项时间较早,这导致很多项目使用的软件版本不支持 M1 设备(ARMv64 设备)
  • HomeBrew 和 macOS 新版本所预构建的工具的版本号都比较新,安装旧版本非常折腾,且不保证能够通过测试
  • 我们很少会使用 macOS 作为生产环境,更多的时候,macOS 会被用来做开发环境,所以我们也并没有必要严格要求这个环境下的组件版本和 Linux 环境下完全一致

但是考虑到过程的严谨,期望构建产物少一些预料之外的问题。在这里,我们还是分别聊聊两种芯片架构的 macOS 设备。

Intel x86 芯片的 macOS 设备

虽然在 CMake 官方网站,我们没有找到预构建程序,但是在 CMake 的 GitHub 仓库发布页面中,我们能够找到和 Milvus 官方 CI 使用版本一致的软件包:3.18.6 版本的 CMake

将文件下载之后,放到可执行文件目录(/usr/local/bin/),或者类似我们上文中安装 gvm 的时候,把包含 cmake 的路径添加到环境变量中即可完成预构建的 CMake 的安装。

安装完毕之后,我们同样可以使用 cmake --version 命令,来简单验证安装是否正确:

cmake --version
cmake version 3.18.6

CMake suite maintained and supported by Kitware (kitware.com/cmake).

当然,这里也可以使用 brew install cmake 来直接安装更新版本的 CMake 程序,简化安装过程。

M1 ARMv64 芯片的 macOS

因为直到 3.19.3 以上版本的 cmake 才提供了 ARMv64 支持,所以我们和 macOS 环境中构建 OpenBLAS 小节中遇到了一样的问题:无法在 macOS 环境下,使用和 Milvus 官方仓库中一致版本号的 cmake

我们同样有两个选择,一个是参考前文中处理 Intel 芯片 macOS 环境中 CMake 的处理方式,只选择官方开始支持 ARMv64 的软件版本,完成预构建程序的安装。

另外一个方案,则是直接使用 brew install cmake 安装 cmake 最新的 “stable” 版本,因为两种方式本质都使用了较高的新版本 cmake,并没有本质差别,所以我更推荐使用后者,安装 “stable” 版本的软件:

brew install cmake
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/cmake-3.23.2.arm64_monterey.bottle.tar.gz
######################################################################## 100.0%
==> Pouring cmake-3.23.2.arm64_monterey.bottle.tar.gz
==> Caveats
To install the CMake documentation, run:
  brew install cmake-docs

Emacs Lisp files have been installed to:
  /opt/homebrew/share/emacs/site-lisp/cmake
==> Summary
🍺  /opt/homebrew/Cellar/cmake/3.23.2: 3,043 files, 42.2MB
==> Running `brew cleanup cmake`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

程序安装完毕,我们使用 cmake --version 来进行一个简单的验证,输出程序的版本号:

cmake version 3.23.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).

准备构建依赖:clang-format、clang-tidy

在 Milvus 代码仓库里的构建工具镜像代码中,我们能够看到两个构建依赖叫做:clang-format-10clang-tidy-10,这两个工具被用于构建过程中,对代码进行格式化和检查

我们在 HomeBrew 官方软件包仓库中,可以找到一个名为 clang-format软件包,它包含了我们所需要的 clang-format 相关组件。但是和上面安装 OpenBLAScmake 一样,软件仓库中并没有提供我们所需要的版本(Milvus 官方仓库的版本)。

所以,我们需要参考上一篇文章中 Ubuntu 22.04 中“自己动手,丰衣足食”的精神,开启手动编译。

依旧是先使用 git clone 下载所需要的代码,和 Milvus 官方仓库保持一致:

 git clone -b ubuntu/focal https://git.launchpad.net/ubuntu/+source/llvm-toolchain-10
Cloning into 'llvm-toolchain-10'...
remote: Enumerating objects: 106493, done.
remote: Counting objects:  21% (22364/106493)
remote: Counting objects: 100% (106493/106493), done.
remote: Compressing objects: 100% (78521/78521), done.
remote: Total 106493 (delta 25377), reused 105666 (delta 24555)B/s
Receiving objects: 100% (106493/106493), 164.17 MiB | 268.00 KiB/s, done.
Resolving deltas: 100% (25377/25377), done.
Updating files: 100% (90282/90282), done.

在代码下载完毕之后,我们还是进入目录,并准备一个用于构建的新目录:

cd llvm-toolchain-10 && \
mkdir build && cd build

在 Ubuntu 环境中,我们想要使用 cmake 构建 llvm-toolchain 需要 ninja-build,在 macOS 中,我们所需要的这个包被叫做 “ninja”,我们可以使用 brew install ninja 来完成它的安装:

brew install ninja
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/ninja-1.11.0.arm64_monterey.bottle.tar.gz
######################################################################## 100.0%
==> Pouring ninja-1.11.0.arm64_monterey.bottle.tar.gz
==> Caveats
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions

Emacs Lisp files have been installed to:
  /opt/homebrew/share/emacs/site-lisp/ninja
==> Summary
🍺  /opt/homebrew/Cellar/ninja/1.11.0: 10 files, 435.3KB
==> Running `brew cleanup ninja`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

在完成 ninja 安装之后,我们就可以使用相同的参数来生成构建所需要的配置文件了:

cmake -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=$(which python3) -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON ../llvm

在构建配置文件生成完毕之后,还是执行 cmake --build . 命令,就可以开始 clang 工具的编译工作了:

cmake --build .

这里默认编译将会使用一个核心,如果我们的设备有更多的核心数,建议添加参数来提升构建速度(比如用8个核心一起并行构建):

cmake --build . -j8

在漫长的编译构建结束后,我们将看到类似下面的日志:

...
[100%] Building CXX object utils/benchmark/src/CMakeFiles/benchmark.dir/timers.cc.o
[100%] Linking CXX static library ../../../lib/libbenchmark.a
[100%] Built target benchmark
[100%] Building CXX object utils/benchmark/src/CMakeFiles/benchmark_main.dir/benchmark_main.cc.o
[100%] Linking CXX static library ../../../lib/libbenchmark_main.a
[100%] Built target benchmark_main
[100%] Copying llvm-locstats into /Users/soulteary/app/llvm-toolchain-10/build/./bin
[100%] Built target llvm-locstats

和上一篇文章中对 Linux 编译产物的验证方式一样,我们分别使用 ./bin/clang-format --version./bin/clang-tidy --version 就能够完成对两个程序的分别验证了:

# ./bin/clang-format --version
clang-format version 10.0.0 (https://git.launchpad.net/ubuntu/+source/llvm-toolchain-10 6f319ce10f040c979f7bb074a7b7465b8c7bf9f7)

# ./bin/clang-tidy --version
LLVM (http://llvm.org/):
  LLVM version 10.0.0
  Optimized build.
  Default target: arm-apple-darwin21.5.0
  Host CPU: cyclone

在完成对程序可运行的验证之后,我们将两个程序分别复制到 homebrew 或者系统的可执行文件的目录中即可:

cp bin/clang-format /usr/local/bin/ && \
cp bin/clang-tidy /usr/local/bin/

其余 C++ 开发环境的依赖

上文中,我们其实已经进行了一些 C++ 环境的依赖和工具的准备,不过为了让 C++ 部分程序能够顺利编译和使用,我们还需要继续补完一些内容。

在 Milvus 官方仓库的依赖安装脚本中,我们能找到一个函数 install_mac_deps,里面定义了基本所有的官方认为需要的工具:

function install_mac_deps() {
  sudo xcode-select --install  > /dev/null 2>&1
  brew install boost libomp ninja tbb cmake llvm ccache
  brew uninstall grep
  brew install grep
  export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
  brew update && brew upgrade && brew cleanup

  if [[ $(arch) == 'arm64' ]]; then
    brew install openssl
    brew install librdkafka
    brew install pkg-config
    sudo mkdir /usr/local/include
    sudo mkdir /usr/local/opt
    sudo ln -s "$(brew --prefix llvm)" "/usr/local/opt/llvm"
    sudo ln -s "$(brew --prefix libomp)/include/omp.h" "/usr/local/include/omp.h"
    sudo ln -s "$(brew --prefix libomp)" "/usr/local/opt/libomp"
    sudo ln -s "$(brew --prefix boost)/include/boost" "/usr/local/include/boost"
    sudo ln -s "$(brew --prefix tbb)/include/tbb" "/usr/local/include/tbb"
    sudo ln -s "$(brew --prefix tbb)/include/oneapi" "/usr/local/include/oneapi"
  fi
}

将上面的内容全部复制,然后粘贴在终端中执行,接着输入 install_mac_deps ,敲击回车,会看到终端提醒我们需要输入密码,才能继续执行程序。

# install_mac_deps
Password:
==> Downloading https://ghcr.io/v2/homebrew/core/icu4c/manifests/70.1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/icu4c/blobs/sha256:43cf787a35559b90597db8e1aaba95dbeedb84b1ee3d2e942be8938ae618724c
==> Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:43cf787a35559b90597db8e1aaba95dbeedb84b1ee3d2e942be8938ae618724c?se=2022-07-06T14%3A35%3A00Z&sig=v38FExWrsokAKB1VwnoRNd%2FjGPYEhs
######################################################################## 100.0%
...

在输入密码之后,耐心等待程序运行完毕,macOS 所需要的 C++ 编译环境就完全就绪了。

Golang 开发环境调整

在文章的“前置准备”小节中,我们提到过 Golang 环境的快速安装配置。但是在 Ubuntu 和 macOS 环境中,两者其实还是有一些不同之处:在 macOS 12.4 版本中,如果我们使用和 Milvus 官方一致的 Golang 1.16.9 将会出现构建失败的问题,所以我们必须升版本到 1.17 及以上。

使用 gvm 命令,来将 Golang 切换到一个合适的版本:

gvm install go1.17 -B && \
gvm use go1.17 --default

从源码编译 Milvus 主程序

看到这里,距离完成 Milvus 项目的构建,我们已经完成了 90% 的工作。接下来,我们就来解决剩下的 10% 的工作。

这部分的在 macOS 环境下的 Milvus 编译,和 Ubuntu 环境大同小异。唯一的差别是,我们需要在执行编译之前,先声明一个环境变量,避免程序在编译过程中因为找不到 pkg-config 而无法继续进行:

export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig"

在完成变量声明之后,我们同样先切换到早早准备好的 Milvus 代码目录中,接着执行 make milvus

cd milvus
make milvus

然后在一阵花花绿绿的终端日志滚动结束之后,我们执行 ./bin/milvus 命令,就能够看到符合预期的 Milvus 执行程序输出的帮助信息了:

# ./bin/milvus
Usage:

milvus run [server type] [flags]
	Start a Milvus Server.
	Tips: Only the server type is 'mixture', flags about starting server can be used.
[flags]
	-rootcoord 'true'
		Start the rootcoord server.
	-querycoord 'true'
		Start the querycoord server.
	-indexcoord 'true'
		Start the indexcoord server.
	-datacoord 'true'
		Start the datacoord server.
	-alias ''
		Set alias


milvus stop [server type] [flags]
	Stop a Milvus Server.
[flags]
	-alias ''
		Set alias


milvus mck run [flags]
	Milvus data consistency check.
	Tips: The flags are optional.
[flags]
	-etcdIp ''
		Ip to connect the ectd server.
	-etcdRootPath ''
		The root path of operating the etcd data.
	-minioAddress ''
		Address to connect the minio server.
	-minioUsername ''
		The username to login the minio server.
	-minioPassword ''
		The password to login the minio server.
	-minioUseSSL 'false'
		Whether to use the ssl to connect the minio server.
	-minioBucketName ''
		The bucket to operate the data in it

milvus mck cleanTrash [flags]
	Clean the back inconsistent data
	Tips: The flags is the same as its of the 'milvus mck [flags]'


[server type]
	standalone
	rootcoord
	proxy
	querycoord
	indexcoord
	embedded
	querynode
	indexnode
	datacoord
	datanode
	mixture

聊到这里 ,Milvus 在两种不同 CPU 架构的 macOS 设备上的编译安装就讲完啦。虽然已经在之前的文章中,铺垫和介绍了一部分内容,但是目前文章字数依然破万字。所以,也就不继续展开更多细节啦。

在下一篇 Milvus 相关的内容中,我们会继续聊聊容器相关的构建和使用,如何构建一个“知根知底”,更加“透明可控”的容器镜像。以及如何优化这个容器镜像的性能极限,让它在开发和生产环境中的性价比更高。

如果你想了解如何构建一个更加可靠、可信赖的容器镜像,我们下一篇文章见。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK