数据产品 · Bitcask for Erlang/OTP

Bitcask · Erlang/OTP 的检索、事务与图数据层

沿用 Basho Bitcask 的日志结构设计,存储与检索引擎换成我们的 libbitcask,经一个 C++23 NIF 接进 Erlang/OTP。对 Erlang 程序来说,它仍然是熟悉的 bitcask:open / put / get。

在这之上,open 时配一个 embedder,写入文本就自动生成向量;查询一句话,全文和向量两路融合返回。事务、图遍历与图分析都在 OTP 里完成,不需要另外的服务。

一个 OTP 应用:存、搜、算、事务

Erlang:隔离事务(悲观 2PL + 死锁检测 + 自动重跑)
1> R = bitcask:open("/tmp/db", [read_write]).
2> bitcask:put(R, <<"a">>, <<"100">>), bitcask:put(R, <<"b">>, <<"0">>).
3> bitcask_txn:transaction(R, fun(Tx) ->
       {ok, A} = bitcask_txn:read(Tx, <<"a">>),
       {ok, B} = bitcask_txn:read(Tx, <<"b">>),
       ok = bitcask_txn:write(Tx, <<"a">>, integer_to_binary(binary_to_integer(A) - 30)),
       ok = bitcask_txn:write(Tx, <<"b">>, integer_to_binary(binary_to_integer(B) + 30)),
       moved
   end).
{atomic,moved}
4> [bitcask:get(R, K) || K <- [<<"a">>, <<"b">>]].
[{ok,<<"70">>},{ok,<<"30">>}]

功能

能做什么

  • 检索:全文、向量、融合

    用 {analyzer, whitespace | ngram | jieba} 打开即启用 BM25,put 自动索引;向量引擎可选 hnsw / ivfrq / diskann;RRF 混合检索融合两路排序。

  • 嵌入自动化

    open 时传入 embedder,集合维度自动对齐,之后写入文本和查询都自动生成向量。支持 OpenAI 兼容端点(如 llama.cpp server、vLLM),也可选本地 llama.cpp 嵌入后端,CUDA / Vulkan 加速,多个库共用一份权重。

  • 原子批与隔离事务

    put_batch_atomic / txn_commit 跨崩溃全有或全无;bitcask_txn 在其上补齐隔离性:悲观两阶段锁、死锁检测、自动重跑,前缀锁让事务内范围扫描没有幻读。

  • 幂等键

    调用方在提交途中被 kill、拿不到结果时,用同一个 idem_key 重试:同键至多提交一次,重来返回第一次的结果。

  • 图处理层

    graphdb 把顶点和边存在 KV 里,邻接走有序前缀扫描:BFS、k-hop、双向最短路、条件过滤遍历;graphdb_analytics 物化成内存 CSR,跑 PageRank、连通分量、单源最短路。

  • 有序范围查询

    range / range_fold 按 key 字典序取 [Lo, Hi),代价 O(范围);前缀扫描一行搞定。

技术实现

里面是怎么做的

  1. bitcask:Erlang 门面

    bitcask.erl 是薄门面,全部操作经 bitcask_cpp_nifs 进入 priv/bitcask_cpp.so,即编译进 NIF 的 libbitcask。耗时操作走 dirty NIF,不阻塞 BEAM 调度器;open 返回 {CaskRef, EmbedderCtx},整体作为句柄传递。

  2. bitcask_txn:事务协调

    纯 OTP 实现、引擎零改动:写入缓冲在调用进程里,提交时按 key 升序展开成一条 txn_commit 原子批;bitcask_txn_locker 管理悲观两阶段锁,按分片部署,wait-for 图做死锁检测,选环上最年轻的事务作牺牲者并自动重跑;前缀锁防幻读,提交令牌保证调用方中途被 kill 也不会提前放锁。

  3. 嵌入(embedder)

    bitcask_embedder 是行为(behaviour),内置 OpenAI 兼容实现;可选的本地后端是独立的第二个 NIF(priv/bitcask_llama.so),由 bitcask_embedder_server 进程持有模型权重,多个库共用一份,slots 配置多路并发推理,proxy 按最短队列分摊。

  4. graphdb:图处理

    顶点与边按定宽 key 存进 KV,边经原子批正反双写;邻接遍历走有序前缀 range,支持 BFS、k-hop、双向最短路;graphdb_analytics 把图物化成内存 CSR,跑 PageRank、连通分量、单源最短路。

  5. OTP 监督树

    bitcask_sup 以 one_for_one 策略监督全局 merge 调度器(时间窗口、去重、限流)与事务锁管理器分片;只有在 application env 里配置了 embedder 时,才多出 embedder 服务进程。整体是标准 OTP 应用,随你的系统启动和停止。

规格

技术规格

运行环境Erlang/OTP 27+,rebar3 构建
实现单一 C++23 NIF(libbitcask)+ 薄 Erlang 门面
嵌入后端OpenAI 兼容 HTTP 端点;可选本地 llama.cpp(默认不构建,开启后支持 CUDA / Vulkan)
测试C++ 400+ GoogleTest,Erlang eunit 全量通过
许可Apache License 2.0

常见问题

你可能想问

和 Basho 原版 bitcask 是什么关系?

沿用原版的日志结构设计与 bitcask:open / put / get 的使用方式,存储与检索引擎换成了 C++23 的 libbitcask,并加上全文、向量、事务、图等能力。

需要哪个 OTP 版本?

最低 Erlang/OTP 27,用 rebar3 构建;C++ 部分需要 C++23 编译器与 ICU 开发包。

嵌入(embedding)必须用 GPU 吗?

不必。可以接任何 OpenAI 兼容的嵌入端点(如 llama.cpp server、vLLM);也可以构建本地 llama.cpp 后端,有独立显卡时用 CUDA 或 Vulkan 加速,没有就走 CPU。

事务提供什么保证?

put_batch_atomic / txn_commit 保证跨崩溃的原子性;bitcask_txn 在此之上提供隔离:两阶段锁、死锁检测、自动重跑。注意事务函数可能被执行多次,必须没有副作用;直通的 bitcask:put / get 不经过锁,不要与事务混用同一批 key。

许可协议是什么?

Apache License 2.0,可用于商业项目。

开源

Apache 2.0 协议开源

引擎、测试、基准与设计文档都在仓库里,欢迎读、改、提 issue。

同一个引擎

libbitcask · 嵌入式 KV 与检索引擎

C++23 写的 Bitcask 追加日志 KV,叠上 BM25 全文、向量近邻与 RRF 混合检索。C++ 库直接用,C ABI 供其它语言绑定。