Docker 部署 Qdrant 集群

Docker 部署 Qdrant 集群

Cocytus Elias 518 2023-05-22

Qdrant 是一个轻量化的向量数据库,部署简单,支持水平扩展、读写分离、高可用和快照备份等,并可以处理数十亿数据点的大规模数据集。

Qdrant 也支持通过 REST APIgRPC 进行调用,并提供了 python rust gosdk,顺带一提,Qdrant 是使用 rust 编写的 。

我们部署一个多节点的 Qdrant 集群,首先我们需要至少两台物理机,建议磁盘使用 SSD

Qdrant 虽然可以直接纯物理机部署,但是官方建议使用 docker 镜像,因为 docker 镜像是经过官方优化的,性能更好并且更稳定。

配置

qdrant 配置文件为 yaml 格式,分为两种:

  • 基础配置:名称为 config.yaml,里面都是默认的配置参数,不需要动。
  • 环境配置:分为 developmentproductiondocker 镜像默认读取的是production.yaml

不论是基础配置还是环境配置他们里面可以设置的内容和格式都是一样的。只是环境优先,即同一个设置同时存储在环境配置和基础配置中的话,以环境配置为准。

# 存储配置
storage:
  # 数据库中的数据存储位置
  storage_path: /disk/storage

  # 数据库快照生成后的保存位置
  snapshots_path: /disk/snapshots

  # 向量元信息是否放在硬盘上。为 true 的话就不会在内存中存储,但是能降低内存占用。但是这个元信息仅限于非检索字段。
  # 向量存储会有两个基础值,ID 和 Vector。
  # ID 存储的是对应的其他数据内容(比如数据库中存储的图片地址、图片 id 等等),这是和业务相关的。
  # Vector 存储的就是向量内容,就是你需要做相似值计算的内容。
  # 元信息就是其他的,一个向量可以附带多个元信息。元信息分为需要筛选和不需要筛选的。
  # 比如,有一个需求,智能客服,用户已经限定了范围是购买相关,那元信息就可以加一个 category 为 buy,筛选的时候除了向量计算外,还需要做一下元信息筛选。这个元信息是需要筛选的。
  # 当然另外还有不需要筛选的,比如图片搜索,我想直接把图片名、图片来源链接等等都在向量库中存储,那这时候就需要附加上图片名、图片来源等信息。但是图片相似度搜索又不需要根据图片名、图片来源链接作为筛选条件。这个元信息就是不需要筛选的。
	# 一个向量可以同时附加 需要筛选和不需要筛选的 元信息。
	# 这个配置是只对 不需要筛选的元信息 起作用。需要筛选的元信息还是会在内存里。
  on_disk_payload: true

  # Write-ahead-log related configuration
  wal:
    # Size of a single WAL segment
    wal_capacity_mb: 32

    # Number of WAL segments to create ahead of actual data requirement
    wal_segments_ahead: 0

  # node_type 是用来确定启动的节点类型,分为 Normal 和 Listener。
  # 如果你这个节点需要正常的提供服务,就是可以正常读写、搜索的话,那就是 Normal。
  # 如果这个节点只是用来监听向量数据信息变更并存储,不提供读写、搜索等服务的话,那就是 Listener
  node_type: "Normal"

  performance:
    # 搜索时使用的并行线程数。0 为自动确定值。
    max_search_threads: 0
    # 最大的优化线程总数,用于持续优化集合搜索。
		# 一个优化线程会起 max_indexing_threads 来构建索引。
		# 实际因为优化线程而引起的线程运行数为 max_optimization_threads * max_indexing_threads
    max_optimization_threads: 1

	# 这块属于性能优化了,根据实际情况调整即可。
  optimizers:
		# 在进行段优化时所需的已删除向量的最小比例
    deleted_threshold: 0.2

    # 在进行段优化时所需的最小向量数。即超过多少向量才会进行优化。
    vacuum_min_vector_number: 1000

    # 优化器尝试保持的段目标数量。为 0 将自动根据可用 CPU 数选择。
    default_segment_number: 0

    # 单个段最大大小。如果需要索引速度,则将此参数设低。如果需要搜索速度,将此参数设高。
		# 可以理解为,什么大小时候做优化。小的话基本就不做优化,但是搜索是跨段了。大的话就不需要跨段搜,但是需要经常整理段内索引。
		# 如果未设置,将根据可用 CPU 数自动选择。
    max_segment_size_kb: null

    # 每个段允许存储在内存中的向量的最大大小,超过最大值段将以只读 memmap 文件的形式存储。
    # 1 KB = 1 个大小为 256 的向量
    # 如果未设置,将不存在最大值,也不会有只读 memmap 文件的形式存储的数据。
    memmap_threshold_kb: null

    # 允许存储在内存中的向量的最大大小(以 KB 为单位),用于普通索引。
    indexing_threshold_kb: 20000

    # 刷新时间
    flush_interval_sec: 5
    
    # 最大的优化线程总数,用于持续优化集合搜索。
		# 一个优化线程会起 max_indexing_threads 来构建索引。
		# 实际因为优化线程而引起的线程运行数为 max_optimization_threads * max_indexing_threads
    max_optimization_threads: 1

  hnsw_index:
    # 图索引中,每个节点的最大关联值,关联值越多,越精准,但是也需要更多的存储空间。
    m: 16
    # 在构建索引时考虑的邻居数。值越大-搜索越准确,构建索引所需的时间越长。
    ef_construct: 100
    # 小于这个向量大小,将使用全查询。
    full_scan_threshold_kb: 10000
    # 最大索引构建线程数。0 位自动选择
    max_indexing_threads: 0
    # 图索引的存储位置,true 代表存在磁盘中,false 代表整体索引存在内存中。
    on_disk: true
    # 用于有效负载索引构建的自定义 m 参数。如果未设置,将使用默认的 m。
    payload_m: null

service:

  # 单次请求最大的大小。不建议太小,因为有的高维向量很大,再加上其它元信息。这个没有通用标准,根据具体业务来判断就行。单位 mb。
  max_request_size_mb: 64

  # 最大的 api 服务线程数。0 为自动选择。
  max_workers: 0

  # 监听地址
  host: 0.0.0.0

  # HTTP 端口,适用于 REST API 调用
  http_port: 6333

  # grpc 端口
  grpc_port: 6334

  # 是否允许跨域请求
  enable_cors: true

cluster:
  # 是否开启集群模式,true 为开始,false 为单机。
  enabled: true

  p2p:
		# 集群内部通信的端口
    port: 6335

  consensus:
    # 集群内健康检查时间,单位 毫秒
    tick_period_ms: 100

# 是否关闭遥测监控,就是各类软件上让你勾选的「是否允许我们收集匿名数据,来提供更好的用户体验」
# true 为不允许,false 为允许
telemetry_disabled: true

Docker Compose 部署

为了方便,我在这里直接编写一个 docker compose 文件,具体部署的时候可以自行转换为相应的 k8s 或者 docker 来运行。

qdrant 集群启动,需要先启动一个主节点,然后其他节点去链接这个主节点。

主节点部署

version: '3.5'

services:
  qdrant:
    container_name: qdrant
    image: qdrant/qdrant:v1.1.1
    environment:
      - QDRANT__CLUSTER__ENABLED=true
    tty: true
    ports:
      - "6333:6333"
      - "6334:6334"
      - "6335:6335"
    volumes:
      - /disk/ssd1/qdrant/storage:/disk/storage
      - /disk/ssd1/qdrant/snapshots:/disk/snapshots
      - /disk/ssd1/qdrant/config/production.yaml:/qdrant/config/production.yaml
    command: /qdrant/qdrant --uri http://host:6335
    networks:
     - qrant

主节点部署的时候,需要指定主节点所在的 地址、端口。端口必须是 p2p 端口。

其他节点部署

version: '3.5'

services:
  qdrant:
    container_name: qdrant
    image: qdrant/qdrant:v1.1.1
    environment:
      - QDRANT__CLUSTER__ENABLED=true
    tty: true
    ports:
      - "6333:6333"
      - "6334:6334"
      - "6335:6335"
    volumes:
      - /disk/ssd1/qdrant/storage:/disk/storage
      - /disk/ssd1/qdrant/snapshots:/disk/snapshots
      - /disk/ssd1/qdrant/config/production.yaml:/qdrant/config/production.yaml
    command: /qdrant/qdrant --bootstrap http://host:6335

其他节点部署的时候,需要指定主节点所在的 地址、端口。端口必须是 p2p 端口。

需要几个节点,直接就部署几个其他节点就 OK 了。