如何在亚马逊EKS上部署开源Milvus向量数据库
这篇文章最初发表在AWS网站上,经允许后在这里翻译、编辑和转载。
向量嵌入和向量数据库概述
生成性人工智能(GenAI)的兴起,特别是大型语言模型(LLMs),极大地激发了人们对向量数据库的兴趣,确立了它们在GenAI生态系统中作为重要组成部分的地位。结果,向量数据库在越来越多的用例中被采用。
一份IDC报告预测,到2025年,超过80%的商业数据将是非结构化的,存在于文本、图像、音频和视频等格式中。理解、处理、存储和大规模查询这些大量的非结构化数据是一个重大挑战。在GenAI和深度学习的常见做法是将非结构化数据转换为向量嵌入,在像Milvus或Zilliz Cloud(完全托管的Milvus)这样的向量数据库中存储和索引它们,以进行向量相似性或语义相似性搜索。
但什么是向量嵌入呢?简单地说,它们是高维空间中浮点数的数值表示。两个向量之间的距离表明了它们的相关性:它们越接近,就越相关,反之亦然。这意味着相似的向量对应于相似的原始数据,这与传统的关键词或精确搜索不同。
Figure_2_How_to_perform_a_vector_search_f38e8533a2.png
图1:如何执行向量相似性搜索
存储、索引和搜索向量嵌入的能力是向量数据库的核心功能。目前,主流的向量数据库分为两类。第一类扩展了现有的关系数据库产品,如带有KNN插件的Amazon OpenSearch Service和带有pgvector扩展的Amazon RDS for PostgreSQL。第二类包括专门的向量数据库产品,包括一些知名的例子,如Milvus、Zilliz Cloud(完全托管的Milvus)、Pinecone、Weaviate、Qdrant和Chroma。
嵌入技术和向量数据库在各种AI驱动的用例中都有广泛的应用,包括图像相似性搜索、视频去重和分析、自然语言处理、推荐系统、定向广告、个性化搜索、智能客户服务和欺诈检测。
Milvus是在众多向量数据库中最受欢迎的开源选项之一。这篇文章介绍了Milvus,并探索了在AWS EKS上部署Milvus的实践。
什么是Milvus?
Milvus是一个高度灵活、可靠且极快的云原生开源向量数据库。它支持向量相似性搜索和人工智能应用,并努力使向量数据库对每个组织都易于访问。Milvus可以存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的超过十亿个向量嵌入。
Milvus在2019年10月根据开源Apache License 2.0发布。目前,它是LF AI & Data Foundation的一个毕业项目。在撰写这篇博客时,Milvus的Docker拉取下载量已经超过5000万次,被许多客户使用,如NVIDIA、AT&T、IBM、eBay、Shopee和Walmart。
Milvus关键特性
作为云原生向量数据库,Milvus拥有以下关键特性:
- 针对十亿规模向量数据集的高性能和毫秒级搜索。
- 多语言支持和工具链。
- 即使在中断事件中也具有水平可扩展性和高可靠性。
- 通过将标量过滤与向量相似性搜索配对实现的混合搜索。
Milvus架构
Milvus遵循数据流和控制流分离的原则。系统分为四个层次,如下图所示:
Milvus_Architecture_Overview_fd10aeffb8.png
图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等。
- 一个Amazon S3存储桶。
- 一个Amazon 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认证选项,并在AWS Secrets Manager中配置用户名和密码。有关详细信息,请参见使用AWS Secrets Manager进行登录认证凭证认证。
Figure_3_Security_settings_enable_SASL_SCRAM_authentication_9cf7cdde00.png
图3:安全设置:启用SASL/SCRAM认证
我们需要从EKS集群的安全组或IP地址范围启用对MSK安全组的访问。
创建EKS集群
有多种方法可以创建EKS集群,例如通过控制台、CloudFormation、eksctl等。本文将展示如何使用eksctl创建EKS集群。
eksctl是一个简单的命令行工具,用于在Amazon EKS上创建和管理Kubernetes集群。它提供了创建新集群和Amazon EKS节点的最快、最简单的方法。有关更多信息,请参见eksctl的网站。
首先,使用以下代码片段创建一个eks_cluster.yaml文件。将<cluster-name>替换为您的集群名称,将<region-code>替换为您想要创建集群的AWS区域,并替换<private-subnet-idx>为您的私有子网。注意:此配置文件通过指定私有子网在现有VPC中创建EKS集群。如果您想要创建一个新的VPC,请删除VPC和子网配置,然后eksctl将自动创建一个新的。
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"
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的ServiceAccount,我们将在稍后安装AWS Load Balancer Controller时使用。
- 一个名为milvus的命名空间和一个在此命名空间内的ServiceAccount milvus-s3-access-sa。这个命名空间将在后面配置Milvus作为对象存储的S3时使用。注意:为了简单起见,这里的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
创建一个配置为GP3存储类型的ebs-sc StorageClass,并将其设置为默认的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 Load Balancer Controller。我们稍后将为Milvus服务和Attu Ingress使用此控制器,因此让我们提前安装它。
首先,添加eks-charts仓库并更新它。
helm repo add eks https://aws.github.io/eks-charts
helm repo update
接下来,安装AWS Load Balancer Controller。将<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支持多种部署方法,如Operator和Helm。Operator更简单,但Helm更直接、更灵活。我们将在本例中使用Helm部署Milvus。
使用Helm部署Milvus时,您可以通过values.yaml文件自定义配置。点击values.yaml查看所有选项。默认情况下,Milvus在集群内创建minio和pulsar作为对象存储和消息存储。我们将做一些配置更改,使其更适合生产。
首先,添加Milvus Helm仓库并更新它。
helm repo add milvus https://zilliztech.github.io/milvus-helm/
helm repo update
创建一个milvus_cluster.yaml文件,包含以下代码片段。此代码片段自定义了Milvus的配置,如配置Amazon S3作为对象存储和Amazon MSK作为消息队列。我们将在后面提供详细的解释和配置指导。
serviceAccount:
create: false
name: milvus-s3-access-sa
minio:
enabled: false
externalS3:
enabled: true
host: "s3.<region-code>.amazonaws.com"
port: "443"
useSSL: true
bucketName: "<bucket-name>"
rootPath: "<root-path>"
useIAM: true
cloudProvider: "aws"
iamEndpoint: ""
pulsar:
enabled: false
externalKafka:
enabled: true
brokerList: "<broker-list>"
securityProtocol: SASL_SSL
sasl:
mechanisms: SCRAM-SHA-512
username: "<username>"
password: "<password>"
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)
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:
-
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
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认证类型相对应的端点地址。将
Figure_4_Configure_MSK_as_the_Message_Storage_of_Milvus_a9e602e0b9.png
图4:将MSK配置为Milvus的消息存储
第3部分:将Milvus服务暴露并启用从集群外部访问。Milvus端点默认使用ClusterIP类型服务,仅在EKS集群内部可访问。如果需要,您可以将其更改为LoadBalancer类型以允许从EKS集群外部访问。LoadBalancer类型服务使用Amazon NLB作为服务负载均衡器。根据安全最佳实践,默认配置aws-load-balancer-scheme为内部模式,这意味着只允许Milvus的内部网络访问。点击查看NLB配置说明。
第4部分:安装并配置Attu,一个开源的Milvus管理工具。它具有直观的GUI,允许您轻松地与Milvus交互。我们启用Attu,使用AWS ALB配置入口,并将其设置为internet-facing类型,以便通过互联网访问Attu。点击此文档为ALB配置指南。
第5部分:启用Milvus核心组件的HA部署。Milvus包含多个独立且解耦的组件。例如,协调服务充当控制层,处理根、查询、数据和索引组件的协调。访问层中的Proxy充当数据库访问端点。这些组件默认只有1个pod副本。部署这些服务组件的多个副本特别需要提高Milvus的可用性。
注意:根、查询、数据和索引协调器组件的多副本部署需要启用activeStandby选项。
第6部分:调整Milvus组件的资源分配以满足您的工作负载要求。Milvus网站还提供了一个大小工具,根据数据量、向量维度、索引类型等生成配置建议。它还可以一键生成Helm配置文件。以下配置是该工具为100万1024维向量和HNSW索引类型给出的建议。
使用Helm在命名空间milvus中创建Milvus(部署)。注意:您可以将
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入口暴露端点。
访问Milvus端点
运行以下命令以获取服务端点:
kubectl get svc -n milvus
您可以看到几个服务。Milvus支持两个端口,端口19530和端口9091:
- 端口19530用于gRPC和RESTful API。当您使用不同的Milvus SDK或HTTP客户端连接到Milvus服务器时,这是默认端口。
- 端口9091是用于指标收集、pprof分析和Kubernetes内健康探针的管理端口。
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的入口,其中ADDRESS列是访问URL。
NAME CLASS HOSTS ADDRESS PORTS AGE
demo-milvus-attu <none> * k8s-attu-xxxx.us-west-2.elb.amazonaws.com 80 27s
在浏览器中打开入口地址,看到以下页面。点击连接以登录。
Figure_5_Log_in_to_your_Attu_account_bde25a6da5.png
图5:登录您的Attu账户
登录后,您可以通过Attu管理Milvus数据库。
Figure_6_The_Attu_interface_3e818e6833.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,这是最受欢迎的开源向量数据库之一,并提供了在AWS上使用Amazon EKS、S3、MSK和ELB等托管服务部署Milvus的指南,以实现更大的弹性和可靠性。
作为各种GenAI系统的核心组件,特别是检索增强型生成(RAG),Milvus支持并与各种主流GenAI模型和框架集成,包括Amazon Sagemaker、PyTorch、HuggingFace、LlamaIndex和LangChain。今天就开始您的GenAI创新之旅,使用Milvus!
技术干货
ChatGPT这样的生成型人工智能会取代谷歌搜索吗?
在本文中,我们将探讨GenAI和传统搜索引擎的工作原理,比较它们的优势和劣势,并讨论整合这两种技术的可能性。
2024-11-15技术干货
入门指南:什么是目标检测
本文将帮助你了解目标检测的工作原理、主流的目标检测模型和算法、目标检测面临的挑战以及这项技术的未来趋势。
2024-11-15技术干货
揭秘 Transformer 模型:Transformer 架构和底层原理的研究
本文将从基础的 encoder-decoder 架构开始介绍 Transformer 模型及其机制和能力。通过探索模型精巧的设计和计算过程,我们将揭秘为什么 Transformer 成为了现代 NLP 进步的基石。
2024-11-15