当前位置:   article > 正文

向量存储和检索解决方案--Vearch

向量存储

1、摘要

vearch是对大规模深度学习向量进行高性能相似搜索的向量检索数据库,可以轻松应对海量的向量数据的存储和检索。(源码地址:https://github.com/vearch/vearch ,文档地址:https://vearch.readthedocs.io/zh_CN/latest/。)

vearch部署架构简单,提供RESTful Api 操作,使用起来非常方便。使用vearch作为向量检索服务,算法工程师可以更加专注于研究算法效果的提升。

下面通过vearch 系统架构,功能特性,系统部署,系统应用,这几个方面进行介绍,从中会穿插介绍vearch的一些高级特性,旨在用户能够轻松构建自己的vearch服务,对vearch有一个全面的认识和了解。

2、系统架构

vearch 分为3个模块,其中包括 master、router和PartitionServer(简称ps)。

Master: 负责元数据管理和集群资源协调。

Router: 提供RESTful API: create、delete、search、update; 请求路由转发及结果合并。

PartitionServer(PS): 基于raft复制的文档分片; Gamma向量搜索引擎,它提供了存储、索引和检索向量、标量的能力。

Architecture

3、功能特性

RESTful API ;

数据持久化存储,高可靠性;

高可用;

高性能;

高召回率;

4、系统部署

vearch 部署便捷,我们常用的方式,可以采用容器化的方式进行快速部署,这里提供两种部署架构,采用docker容器化和k8s的方式都可以实现。

4.1、部署架构

a、快速分布式部署

 

b、etcd+vearch分布式部署

 

如果你对etcd比较熟悉,或者有现成的etcd服务,那可以使用b的部署架构(后续会提供完整文档),ps和router可通过域名的方式进行部署。

为了操作简单,下面我们介绍一下基于docker容器化,a的快速分布式部署方案:

采用一台物理机,创建多个docker容器。现在我们需要部署节点为:master 1个、router 1个、ps 3个,总共5个节点,即创建5个docker容器。如果你采用的是多台物理机搭建docker环境,需要注意容器之间的连通性,ip地址和端口的配置。

4.2、docker容器化部署

4.2.1、启动vearch容器

首先我们需要下载vearch 的docker 镜像。

执行:

docker pull vearch/vearch:v3.2.0

执行docker images 查看镜像是否存在:找到vearch v3.2.0

 

修改配置文件:(可以使用docker固定IP的方式,需要提前知道 master的ip地址,假设我们这里保证master的ip 为172.17.0.2),修改后的配置文件如下。

[global]

    # the name will validate join cluster by same name

    name = "vdb"

    # you data save to disk path ,If you are in a production environment, You'd better set absolute paths

    data = [

            "/export/vdb/baud/datas/",

        ]

    # log path , If you are in a production environment, You'd better set absolute paths

    log = "/export/vdb/baud/logs/"

    default log type for any model

    level = "debug"

    # master <-> ps <-> router will use this key to send or receive data

    signkey = "vdb"

    # skip auth for master and router

    skip_auth = true

    # tell Vearch whether it should manage it's own instance of etcd or not

    self_manage_etcd = false

    # automatically remove the failed node and recover when new nodes join

    auto_recover_ps = false

    # support access etcd basic auth,depend on self_manage_etcd = true

    support_etcd_auth = false

 

[etcd]

    #etcd server ip or domain

    address = ["my.vearch.local"]

    # advertise_client_urls AND listen_client_urls

    etcd_client_port = 2379

 

if you are master you'd better set all config for router and ps and router and ps use default config it so cool

[[masters]]

    #name machine name for cluster

    name = "master1"

    #ip or domain

    address = "172.17.0.2"

    # api port for http server

    api_port = 7810

    # port for etcd server

    etcd_port = 2378

    # listen_peer_urls List of comma separated URLs to listen on for peer traffic.

    # advertise_peer_urls List of this member's peer URLs to advertise to the rest of the cluster. The URLs needed to be a comma-separated list.

    etcd_peer_port = 2390

    # List of this member's client URLs to advertise to the public.

    # The URLs needed to be a comma-separated list.

    # advertise_client_urls AND listen_client_urls

    etcd_client_port = 2370

    data = ["/export/vdb/vdb-master/datas/"]

[router]

    # port for server

    port = 8230

    fix_name = 0

    pprof_port = 6061

    monitor_port = 8818

[ps]

    # port for server

    rpc_port = 8081

    #raft config begin

    raft_heartbeat_port = 8898

    raft_replicate_port = 8899

    heartbeat-interval = 200 #ms

    raft_retain_logs = 1000000

    raft_replica_concurrency = 1

    raft_snap_concurrency = 1

    journal_enabled = true

    max_size = 50000000000

    pprof_port = 6060

    engine_dwpt_num = 1

    raft_truncate_count = 1000000000

 

执行下面的命令,创建docker容器。说明:master1: 7810端口是master restful 端口号,包括创建表和查询的一些功能接口,2370是etcd端口号,可以使用etcdctl工具查询元数据信息。

nohup docker run -p 7810:7810 --name master1 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 master > master.log 2>&1 &

nohup docker run -p 8230:8230 --name router1 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 router > router.log 2>&1 &

nohup docker run --name ps1 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 ps > ps1.log 2>&1 &

nohup docker run --name ps2 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 ps > ps2.log 2>&1 &

nohup docker run --name ps3 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 ps > ps3.log 2>&1 &

如下图:

 

5个节点都启动成功。

4.2.2、环境验证

a、执行:curl localhost:7810(保证docker端口映射成功),或者 启动另外一个centos docker环境。

启动 另外一个centos 容器:docker run -it centos:centos7 ,执行:curl 172.17.0.2:7810,返回集群状态信息,说明vearch master启动成功。

 

b、集群整体验证:如下,master的ip地址和端口号为  172.17.0.2:7810。

执行:curl  172.17.0.2:7810/list/server 

获取集群全部的ps节点信息。

得到json结果,如下:

 

 

执行完以上步骤,那么vearch集群就已经搭建完成了。

4.3、k8s 环境部署

后续会提供完整文档,可先根据前面的docker环境部署进行探索。

5、功能验证

从系统应用的角度,把基本功能验证流程走一遍(详细的功能API文档参考:https://vearch.readthedocs.io/zh_CN/latest/)。功能验证的同时,穿插加入高可用和扩容、缩容的介绍。

数据来源于真实业务场景历史数据,用户在测试使用时,需要根据业务需求进行合理的选择。

这里指定两个变量:

a、master_server指的是master服务的ip地址和端口号[masterIP:7810]。为了方便操作,可以将docker容器的端口映射到物理机,此时masterIP指的就是物理宿主机ip。

b、router_server指的是router服务的IP地址和端口号[routerIP:8230]。,此时routerIP指的也是物理宿主机ip。

5.1、建表

a、建库

curl -H "content-type: application/json" -XPUT -d'

{

    "name":"ts_db_1"

}

' http://172.17.0.2:7810/db/_create

b、建表 :16 维向量,检索类型:IVFPQ  1个分区,3个副本。

curl -XPUT -H "content-type: application/json" -d'

{

    "name""ts_space_1",

    "partition_num"1,

    "replica_num"3,

    "engine": {

        "name""gamma",

        "index_size"70000,

        "id_type""String",

        "retrieval_type""IVFPQ",

        "retrieval_param": {

            "metric_type""InnerProduct",

            "ncentroids"256,

            "nsubvector"32

        }

    },

    "properties": {

        "feature": {

            "dimension"16,

            "type""vector"

        },

        "image_url": {

            "index"true,

            "type""string"

        }

    }

}

' http://172.17.0.2:7810/space/ts_db_1/_create

验证一下是否创建成功:

curl http://172.17.0.2:7810/space/ts_db_1/ts_space_1

5.2、数据插入

5.2.1、指定docId [可根据id查询doc] ,(查看,确认一下router1 的ip地址 docker inspect <router 1 的docker id>,此处为 172.17.0.3)

curl -XPOST -H "content-type: application/json"  -d'

{"feature": {"feature" :[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5]},"image_url":"5e7de70eE1d0e2912268d0db90558041d.jpg"}

' http://172.17.0.3:8230/ts_db_1/ts_space_1/5e7de70eE1d0e2912268d0db90558041d.jpg

5.2.2、不指定docId

curl -XPOST -H "content-type: application/json"  -d'

{"feature": {"feature" :[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5]},"image_url":"5e7de70eE1d0e2912268d0db90558041d.jpg"}

' http://172.17.0.3:8230/ts_db_1/ts_space_1

返回结果:

{"_index":"ts_db_1","_type":"ts_space_1","_id":"5e7de70eE1d0e2912268d0db90558041d.jpg","status":200}

可根据status判断数据是否插入成功。status = 200代表成功。

5.2.3、数据正确性

数据插入成功,可通过以下方式检验数据正确性:

a、根据插入成功数据量,插入成功的数据量和系统的数据量一致。插入成功的数据量,用户可自己统计记录,系统数据量查询方式:可查询partition每个副本包含的数据量。

curl 172.17.0.2:7810/_cluster/health

数据格式如下:

 

Tips:数据插入过程,会出现丢数据的情况吗?

vearch采用raft 来保证数据的一致性和正确性。raft commit 数据时,已经将数据写入到了多数的节点上,才会返回成功,即使leader出现故障,也会重新选举出拥有最新数据的节点作为leader继续进行数据的写入。不会出现丢失数据的情况。

b、插入数据按照指定docId进行(在下一节数据查询中介绍方法),随机抽取数据的docId,查询系统是否正确返回数据。

c、观察3个副本,每个副本的数据量是否保持一致。

5.3、数据查询

a、根据id查询:

curl -XGET http://172.17.0.3:8230/ts_db_1/ts_space_1/5e7de70eE1d0e2912268d0db90558041d.jpg

b、向量检索:

curl -H "content-type: application/json" -XPOST -d'

{

    "query": {

        "sum": [{

            "field""feature",

            "feature": [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5],

            "boost":1,

            "min_score":0.0,

            "max_score":1.0

        }]

    },

    "size"1

}

' http://172.17.0.3:8230/ts_db_1/ts_space_1/_search

5.4、高可用

vearch采用多副本的模式,每个partition都可以创建多个副本,只要系统中的副本存活数大于1/2,既可以保证系统的可用性。

例子:我们上面创建的库表 [ts_db_1/ts_space_1] ,1个partition创建3个副本;partitionID 1,replicasIDs[1,2,3]。leader 的数值是1,代表server 为1的节点,现在是partitionID为1的raft组的leader。

可以通过:curl 172.17.0.2:7810/list/server 查看。也可通过 etcdctl 查看元数据。

 

高可用场景的验证方法:

a、partition 的某个非leader副本故障:leader正常,数据的写入是正常的;如果该副本,经过一段时间后,重启成功,该副本会自动同步leader节点的数据至恢复到最新数据。如果副本故障,无法重启恢复,可通过扩容增加一个副本(参见扩容、缩容)。

故障的副本,可以通过 :curl 172.17.0.2:7810/_cluster/health 验证,数据量是否恢复一致。(参见:数据正确性)

b、leader副本故障:leader节点故障,会出现短暂的数据无法写入,秒级时间会重新选出新的leader,数据写入会恢复正常,故障的副本也可重启恢复或扩容恢复。

副本故障,不断的写入数据,观察数据的返回状态,1、统计插入成功的数据量与系统数据量是否一致;(正确性验证)2、观察非leader副本故障,数据的写入和读取是否正常(正常);3、观察leader副本故障,数据的写入读取是否正常(秒级 leader切换,数据短暂不可写,很快会恢复)。

5.5、扩容、缩容

回顾一下,我们现在是总共5个节点 3个ps节点,假如系统流量高峰,需要扩容,或者高峰过后需要缩容,可以通过下面的方法进行ps节点扩容。(router节点扩容,直接增加新的节点即可)

5.5.1、扩容

扩容,首先我们需要增加新的节点加入集群。

a、 nohup docker run --name ps4 -v $PWD/config.toml:/vearch/config.toml vearch/vearch:3.2.0 ps > ps4.log 2>&1 &

执行:curl  172.17.0.2:7810/list/server,查看新增节点的nodeId,partitions信息为空。

 

可以看到,新增的节点,node_id为4。

执行创建副本命令,说明:method = 0代表新增副本,method = 1代表减少副本。node_id为需要操作的节点id。

curl -XPOST -H "content-type:application/json" -d '{

    "partition_id":1,

    "node_id":4,

    "method":0

}

' http://172.17.0.2:7810/partition/change_member

再次通过curl  172.17.0.2:7810/list/server查询。

 

5.5.2、缩容

缩容操作命令为:

curl -XPOST -H "content-type:application/json" -d '{

    "partition_id":1,

    "node_id":4,

    "method":1

}

' http://172.17.0.2:7810/partition/change_member

其他的查询命令同扩容一致。

6、总结

vearch提供了完善的分布式环境下的向量存储和检索服务。内容从容器化部署,到实际应用场景都进行了详细的介绍。同时还介绍了数据正确性的验证方法,高可用的验证方法,副本的扩容和缩容方法以及高召回率。服务恢复发布,版本升级,也不会影响服务的查询性能。

下表为一些相关特性总结:

硬件环境

数据正确性

高可用

扩容、缩容

高召回率

备注

docker 环境:

1 router

硬件指标:4c,8G

3 ps

硬件指标:16c,32G

与插入成功的数据量一致,不存在数据丢失。

 

支持多副本,副本故障数小于副本总数的1/2,保证系统的百分之百可用性。很好的支持副本的扩容和缩容。支持多种索引,有高召回率。 

召回测试

测试方法

方法说明:用vearch的hnsw召回模型与暴力搜索在公开人脸数据集上做召回对比。

数据集:VGGFace2的300万人脸数据集

特征模型:Inception-resnet , 提取的特征向量维度为512

测试数据:从300万人脸特征向量中随机抽取1万特征向量做为搜索测试数据

建库数据:除去1万测试数据,剩下的299万人脸特征向量全部插入vearch进行建库

测试结果

召回模型识别总次数识别成功次数识别准确率相对暴力搜索召回率
暴力搜索10000965896.58%100%
HNSW10000963096.30%99.71%=9630/9658

结论:300万数量级时,HNSW相比暴力搜索的召回率为99.71%

性能测试

测试说明:性能测试仍然是向vearch中插入299万基于VGGFace2人脸数据集的特征向量,然后测试search的性能

测试部署:vearch所有服务都部署在 docker(k8s)平台上

master:1台 4c8g

router:3台 8c8g  (避免router成为性能瓶颈,所以多部署了两台)

ps:1台 8c16G (集群资源核心)

测试结果

召回模型并发QPS平均latencytp99cpumemory
暴力搜索12.5385ms540ms800%7.6G
HNSW15715ms20ms23%7.95G
暴力搜索30nonenonenonenonenone
HNSW30130919ms75ms800%8G

备注:表中的“none”表示没有测试的意义,放弃测试

结论:在相同的硬件资源情况下,HNSW的搜索性能是暴力搜索的>100倍

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/703170
推荐阅读
相关标签
  

闽ICP备14008679号