Zvec 架构深度解析:阿里开源轻量级进程内向量数据库
Zvec 是阿里巴巴开源的一个轻量级、闪电般快速的进程内向量数据库。本文将深入分析 Zvec 的代码架构,揭示其核心设计理念和技术实现细节。
一、项目概览
1.1 核心特性
Zvec 基于 Alibaba 久经考验的 向量搜索引擎构建,提供生产级的低延迟、可扩展的相似度搜索能力:
Zvec 是阿里巴巴开源的轻量级进程内向量数据库,基于 Proxima 引擎构建。支持稠密与稀疏向量混合搜索,提供毫秒级低延迟性能。架构采用分层设计,包含用户层、绑定层、数据库层及核心索引框架,存储层结合 RocksDB 与 MMap。支持 C++ 原生及 Python、Node.js 绑定。目前 PyPI 包尚未发布,源码构建需初始化 Git 子模块。适用于 RAG、推荐系统及边缘计算等对延迟敏感场景。
Zvec 是阿里巴巴开源的一个轻量级、闪电般快速的进程内向量数据库。本文将深入分析 Zvec 的代码架构,揭示其核心设计理念和技术实现细节。
Zvec 基于 Alibaba 久经考验的 向量搜索引擎构建,提供生产级的低延迟、可扩展的相似度搜索能力:
| 组件 | 技术 |
|---|---|
| 语言 | C++17 |
| 构建系统 | CMake |
| Python 绑定 | Pybind11 |
| 存储引擎 | RocksDB |
| 向量索引 | Proxima (IVF, HNSW, Flat) |
| 序列化 | Protobuf |
| 压缩 | LZ4 |
| 位图 | CRoaring |
| 距离计算 | SIMD 加速 |
zvec/
├── src/
│ ├── include/zvec/ # 公共头文件
│ │ ├── core/ # 核心索引框架
│ │ │ ├── framework/ # 索引组件框架
│ │ │ └── interface/ # 索引接口定义
│ │ ├── db/ # 数据库层
│ │ └── ailego/ # 基础工具库
│ ├── binding/python/ # Python 绑定
│ └── ailego/ # 辅助工具实现
├── thirdparty/ # 第三方依赖
├── python/ # Python 包
├── tests/ # 测试用例
└── CMakeLists.txt
架构层次说明:
Zvec 提供三种索引类型,根据数据规模自动选择最优算法:
| 索引类型 | 适用场景 | 特点 |
|---|---|---|
| Flat | 小数据集 (<10 万) | 100% 召回率,暴力搜索 |
| IVF | 中等数据集 (10 万 -1 亿) | 聚类分区,速度与精度平衡 |
| HNSW | 大数据集 (>1 亿) | 图结构,极快查询 |
核心代码实现 (src/include/zvec/core/interface/index.h):
class Index {
public:
virtual int Add(const VectorData &vector, uint32_t doc_id);
virtual int Search(const VectorData &query, SearchParams *, SearchResult *);
virtual int Train();
virtual int Open(const std::string &file_path, StorageOptions);
};
// 三种索引类型实现
class FlatIndex : public Index {};
// 暴力搜索
class IVFIndex : public Index {};
// 倒排文件索引
class HNSWIndex : public Index {};
// 层次导航小世界图
IndexHolder 是一个精心设计的模板系统,用于在索引构建和搜索期间管理向量数据。
OnePass*Holder:单次遍历,迭代时消耗数据(使用 std::list)MultiPass*Holder:支持多次遍历(使用 std::vector)RandomAccessIndexHolder:O(1) 随机访问NumericalIndexHolder:FP16, FP32, FP64, INT8, INT16BinaryIndexHolder:Binary32, Binary64SparseIndexHolder:稀疏向量(indices + values)HybridIndexHolder:稠密 + 稀疏组合element_size() 返回 dimension * sizeof(type)(dim + 7) / 8 * sizeof(T) 公式OnePass holders 使用 std::list<std::pair<key, vector>>:
MultiPass holders 使用 std::vector<std::pair<key, vector>>:
struct SparseVector {
uint32_t count;
const void* indices; // uint32_t*
const void* values; // 类型特定*
};
struct HybridVector {
// 组合稠密和稀疏向量
// 支持混合搜索策略
};
| Holder 类型 | 容器 | 迭代特性 | 内存策略 | 适用场景 |
|---|---|---|---|---|
| OnePass | std::list | 消费数据 | 迭代后释放 | 单次遍历(索引构建) |
| MultiPass | std::vector | 保留数据 | holder 销毁时释放 | 多次遍历(搜索精炼) |
| RandomAccess | 紧凑数组 + key 向量 | 随机访问 | 紧凑布局 | O(1) 查找需求 |
class HnswQueryParams : public QueryParams {
int ef_; // 探索因子
float radius_; // 搜索半径
bool is_linear_; // 是否使用线性扫描
bool is_using_refiner_; // 是否使用精炼器
};
class IVFQueryParams : public QueryParams {
int nprobe_; // 探测的簇数量
float scale_factor_; // 缩放因子
};
class CollectionImpl : public Collection {
// 路径管理
std::string path_;
bool destroyed_{false};
// Schema 和选项
CollectionSchema::Ptr schema_;
CollectionOptions options_;
mutable std::shared_mutex schema_handle_mtx_;
// 分片管理
std::atomic<SegmentID> segment_id_allocator_;
std::atomic<SegmentID> tmp_segment_id_allocator_;
Segment::Ptr writing_segment_;
SegmentManager::Ptr segment_manager_;
// 版本管理
VersionManager::Ptr version_manager_;
// 并发控制
mutable std::shared_mutex write_mtx_;
// 文件锁和元数据
ailego::File lock_file_;
IDMap::Ptr id_map_;
DeleteStore::Ptr delete_store_;
sqlengine::SQLEngine::Ptr sql_engine_;
};
enum class WriteMode : uint8_t {
UNDEFINED = 0,
INSERT, // 仅插入新文档
UPDATE, // 更新现有文档
UPSERT, // 更新或插入
};
Writing Segment:用于写入的活动分片
max_doc_count_per_segment(1000 万)时自动切换Segment Manager:管理所有非写入分片
ID 分配:分片 ID 的原子分配
SegmentID allocate_segment_id() {
return segment_id_allocator_.fetch_add(1);
}
Schema 操作:std::shared_mutex schema_handle_mtx_
写入操作:std::shared_mutex write_mtx_
分段读取:无锁
collection_root/
├── _CollectionLock # 进程锁文件
├── meta/ # 元数据
│ ├── schema.pb # 集合 schema
│ ├── config.pb # 选项配置
│ └── version.pb # 版本信息
├── segments/ # 数据分片
│ ├── segment_00001/
│ │ ├── meta.pb # 分片元数据
│ │ ├── data/ # 原始向量数据
│ │ ├── indexes/ # 向量索引
│ │ │ ├── flat/
│ │ │ ├── ivf/
│ │ │ └── hnsw/
│ │ ├── forward/ # 标量字段
│ │ │ └── rocksdb/
│ │ └── sql.db # SQL 引擎数据库
│ └── ...
├── writing_segment/ # 活动写入分片
├── id_map/ # PK → DocID 映射
├── delete_store/ # 删除墓碑标记
└── version_manager/ # 版本跟踪
IndexStorage (src/include/zvec/core/framework/index_storage.h):
struct MemoryBlock {
enum MemoryBlockType {
MBT_MMAP = 1, // 内存映射文件
MBT_BUFFERPOOL = 2 // 内存池缓冲区
};
// 支持零拷贝访问
const void* data;
BufferHandle buffer_handle_;
};
class IndexStorage {
// 段管理
virtual int open(const std::string &path, bool create) = 0;
virtual int append(const std::string &id, size_t size) = 0;
virtual Segment::Pointer get(const std::string &id) = 0;
};
RocksDB 集成:
// 内存映射文件,零拷贝访问
class MMapFile {
int fd_;
void* mapped_data_;
size_t size_;
int map(const std::string &path, size_t size, int prot, int flags);
int unmap();
};
优势:
PYBIND11_MODULE(_zvec, m){
ZVecPyTyping::Initialize(m); // 类型定义
ZVecPyParams::Initialize(m); // 参数绑定
ZVecPySchemas::Initialize(m); // Schema 绑定
ZVecPyConfig::Initialize(m); // 配置绑定
ZVecPyDoc::Initialize(m); // 文档绑定
ZVecPyCollection::Initialize(m); // 集合绑定
}
C++ Status → Python Exception:
void throw_if_error(const Status &status) {
switch(status.code()) {
case StatusCode::NOT_FOUND: throw py::key_error(status.message());
case StatusCode::INVALID_ARGUMENT: throw py::value_error(status.message());
default: throw std::runtime_error(status.message());
}
}
template<typename T>
T unwrap_expected(const tl::expected<T, Status>& exp) {
if(exp.has_value()) { return exp.value(); }
throw_if_error(exp.error());
}
import zvec
# 定义 Schema
schema = zvec.CollectionSchema(
name="example",
vectors=zvec.VectorSchema("embedding", zvec.DataType.VECTOR_FP32, 4)
)
# 创建并打开集合
collection = zvec.create_and_open(path="./zvec_example", schema=schema)
# 插入文档
collection.insert([
zvec.Doc(id="doc_1", vectors={"embedding": [0.1, 0.2, 0.3, 0.4]}),
zvec.Doc(id="doc_2", vectors={"embedding": [0.2, 0.3, 0.4, 0.1]}),
])
# 向量搜索
results = collection.query(
zvec.VectorQuery("embedding", vector=[0.4, 0.3, 0.3, 0.1]),
topk=10
)
// SIMD 优化的批量计算
namespace math_batch {
// 批量点积计算
void dot_product_simd(const float* a, const float* b, size_t n, float* result);
// 批量 L2 距离计算
void l2_distance_simd(const float* a, const float* b, size_t n, float* result);
}
class BufferManager {
// 预分配内存池
void* allocate(size_t size);
// 回收内存到池中
void deallocate(void* ptr);
// 批量分配,减少系统调用
std::vector<void*> batch_allocate(size_t size, size_t count);
};
| 依赖 | 用途 | 原因 |
|---|---|---|
| RocksDB | 结构化数据存储 | 高性能 KV 引擎 |
| Arrow | 列式数据格式 | 零拷贝互操作性 |
| Protobuf | 元数据序列化 | 跨语言兼容 |
| LZ4 | 数据压缩 | 极快压缩/解压 |
| CRoaring | 位图索引 | 压缩集合运算 |
| SparseHash | 稀疏数据存储 | 内存高效 |
| glog | 日志记录 | Google 风格日志 |
| ANTLR | 表达式解析 | 过滤表达式 |
| googletest | 单元测试 | Google 测试框架 |
流程关键点:
std::shared_mutex 确保写入串行化Python API ↓ Pybind11 包装器 (throw_if_error) ↓ Collection::Insert() ↓ CollectionImpl::write_impl(INSERT) ↓
1. 获取写锁 (std::shared_mutex)
2. 检查分片容量
3. 如需要切换到新分片
4. 分配文档 ID (IDMap)
5. 写入向量数据 (VectorSegment)
6. 写入标量数据 (RocksDB)
7. 更新分片元数据
8. 释放写锁 ↓
返回 WriteResults ↓ Python WriteResults 对象
Python VectorQuery ↓ Pybind11 包装器 ↓ Collection::Query() ↓ CollectionImpl::Query() ↓
1. 解析查询参数
2. 识别相关分片
3. 查询每个分片索引 - HNSWIndex::Search() - 或 IVFIndex::Search() - 或 FlatIndex::Search()
4. 应用过滤器(如果有)
5. 合并和排序结果
6. 精炼 top-K 结果(如果配置) ↓
返回 DocPtrList ↓ Python Doc 对象列表
| 特性 | Zvec (进程内) | Milvus/Pinecone (服务器) |
|---|---|---|
| 延迟 | ~1ms | ~10-100ms |
| 部署 | 嵌入式 | 独立服务 |
| 扩展性 | 单机 | 水平扩展 |
| 配置 | 无 | 必需 |
| 资源占用 | 与应用共享 | 专用 |
Zvec 的架构设计使其特别适合以下场景:
| 功能 | 文件路径 |
|---|---|
| 索引接口 | src/include/zvec/core/interface/index.h |
| 集合接口 | src/include/zvec/db/collection.h |
| 索引 Holder | src/include/zvec/core/framework/index_holder.h |
| 索引存储 | src/include/zvec/core/framework/index_storage.h |
| 集合实现 | src/db/collection.cc |
| Python 绑定 | src/binding/python/model/python_collection.cc |
| Schema | src/include/zvec/db/schema.h |
| 查询参数 | src/include/zvec/db/query_params.h |
注意:由于 Zvec 的 PyPI 包尚未发布,实际安装需关注官方动态。
根据 README 文档,Zvec 声称支持 Python 3.10-3.12 版本,可通过 pip install zvec 安装。但实际尝试中发现:
pip install zvec 返回 'No matching distribution found'建议:关注 GitHub Releases 获取预构建包,或等待 PyPI 正式发布。
# 激活 Python 环境
source ~/miniforge3/bin/activate py311
# 克隆仓库
git clone https://github.com/alibaba/zvec.git
cd zvec
# 初始化 Git Submodules
git submodule update --init --recursive
# 配置构建
mkdir -p test_build && cd test_build
cmake -S .. -B . -DCMAKE_BUILD_PYTHON_BINDINGS=OFF
# 构建
make -j4
git submodule update --init --recursiveZvec 是一个设计精良的向量数据库,其核心优势在于:
GitHub: https://github.com/alibaba/zvec
文档: https://zvec.org

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online