如何在亚马逊 EKS 上部署开源 Milvus 向量数据库
这篇文章最初发表在AWS 网站上,经翻译、编辑并获得许可后在此转贴。
向量嵌入和向量数据库概述
生成式人工智能(GenAI)的兴起,尤其是大型语言模型(LLMs)的兴起,极大地提升了人们对向量数据库的兴趣,使其成为 GenAI 生态系统中的重要组成部分。因此,向量数据库正被越来越多的用例所采用。
IDC 报告预测,到 2025 年,80% 以上的业务数据将是非结构化的,以文本、图像、音频和视频等格式存在。大规模地理解、处理、存储和查询这些海量非结构化数据是一项巨大的挑战。GenAI 和深度学习的常见做法是将非结构化数据转化为向量嵌入,存储并索引到Milvus或Zilliz Cloud(完全托管的 Milvus)等向量数据库中,用于向量相似性或语义相似性搜索。
但向量嵌入到底是什么呢?简单地说,它们是浮点数在高维空间中的数字表示。两个向量之间的距离表示它们的相关性:距离越近,它们之间的相关性越高,反之亦然。这意味着相似的向量对应着相似的原始数据,这与传统的关键字或精确搜索不同。
如何执行向量相似性搜索
图 1:如何执行向量相似性搜索
向量嵌入的存储、索引和搜索能力是向量数据库的核心功能。目前,主流的向量数据库分为两类。第一类是对现有关系数据库产品的扩展,如亚马逊 OpenSearch 服务的KNN插件和亚马逊 RDS forPostgreSQL的 pgvector 扩展。第二类是专门的向量数据库产品,包括 Milvus、Zilliz Cloud(完全托管的 Milvus)、Pinecone、Weaviate、Qdrant 和Chroma 等著名案例。
Embeddings 技术和向量数据库在各种人工智能驱动的用例中有着广泛的应用,包括图像相似性搜索、视频重复数据删除和分析、自然语言处理、推荐系统、定向广告、个性化搜索、智能客户服务和欺诈检测。
在众多向量数据库中,Milvus是最受欢迎的开源选项之一。本篇文章将介绍 Milvus,并探讨在 AWS EKS 上部署 Milvus 的实践。
Milvus 是什么?
Milvus是一个高度灵活、可靠、快速的云原生开源向量数据库。它为向量相似性搜索和人工智能应用提供动力,并努力使每个组织都能访问向量数据库。Milvus 可以存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的 10 亿多个向量 Embeddings。
Milvus 于 2019 年 10 月以开源 Apache License 2.0发布。它目前是LF AI & Data Foundation 的一个毕业项目。在撰写本博客时,Milvus 的Docker pull下载量已达到5000 多万次,并被英伟达、AT&T、IBM、eBay、Shopee 和沃尔玛等众多客户使用。
Milvus 的主要功能
作为云原生向量数据库,Milvus 拥有以下主要功能:
在十亿级向量数据集上实现高性能和毫秒级搜索。
多语言支持和工具链。
横向可扩展性和高可靠性,即使在中断情况下也是如此。
混合搜索,通过标量过滤与向量相似性搜索配对实现。
Milvus 架构
Milvus 遵循数据流与控制流分离的原则。如图所示,系统分为四个层次:
Milvus 架构
图 2 Milvus 架构
访问层:访问层由一组无状态代理组成,是系统的前端层和用户的终端。
协调服务:协调服务将任务分配给工作节点。
工作节点:工作节点是哑执行器,它们遵循协调者服务的指令,执行用户触发的 DML/DDL 命令。
存储:存储负责数据持久性。它包括元存储、日志代理和对象存储。
Milvus 部署选项
Milvus 支持三种运行模式:Milvus Lite、Standalone 和 Distributed。
Milvus Lite是一个 Python 库,可导入本地应用程序。作为 Milvus 的轻量级版本,它非常适合在 Jupyter Notebooks 中进行快速原型开发,或在资源有限的智能设备上运行。
Milvus Standalone 是单机服务器部署。如果你有生产工作负载,但又不想使用 Kubernetes,那么在内存充足的单机上运行 Milvus Standalone 是一个不错的选择。
Milvus Distributed可以部署在 Kubernetes 集群上。它支持更大的数据集、更高的可用性和可扩展性,更适合生产环境。
Milvus 从设计之初就支持 Kubernetes,可以轻松部署在 AWS 上。我们可以使用 Amazon Elastic Kubernetes Service(Amazon EKS)作为受管 Kubernetes,使用 Amazon S3 作为对象存储,使用 Amazon Managed Streaming for Apache Kafka(Amazon MSK)作为消息存储,使用 Amazon Elastic Load Balancing(Amazon ELB)作为负载平衡器,从而构建一个可靠、弹性的 Milvus 数据库集群。
接下来,我们将逐步指导大家使用 EKS 和其他服务部署 Milvus 集群。
在 AWS EKS 上部署 Milvus
先决条件
我们将使用 AWS CLI 创建 EKS 群集并部署 Milvus 数据库。需要以下先决条件:
安装了 AWS CLI并配置了适当权限的 PC/Mac 或 Amazon EC2 实例。如果使用 Amazon Linux 2 或 Amazon Linux 2023,则默认安装 AWS CLI 工具。
已安装 EKS 工具,包括 Helm、Kubectl、eksctl 等。
一个亚马逊 S3 存储桶。
亚马逊 MSK 实例。
创建 MSK 时的注意事项
- Milvus 的最新稳定版本(v2.3.13)依赖于 Kafka 的
autoCreateTopics
功能。因此,在创建 MSK 时,我们需要使用自定义配置,并将auto.create.topics.enable
属性从默认的false
更改为true
。此外,为提高 MSK 的消息吞吐量,建议增加message.max.bytes
和replica.fetch.max.bytes
的值。有关详情,请参阅自定义 MSK 配置。
auto.create.topics.enable=true
message.max.bytes=10485880
replica.fetch.max.bytes=20971760
- Milvus 不支持 MSK 基于 IAM 角色的身份验证。因此,在创建 MSK 时,请在安全配置中启用
SASL/SCRAM authentication
选项,并在 AWS Secrets Manager 中配置username
和password
。有关详情,请参阅使用 AWS Secrets Manager 进行登录凭据身份验证。
图 3 安全设置启用 SASL SCRAM 身份验证.png
图 3:安全设置:启用 SASL/SCRAM 身份验证
- 我们需要启用从 EKS 群集的安全组或 IP 地址范围访问 MSK 安全组。
创建 EKS 群集
创建 EKS 群集的方法有很多,如通过控制台、CloudFormation、eksctl 等。本文章将介绍如何使用 eksctl 创建 EKS 群集。
eksctl
是一个简单的命令行工具,用于在亚马逊 EKS 上创建和管理 Kubernetes 群集。它提供了最快、最简单的方法来为亚马逊 EKS 创建一个带有节点的新集群。更多信息,请参阅 eksctl网站。
- 首先,用以下代码段创建一个
eks_cluster.yaml
文件。将cluster-name
替换为群集名称,将region-code
替换为要创建群集的 AWS 区域,将private-subnet-idx
替换为私有子网。 注意:此配置文件通过指定私有子网在现有 VPC 中创建 EKS 群集。如果要创建新的 VPC,请删除 VPC 和子网配置,然后eksctl
将自动创建一个新的 VPC。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: <cluster-name>
region: <region-code>
version: "1.26"
iam:
withOIDC: true
serviceAccounts:
- metadata:
name: aws-load-balancer-controller
namespace: kube-system
wellKnownPolicies:
awsLoadBalancerController: true
- metadata:
name: milvus-s3-access-sa
# if no namespace is set, "default" will be used;
# the namespace will be created if it doesn't exist already
namespace: milvus
labels: {aws-usage: "milvus"}
attachPolicyARNs:
- "arn:aws:iam::aws:policy/AmazonS3FullAccess"
# Use existed VPC to create EKS.
# If you don't config vpc subnets, eksctl will automatically create a brand new VPC
vpc:
subnets:
private:
us-west-2a: { id: <private-subnet-id1> }
us-west-2b: { id: <private-subnet-id2> }
us-west-2c: { id: <private-subnet-id3> }
managedNodeGroups:
- name: ng-1-milvus
labels: { role: milvus }
instanceType: m6i.2xlarge
desiredCapacity: 3
privateNetworking: true
addons:
- name: vpc-cni # no version is specified so it deploys the default version
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
- name: coredns
version: latest # auto discovers the latest available
- name: kube-proxy
version: latest
- name: aws-ebs-csi-driver
wellKnownPolicies: # add IAM and service account
ebsCSIController: true
- 然后,运行
eksctl
命令创建 EKS 群集。
eksctl create cluster -f eks_cluster.yaml
该命令将创建以下资源:
具有指定版本的 EKS 群集。
一个包含三个 m6i.2xlarge EC2 实例的受管节点组。
一个IAM OIDC 身份提供程序和一个名为
aws-load-balancer-controller
的服务帐户,我们稍后将在安装AWS 负载平衡器控制器时使用该帐户。一个命名空间
milvus
和该命名空间中的一个服务帐户milvus-s3-access-sa
。稍后在配置 S3 作为 Milvus 的对象存储时将使用该命名空间。注:为简单起见,此处的
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
替换为群集的名称。
aws eks update-kubeconfig --region <region-code> --name <cluster-name>
创建群集后,可以通过运行以下命令查看节点:
kubectl get nodes -A -o wide
- 创建
ebs-sc
StorageClass,将 GP3 配置为存储类型,并将其设置为默认 StorageClass。Milvus 使用 etcd 作为其元存储,并需要此 StorageClass 来创建和管理 PVC。
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
EOF
然后,将原来的gp2
StorageClass 设置为非默认:
kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
- 安装 AWS 负载平衡器控制器。我们稍后将在 Milvus 服务和 Attu Ingress 中使用此控制器,因此让我们事先安装它。
- 首先,添加
eks-charts
repo 并更新。
helm repo add eks https://aws.github.io/eks-charts
helm repo update
- 然后,安装 AWS 负载平衡器控制器。用群集名称替换
cluster-name
。在前面的步骤中创建 EKS 群集时,已经创建了名为aws-load-balancer-controller
的 ServiceAccount。
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<cluster-name> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
- 验证控制器是否安装成功。
kubectl get deployment -n kube-system aws-load-balancer-controller
- 输出结果应如下所示:
NAME READY UP-TO-DATE AVAILABLE AGE
aws-load-balancer-controller 2/2 2 2 12m
部署 Milvus 群集
Milvus 支持多种部署方法,如操作符和 Helm。操作符更简单,但 Helm 更直接、更灵活。本例中我们将使用 Helm 部署 Milvus。
使用 Helm 部署 Milvus 时,可以通过values.yaml
文件自定义配置。点击values.yaml查看所有选项。默认情况下,Milvus 将集群内的 minio 和 pulsar 分别创建为对象存储和消息存储。我们将对配置进行一些修改,使其更适合生产环境。
- 首先,添加 Milvus Helm repo 并更新它。
helm repo add milvus https://zilliztech.github.io/milvus-helm/
helm repo update
- 用以下代码段创建
milvus_cluster.yaml
文件。该代码片段自定义了 Milvus 的配置,例如将 Amazon S3 配置为对象存储,将 Amazon MSK 配置为消息队列。稍后我们将提供详细解释和配置指导。
#####################################
# Section 1
#
# Configure S3 as the Object Storage
#####################################
# Service account
# - this service account are used by External S3 access
serviceAccount:
create: false
name: milvus-s3-access-sa
# Close in-cluster minio
minio:
enabled: false
# External S3
# - these configs are only used when `externalS3.enabled` is true
externalS3:
enabled: true
host: "s3.<region-code>.amazonaws.com"
port: "443"
useSSL: true
bucketName: "<bucket-name>"
rootPath: "<root-path>"
useIAM: true
cloudProvider: "aws"
iamEndpoint: ""
#####################################
# Section 2
#
# Configure MSK as the Message Storage
#####################################
# Close in-cluster pulsar
pulsar:
enabled: false
# External kafka
# - these configs are only used when `externalKafka.enabled` is true
externalKafka:
enabled: true
brokerList: "<broker-list>"
securityProtocol: SASL_SSL
sasl:
mechanisms: SCRAM-SHA-512
username: "<username>"
password: "<password>"
#####################################
# Section 3
#
# Expose the Milvus service to be accessed from outside the cluster (LoadBalancer service).
# or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it.
#####################################
service:
type: LoadBalancer
port: 19530
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external #AWS Load Balancer Controller fulfills services that has this annotation
service.beta.kubernetes.io/aws-load-balancer-name : milvus-service #User defined name given to AWS Network Load Balancer
service.beta.kubernetes.io/aws-load-balancer-scheme: internal # internal or internet-facing, later allowing for public access via internet
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip #The Pod IPs should be used as the target IPs (rather than the node IPs)
#####################################
# Section 4
#
# Installing Attu the Milvus management GUI
#####################################
attu:
enabled: true
name: attu
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb # Annotation: set ALB ingress type
alb.ingress.kubernetes.io/scheme: internet-facing #Places the load balancer on public subnets
alb.ingress.kubernetes.io/target-type: ip #The Pod IPs should be used as the target IPs (rather than the node IPs)
alb.ingress.kubernetes.io/group.name: attu # Groups multiple Ingress resources
hosts:
-
#####################################
# Section 5
#
# HA deployment of Milvus Core Components
#####################################
rootCoordinator:
replicas: 2
activeStandby:
enabled: true # Enable active-standby when you set multiple replicas for root coordinator
resources:
limits:
cpu: 1
memory: 2Gi
indexCoordinator:
replicas: 2
activeStandby:
enabled: true # Enable active-standby when you set multiple replicas for index coordinator
resources:
limits:
cpu: "0.5"
memory: 0.5Gi
queryCoordinator:
replicas: 2
activeStandby:
enabled: true # Enable active-standby when you set multiple replicas for query coordinator
resources:
limits:
cpu: "0.5"
memory: 0.5Gi
dataCoordinator:
replicas: 2
activeStandby:
enabled: true # Enable active-standby when you set multiple replicas for data coordinator
resources:
limits:
cpu: "0.5"
memory: 0.5Gi
proxy:
replicas: 2
resources:
limits:
cpu: 1
memory: 4Gi
#####################################
# Section 6
#
# Milvus Resource Allocation
#####################################
queryNode:
replicas: 1
resources:
limits:
cpu: 2
memory: 8Gi
dataNode:
replicas: 1
resources:
limits:
cpu: 1
memory: 4Gi
indexNode:
replicas: 1
resources:
limits:
cpu: 4
memory: 8Gi
代码包含六个部分。请按照以下说明更改相应配置。
第 1 节:将 S3 配置为对象存储。serviceAccount 授予 Milvus 访问 S3 的权限(在本例中是milvus-s3-access-sa
,它是在我们创建 EKS 群集时创建的)。确保将<region-code>
替换为群集所在的 AWS 区域。将<bucket-name>
替换为 S3 存储桶的名称,将<root-path>
替换为 S3 存储桶的前缀(此字段可留空)。
第 2 部分:将 MSK 配置为消息存储。将<broker-list>
替换为与 MSK 的 SASL/SCRAM 身份验证类型相对应的端点地址。将<username>
和<password>
替换为 MSK 帐户的用户名和密码。您可以从 MSK 客户端信息中获取<broker-list>
,如下图所示。
图 4 将 MSK 配置为 Milvus.png 的消息存储器
图 4:将 MSK 配置为 Milvus 的信息存储空间
第 3 部分:公开 Milvus 服务并启用群集外部访问。Milvus 端点默认使用 ClusterIP 类型的服务,只能在 EKS 集群内访问。如有需要,可以将其更改为负载平衡器类型,以允许从 EKS 集群外部访问。LoadBalancer 类型服务使用 Amazon NLB 作为负载平衡器。根据安全最佳实践,这里默认将aws-load-balancer-scheme
配置为内部模式,这意味着只允许内网访问 Milvus。点击查看 NLB 配置说明。
第 4 部分:安装和配置开源 milvus 管理工具Attu。它有一个直观的图形用户界面,可以让你轻松与 Milvus 交互。我们启用 Attu,使用 AWS ALB 配置入口,并将其设置为internet-facing
类型,这样就可以通过互联网访问 Attu。点击本文档获取 ALB 配置指南。
第 5 节:启用 Milvus 核心组件的 HA 部署。Milvus 包含多个独立且解耦的组件。例如,协调器服务作为控制层,负责协调根、查询、数据和索引组件。访问层中的代理作为数据库访问端点。这些组件默认只有一个 pod 复制。为了提高 Milvus 的可用性,部署这些服务组件的多个副本尤为必要。
注意:根、查询、数据和索引协调器组件的多副本部署需要启用activeStandby
选项。
第 6 节:调整 Milvus 组件的资源分配,以满足工作负载的要求。Milvus 网站还提供了一个尺寸工具,可根据数据量、向量尺寸、索引类型等生成配置建议。它还可以一键生成 Helm 配置文件。以下配置是该工具针对 100 万 1024 维向量和 HNSW 索引类型给出的建议。
- 使用 Helm 创建 Milvus(部署在命名空间
milvus
)。注:可以用自定义名称替换<demo>
。
helm install <demo> milvus/milvus -n milvus -f milvus_cluster.yaml
- 运行以下命令检查部署状态。
kubectl get deployment -n milvus
以下输出显示 Milvus 组件都已可用,协调组件已启用多个副本。
NAME READY UP-TO-DATE AVAILABLE AGE
demo-milvus-attu 1/1 1 1 5m27s
demo-milvus-datacoord 2/2 2 2 5m27s
demo-milvus-datanode 1/1 1 1 5m27s
demo-milvus-indexcoord 2/2 2 2 5m27s
demo-milvus-indexnode 1/1 1 1 5m27s
demo-milvus-proxy 2/2 2 2 5m27s
demo-milvus-querycoord 2/2 2 2 5m27s
demo-milvus-querynode 1/1 1 1 5m27s
demo-milvus-rootcoord 2/2 2 2 5m27s
访问和管理 Milvus
至此,我们已经成功部署了 Milvus 向量数据库。现在,我们可以通过端点访问 Milvus。Milvus 通过 Kubernetes 服务公开端点。Attu 通过 Kubernetes Ingress 公开端点。
访问 Milvus 端点
运行以下命令获取服务端点:
kubectl get svc -n milvus
您可以查看多个服务。Milvus 支持两个端口:端口19530
和端口9091
:
19530
端口用于 gRPC 和 RESTful API。使用不同的 Milvus SDK 或 HTTP 客户端连接 Milvus 服务器时,它是默认端口。9091
端口是管理端口,用于 Kubernetes 内的度量 Collections、pprof 剖析和健康探针。
demo-milvus
服务提供一个数据库访问端点,用于从客户端建立连接。它使用 NLB 作为服务负载平衡器。您可以从EXTERNAL-IP
列获取服务端点。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-etcd ClusterIP 172.20.103.138 <none> 2379/TCP,2380/TCP 62m
demo-etcd-headless ClusterIP None <none> 2379/TCP,2380/TCP 62m
demo-milvus LoadBalancer 172.20.219.33 milvus-nlb-xxxx.elb.us-west-2.amazonaws.com 19530:31201/TCP,9091:31088/TCP 62m
demo-milvus-datacoord ClusterIP 172.20.214.106 <none> 13333/TCP,9091/TCP 62m
demo-milvus-datanode ClusterIP None <none> 9091/TCP 62m
demo-milvus-indexcoord ClusterIP 172.20.106.51 <none> 31000/TCP,9091/TCP 62m
demo-milvus-indexnode ClusterIP None <none> 9091/TCP 62m
demo-milvus-querycoord ClusterIP 172.20.136.213 <none> 19531/TCP,9091/TCP 62m
demo-milvus-querynode ClusterIP None <none> 9091/TCP 62m
demo-milvus-rootcoord ClusterIP 172.20.173.98 <none> 53100/TCP,9091/TCP 62m
使用 Attu 管理 Milvus
如前所述,我们安装了 Attu 来管理 Milvus。运行以下命令获取端点:
kubectl get ingress -n milvus
你可以看到一个名为demo-milvus-attu
的 Ingress,其中ADDRESS
列是访问 URL。
NAME CLASS HOSTS ADDRESS PORTS AGE
demo-milvus-attu <none> * k8s-attu-xxxx.us-west-2.elb.amazonaws.com 80 27s
在浏览器中打开 Ingress 地址,看到如下页面。单击连接登录。
图 5 登录您的 Attu 账户.png
图 5:登录您的 Attu 账户
登录后,您可以通过 Attu 管理 Milvus 数据库。
图 6 Attu 界面.png
图 6:Attu 界面
测试 Milvus 向量数据库
我们将使用 Milvus示例代码来测试 Milvus 数据库是否正常工作。首先,使用以下命令下载hello_milvus.py
示例代码:
wget https://raw.githubusercontent.com/milvus-io/pymilvus/master/examples/hello_milvus.py
修改示例代码中的主机为 Milvus 服务端点。
print(fmt.format("start connecting to Milvus"))
connections.connect("default", host="milvus-nlb-xxx.elb.us-west-2.amazonaws.com", port="19530")
运行代码:
python3 hello_milvus.py
如果系统返回如下结果,则表明 Milvus 运行正常。
=== start connecting to Milvus ===
Does collection hello_milvus exist in Milvus: False
=== Create collection `hello_milvus` ===
=== Start inserting entities ===
Number of entities in Milvus: 3000
=== Start Creating index IVF_FLAT ===
=== Start loading ===
结论
本篇文章介绍了最流行的开源向量数据库之一Milvus,并指导如何使用亚马逊 EKS、S3、MSK 和 ELB 等托管服务在 AWS 上部署 Milvus,以实现更高的弹性和可靠性。
作为各种 GenAI 系统(尤其是检索增强生成(RAG))的核心组件,Milvus 支持并集成了各种主流 GenAI 模型和框架,包括 Amazon Sagemaker、PyTorch、HuggingFace、LlamaIndex 和 LangChain。立即使用 Milvus 开始您的 GenAI 创新之旅!
参考资料
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word