Press "Enter" to skip to content

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

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

 

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

 

写在前面

 

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

 

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

 

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

 

前置准备

 

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

 

操作系统

 

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

 

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

《重新安装 macOS》
《如何创建可引导的 macOS 安装器》

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

 

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

 

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

 

Golang 和 C++ 开发环境

 

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

 

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

如何在 Linux 环境中《搭建可维护的 Golang 开发环境》
(同样适用于 macOS)
以及在《M1 芯片 Mac 上更好的 Golang 使用方案》
(同样适用于 Intel 芯片的 x86 架构)

经过实际测试,只需要按照文章中的步骤,一步一步 “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
:beer:  /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-10
clang-tidy-10
,这两个工具被用于构建过程中,对代码进行格式化和检查

 

我们在 HomeBrew 官方软件包仓库中,可以找到一个名为clang-format
软件包
,它包含了我们所需要的clang-format
相关组件。但是和上面安装OpenBLAS
cmake
一样,软件仓库中并没有提供我们所需要的版本(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
:beer:  /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 相关的内容中,我们会继续聊聊容器相关的构建和使用,如何构建一个“知根知底”,更加“透明可控”的容器镜像。以及如何优化这个容器镜像的性能极限,让它在开发和生产环境中的性价比更高。

 

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

 

–EOF

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注