跳转至

架构设计

本项目是一个用纯 Go 实现的轻量级嵌入式向量数据库,目标是为本地应用、桌面程序和边缘设备提供高性能、低延迟的向量相似度检索能力。它提供:

  • Qdrant 兼容的 REST API(可选微服务模式)
  • 内嵌库模式:零网络开销,直接在应用中使用
  • HNSW 近似最近邻索引,支持子线性搜索复杂度
  • 基于 BoltDB 的持久化,使用 Protobuf 序列化
  • 支持多种距离度量(余弦、欧氏、点积)
  • 高级元数据过滤(精确、范围、前缀、正则、包含)
  • 可选 8 位标量量化以降低磁盘占用

项目结构

仓库采用按“功能域”组织的分层结构:

  • cmd/govector:独立服务入口,启动 HTTP API 服务器
  • api:HTTP API 层,暴露 Qdrant 兼容接口
  • core:核心引擎层,包含集合管理、索引、存储、模型与量化
  • example/embedded:嵌入式库使用示例
  • 资源与脚本:构建、发布与演示脚本
graph TB
subgraph "应用层"
EMB["嵌入式应用
example/embedded/main.go"] SVC["独立服务
cmd/govector/main.go"] end subgraph "API 层" API["HTTP API 服务器
api/server.go"] end subgraph "业务逻辑层" COL["集合 Collection
core/collection.go"] IDX_IF["索引接口 VectorIndex
core/index.go"] HNSW["HNSW 索引实现
core/hnsw_index.go"] FLAT["扁平索引实现
core/flat_index.go"] QUANT["量化器接口/实现
core/quantization.go"] end subgraph "存储层" STORE["存储 Storage
core/storage.go"] BBOLT["BoltDB 引擎
go.mod 外部依赖"] PROTO["Protobuf 序列化
core/proto/*.proto"] end EMB --> COL SVC --> API API --> COL COL --> IDX_IF IDX_IF --> HNSW IDX_IF --> FLAT COL --> STORE STORE --> BBOLT STORE --> PROTO QUANT --> STORE

核心组件

  • 存储层(Storage):基于 bbolt 的键值存储,每个集合一个桶;集合元数据保存在特殊桶中;使用 Protobuf 序列化点数据;支持可选的 8 位标量量化(SQ8)
  • 索引层(VectorIndex 接口及其实现):统一抽象,支持扁平暴力索引(FlatIndex)与 HNSW 图索引(HNSWIndex),运行时透明切换
  • 业务逻辑层(Collection):封装集合维度、距离度量、并发控制、持久化一致性保证;提供 Upsert/Search/Delete
  • API 层(Server):提供 Qdrant 兼容 REST 接口,负责路由、参数解析、错误处理与结果编码;支持自动加载持久化集合

架构总览

系统采用“存储层-索引层-业务逻辑层-API 层”的四层架构,结合“嵌入式库模式”和“独立服务模式”,满足不同部署场景的需求。

graph TB
Client["客户端/应用"] --> API["API 层
api/server.go"] API --> COL["业务逻辑层
core/collection.go"] COL --> IDX["索引层接口
core/index.go"] IDX --> HNSW["HNSW 实现
core/hnsw_index.go"] IDX --> FLAT["扁平实现
core/flat_index.go"] COL --> STORE["存储层
core/storage.go"] STORE --> BBOLT["bbolt 数据库"] STORE --> PROTO["Protobuf 序列化"] STORE --> QUANT["SQ8 量化器"]

详细组件分析

API 层(HTTP 服务器)

职责与特性: - 提供 Qdrant 兼容端点:集合管理、点写入、查询、删除 - 自动从存储加载集合元数据并初始化内存索引 - 并发安全:内部使用互斥锁保护 HTTP 服务器与集合映射 - 错误处理:对无效 JSON、不存在集合、内部错误返回标准状态码

关键流程(以搜索为例):

sequenceDiagram
participant C as "客户端"
participant S as "Server(api/server.go)"
participant M as "集合(Collection)"
participant I as "索引(VectorIndex)"
participant ST as "存储(Storage)"
C->>S : "POST /collections/{name}/points/search"
S->>S : "解析请求体/校验参数"
S->>M : "Search(query, filter, limit)"
M->>I : "Search(query, filter, topK)"
I->>I : "HNSW 图遍历/扁平扫描"
I-->>M : "TopK 结果(含ID/Payload)"
M-->>S : "结果"
S-->>C : "JSON 响应"

业务逻辑层(Collection)

职责与特性: - 统一管理集合维度、距离度量、并发读写 - 在创建时保存集合元数据并在存储中确保集合桶存在 - Upsert 严格遵循“先持久化、后更新内存索引”的顺序,失败时尽力回滚 - Search/Count/Delete 对外暴露一致的接口,内部通过索引层执行

Upsert 流程(带持久化一致性):

flowchart TD
Start(["进入 Upsert"]) --> Lock["加写锁"]
Lock --> Validate["校验维度/生成版本号"]
Validate --> Persist{"是否配置存储?"}
Persist --> |是| Save["存储层写入"]
Persist --> |否| UpdateMem["跳过存储"]
Save --> UpdateMem
UpdateMem --> IndexUpsert["索引层 Upsert"]
IndexUpsert --> Ok{"成功?"}
Ok --> |是| Unlock["解锁并返回"]
Ok --> |否| Rollback["尝试删除已写入的点(尽力而为)"]
Rollback --> Unlock

索引层(VectorIndex 抽象与实现)

  • 抽象接口:统一 Upsert/Search/Delete/Count/按条件筛选等能力
  • HNSW 实现:基于外部库,支持自定义 M、EfSearch 等参数;根据距离度量设置距离函数;支持按过滤条件后过滤(当前策略)
  • 扁平实现:内存中维护点映射,暴力计算距离,适合小规模或需要精确检索的场景

HNSW 搜索流程(含后过滤):

flowchart TD
Enter(["进入 Search"]) --> CheckFilter{"是否存在过滤?"}
CheckFilter --> |是| FetchK["扩大取数 K(估算过滤后数量)"]
CheckFilter --> |否| UseTopK["使用 topK"]
FetchK --> Graph["HNSW 图搜索"]
UseTopK --> Graph
Graph --> Iterate["遍历邻居节点"]
Iterate --> Lookup["按ID查点/校验Payload"]
Lookup --> Calc["按度量重新计算分数"]
Calc --> Collect["收集结果"]
Collect --> Done(["返回 TopK"])

存储层(Storage)

  • 持久化模型:每个集合一个桶;集合元数据保存在特殊桶中
  • 序列化:使用 Protobuf 将点结构序列化为字节,支持多类型负载
  • 量化:可选 SQ8 量化,写入时压缩、读取时解压
  • 并发:基于 bbolt 的事务模型,提供只读/读写事务

数据模型与过滤

  • PointStruct/SimplePoint:包含 ID、版本、向量、负载
  • Filter/Condition:支持 Must/MustNot、多种匹配类型(精确、范围、前缀、包含、正则)
  • 匹配算法:针对字符串、数组、数值等类型分别处理,支持正则编译与匹配

独立服务与嵌入式模式

  • 独立服务:命令行启动 HTTP 服务器,加载默认集合,注册到 API 服务器
  • 嵌入式库:应用直接导入 core 包,创建 Storage/Collection,进行 Upsert/Search

依赖关系分析

  • 外部依赖
  • HNSW 图库:用于近似最近邻搜索
  • bbolt:嵌入式键值数据库
  • Protobuf:结构化序列化
  • 内部耦合
  • API 层依赖 Collection
  • Collection 依赖 VectorIndex 接口与 Storage
  • HNSW/Flat 实现依赖 Collection 的数据结构
  • Storage 依赖 Protobuf 定义与 bbolt
graph LR
API["api/server.go"] --> COL["core/collection.go"]
COL --> IDX["core/index.go"]
IDX --> HNSW["core/hnsw_index.go"]
IDX --> FLAT["core/flat_index.go"]
COL --> STORE["core/storage.go"]
STORE --> BBOLT["bbolt"]
STORE --> PROTO["protobuf"]
STORE --> QUANT["core/quantization.go"]

性能与可扩展性

  • 索引选择
  • HNSW:支持子线性搜索复杂度,适合大规模数据;可通过参数调优(M、EfSearch、EfConstruction、K)
  • 扁平索引:O(n) 暴力搜索,适合小规模或需要精确检索的场景
  • 持久化与序列化
  • 使用 bbolt 与 Protobuf,兼顾吞吐与可靠性
  • SQ8 量化显著降低磁盘占用,适合大规模向量存储
  • 并发与一致性
  • Collection 使用读写锁,API 层也对集合映射加锁,避免竞态
  • Upsert 严格遵循“先持久化、后更新索引”的顺序,失败时尽力回滚
  • 可扩展性建议
  • 水平扩展:当前为单机嵌入式设计,不支持分布式复制;若需水平扩展,可在应用层拆分集合或引入代理层
  • 参数调优:根据数据规模与查询特征调整 HNSW 参数;启用量化以节省空间
  • 缓存:可在外层增加查询缓存(注意与版本/更新同步)

安全与运维

  • 安全
  • 当前未内置认证/授权与 TLS;建议在反向代理层添加鉴权与加密
  • 输入校验:API 层对 JSON、集合名、维度、度量等进行校验
  • 监控
  • 可在 API 层增加请求计数、耗时、错误率指标;结合日志输出
  • 灾难恢复
  • bbolt 文件即数据文件,定期备份;支持重启后自动加载集合元数据与点
  • Upsert 失败时尽力回滚,减少不一致风险

故障排查指南

  • 启动失败
  • 检查 bbolt 数据库文件权限与路径
  • 查看存储层打开错误与集合元数据加载错误
  • 查询异常
  • 确认查询向量维度与集合维度一致
  • 检查过滤条件是否正确(Must/MustNot、匹配类型)
  • 写入失败
  • 关注 Upsert 的持久化与索引更新顺序;查看回滚日志
  • 服务关闭
  • 使用优雅关闭,等待连接完成或超时

结论

本项目以清晰的分层架构实现了“嵌入式向量数据库”的核心能力:高性能检索(HNSW)、可靠持久化(bbolt+Protobuf)、灵活过滤与双模式部署(嵌入式/微服务)。通过抽象化的索引接口与严格的持久化顺序,系统在可用性与一致性之间取得良好平衡。未来可在查询过滤下推、水平扩展与可观测性方面进一步演进。