亚马逊AWS官方博客
基于 Amazon EKS 搭建开源向量数据库 Milvus
一、前言
生成式 AI(Generative AI)的火爆引发了广泛的关注,也彻底点燃了向量数据库(Vector Database)市场,众多的向量数据库产品开始真正出圈,走进大众的视野。
根据 IDC 的预测,到 2025 年,超过 80% 的业务数据将是非结构化的,以文本、图像、音频、视频或其他格式存储。而大规模存储和查询非结构化数据是一个非常大的挑战。
在生成式 AI 和深度学习领域通常的做法是通过将非结构化数据转换为向量进行存储,并通过向量相似性搜索(Vector similarity search)技术进行语义相关性搜索。而快速地存储、索引和搜索 Embedding 向量,正是向量数据库的核心功能。
那么,什么是 Embedding 呢?简单地说,Embedding 就是浮点数的向量的嵌入式表征。两个向量之间的距离表示它们的相关性, 距离越近相关性越高,距离越远相关性越低。如果两个 Embedding 相似,就意味着他们代表的原始数据也是相似的。这一点与传统的关键词搜索有很大的不同。
当前市面上主流的向量数据库可以分为两大类,一类是在既有数据库产品上进行扩展,例如 Amazon OpenSearch 服务通过 KNN 插件、Amazon RDS for PostgreSQL 通过 pgvector 扩展实现对向量的支持。另一类是独立的向量数据库产品,比较知名的有 Milvus、Zilliz Cloud(powered by Milvus)、Pinecone、Weaviate、Qdrant、Chroma 等。在这类向量数据库中,向量是一等公民,所有的功能都是围绕着它建立的。
Embedding 技术和向量数据库可以被广泛应用于各类 AI 驱动的应用场景,包括图片检索、视频分析、自然语言理解、推荐系统、定向广告、个性化搜索、智能客服和欺诈检测等。
在众多的向量数据库中,Milvus 是全球最流行的开源向量数据库之一,截止本文创作时至,在 Github 有超过 1.8 万颗 Star。且看 Milvus 的官方介绍:
- Milvus 是一个高度灵活、可靠且速度极快的云原生开源向量数据库。它为 embedding 相似性搜索和 AI 应用程序提供支持,并努力使每个组织都可以访问向量数据库。 Milvus 可以存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的十亿级别以上的 embedding 向量。
本文主要探讨基于 Amazon EKS 等服务部署 Milvus 集群的实践。
二、架构说明
作为一款云原生的向量数据库产品,Milvus 的设计采用了共享存储的架构,存储计算完全分离,数据、查询和索引节点分离,并使用消息队列实现各个核心组件之间的解藕。核心工作节点是无状态的,因此可以提供极大的弹性和灵活性。
Milvus 遵循数据流和控制流分离的原则,整体分为了四个层次,分别为接入层(access layer)、协调服务(coordinator service)、工作节点(worker node)和存储层(storage)。
Milvus 设计之初就支持 Kubernetes 平台。本文采用 Amazon EKS 作为底层容器平台,并使用 Amazon S3、Amazon MSK(Managed Streaming for Apache Kafka)、Amazon ELB 等托管服务分别用作其中的 Object Storage、Message storage、Load Balancer 等核心组件,以搭建可靠、弹性的 Milvus 数据库集群,使其更适合生产环境使用。
本文采用渐进的方式一步步地部署、优化 Milvus 集群,使您更容易理解 EKS 和 Milvus 部署和配置过程。
三、先决条件
本文使用命令行的方式创建 EKS 和部署 Milvus 数据库集群,因此需要如下的预备条件:
- 一台个人电脑或者 Amazon EC2,安装 AWS CLI,并配置相应的权限。如果您使用 Amazon Linux 2 或者 Amazon Linux 2023,AWS CLI 工具默认已经安装。
- 安装 EKS 相关工具,包括 Helm,Kubectl,eksctl 等。
- 一个 Amazon S3 存储桶。
- 一个 Amazon MSK 实例。
MSK 创建注意事项:
1)当前最新稳定版本的 Milvus(v2.2.13)依赖 Kafka 的autoCreateTopics
特性,因此在创建 MSK 时需要使用自定义配置,并将属性auto.create.topics.enable
由默认的false
改为true
。另外,为了提高 MSK 的消息吞吐量,建议调大message.max.bytes
和replica.fetch.max.bytes
的值。详见 Custom MSK configurations。2)Milvus 不支持 MSK 的 IAM role-based 认证,因此 MSK 创建时需要在安全配置里打开
SASL/SCRAM authentication
选项,并在 Secret Manager 里配置username
和password
,详见 Sign-in credentials authentication with AWS Secrets Manager。
3)MSK 的安全组要允许 EKS 集群安全组或者 IP 地址段进行访问。
四、创建 EKS 集群
EKS 集群的创建方式有很多,如控制台、CloudFormation、eksctl 等。本文使用 eksctl 的方式。
eksctl
是一款简单的命令行工具,用于在 Amazon EKS 上创建和管理 Kubernetes 集群。eksctl
提供使用 Amazon EKS 节点创建新集群的最快、最简单的方式。如需查阅官方文档,请参阅 https://eksctl.io/。
1. 首先,用如下内容创建 eks_cluster.yaml
文件。请将 cluster-name
替换为您的集群名称,将 region-code
替换为创建集群的 AWS 区域,将 private-subnet-idx
替换为您的私有子网。注:该配置文件通过指定私有 subnets 的方式在现有的 VPC 创建 EKS。您也可以删除 VPC 及 subnets 的配置,这样 eksctl 会自动创建一个全新的 VPC。
然后,运行 eksctl 命令创建 EKS 集群。
- 创建一个指定版本的 EKS 集群。
- 创建一个拥有 3 个 m6i.2xlarge EC2 实例的托管节点组。
- 创建 IAM OIDC 身份提供商和名为
aws-load-balancer-controller
的 ServiceAccount,后文安装 AWS Load Balancer Controller 时使用。 - 创建一个命名空间
milvus
,并在此命名空间里创建名milvus-s3-access-sa
的 ServiceAccount。后文为 Milvus 配置 S3 做 Object Storage 时使用。- 注意,此处为了方便授予了 milvus-s3-access-sa 所有 S3 访问权限,在生产环境部署时建议遵循最小化授权原则,只授予指定用于 Milvus 的 S3 存储桶的访问权限。
- 安装多个插件,其中
vpc-cni
,coredns
,kube-proxy
为 EKS 必备核心插件。aws-ebs-csi-driver
是 AWS EBS CSI 驱动程序,允许 EKS 集群管理 Amazon EBS 持久卷的生命周期。
等待集群创建完成。集群创建过程中会自动创建或者更新 kubeconfig
文件。您也可以运行如下命令手动更新,注意将 region-code
替换为创建集群的 AWS 区域,将 cluster-name
替换为您的集群名称。
并将原来的 gp2
StorageClass 设置为非默认:
添加 eks-charts
仓库并更新。
五、部署 Milvus 数据库
Milvus 支持 Operator 和 Helm 等多种部署方式,相比较而言,通过 Operator 进行部署和管理要更为简单,但 Helm 方式要更加直接和灵活,因此本文采用 Helm 的部署方式。 在使用 Helm 部署 Milvus 时,可以通过配置文件 values.yaml
进行自定义配置,点击 values.yaml 可以查看所有配置选项。 Milvus 默认创建 in-cluster 的 minio 和 pulsar 分别作为 Object Storage 和 Message Storage。为了更适合在生产环境使用,我们通过配置文件使用 S3 和 MSK 作为替代。
1. 首先,添加 Milvus Helm 仓库并更新。
4. 将 2-3 步的配置合并并保存为 milvus_cluster.yaml
文件,并使用 Helm 命令创建 Milvus(部署在 milvus
命名空间)。注意,您可以将 demo 替换为自定义名称。
输出示例如下,demo-milvus 就是 Milvus 的服务终端节点,其中 19530 为数据库访问端口,9091 为 Metrics 访问端口。默认的 Service 类型为 ClusterIP,这种类型只能在 EKS 集群内部访问。我们将在下一章节讲解如何配置为允许集群外访问。
至此,我们已经成功地部署了 Milvus 集群,但很多 Milvus 的默认配置无发满足生产环境自定义需求,本部分主要围绕如下三个方面进行配置优化。
1. Milvus 默认部署 ClusterIP 类型的 service,这种 service 只能在 EKS 内部访问,将 Milvus service 更改为 Loadbalancer 类型,使集群外也可以进行访问。
2. 安装 Attu,通过可视化界面管理 Milvus 数据库。
3. 优化各个组件的配置,使其满足于您的负载情况。
4. Milvus 核心组件冗余部署,实现生产级别的高可用。
前两项配置需要用到 AWS Load Balancer Controller,请确认在第三章中完成安装。
6.1 配置 Milvus 服务可供 EKS 集群外访问
Helm 支持在创建之后使用 helm upgrade
命令进行配置更新,我们采用这种方式对 Milvus 进行配置。 使用如下代码创建 milvus_service.yaml
配置文件,该配置文件指定使用 Load Balancer Controller 创建 LoadBalancer 类型的 service,以方便在集群外进行访问。LoadBalancer 类型的 Service 使用 Amazon NLB 作为负载均衡器。根据安全最佳实践,此处 aws-load-balancer-scheme
默认配置为 internal
模式,即只允许内网访问 Milvus。如果您确实需要通过 Internet 访问 Milvus,需要将 internal
更改为 internet-facing
。点击查看 NLB 配置说明。
登录之后就可以通过可视化的方式管理 Milvus 数据库。
6.3 优化 Milvus 的资源分配
本部分介绍如何调整 EKS 上 Milvus 组件资源分配。 通常,您在生产环境中分配给 Milvus 集群的资源应该与工作负载成正比。虽然您可以在集群运行时更新配置,但我们建议在正式部署工作负载之前进行配置。
通过前边的架构图我们可以看到 Milvus 包含多个独立且解藕的组件,运行 kubectl get deployment -n milvus
命令可以看到 Milvus 的核心组件。
如下配置是在 100 万条数据、128 维向量和 HNSW 索引类型的条件下,工具给出的配置建议。
6.4 Milvus 核心组件高可用部署
根据架构说明和前边的描述,我们已经知道 Milvus 包含了多个独立且解藕的组件,其中协调服务(coordinator service)充当控制层面的工作,包括 Root、Query、Data、Index 等协调工作;接入层(access layer)的 Proxy 充当了数据库访问入口,这些组件默认只配置为 1 个副本。为了提高 Milvus 系统的高可用,实现这些服务组件的多副本部署尤为必要。
如下配置可以开启这些组件的多副本部署。需要注意的是 Root、Query、Data、Index 等协调组件的多副本部署需要将 activeStandby
选项打开。
使用以上配置创建 milvus_ha.yaml
文件,并使用 Helm 命令进行更新。
然后,运行 kubectl get deployment -n milvus
命令可以看到指定组件已经实现多副本。
七、测试 Milvus 集群
我们使用 Milvus 官方的示例代码来测试 Milvus 集群能否正常工作。首先,直接下载 hello_milvus.py
示例代码。
运行代码:
返回如下结果即证明 Milvus 运行正常。
该示例代码验证了 PyMilvus(Milvus 的 Python SDK)的基本操作流程,包括:
- 连接到 Milvus
- 创建 collection
- 插入数据
- 创建索引
- 搜索、查询和混合搜索
- 根据主键删除 entities
- 删除 collection
八、总结
本文介绍了基于 Amazon EKS 部署 Milvus 集群的方案,并在方案中集成 S3、MSK、ELB 等托管服务实现更高的弹性和可靠性。
当前,生成式 AI 领域的发展一日千里,各类大模型与向量数据库的结合也激发了无数的创新。近期,使用 LangChain、大语言模型(LLM)与向量数据库构建基于企业知识库的智能搜索和智能问答应用,颠覆了传统的开发模式,得到了广泛的关注。
Milvus 已经支持 Amazon Sagemaker、PyTorch、HuggingFace、LlamaIndex、LangChain 等业界主流的 AI 模型和框架,赶快使用 Milvus 开始您的创新之旅吧。
九、参考资料
Amazon EKS 用户指南:https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html
Milvus 官方网站:https://milvus.io/
eksctl 官方网站:https://eksctl.io/