数据产品 · Bitcask for Erlang/OTP
Bitcask · Erlang/OTP 的检索、事务与图数据层
沿用 Basho Bitcask 的日志结构设计,存储与检索引擎换成我们的 libbitcask,经一个 C++23 NIF 接进 Erlang/OTP。对 Erlang 程序来说,它仍然是熟悉的 bitcask:open / put / get。
在这之上,open 时配一个 embedder,写入文本就自动生成向量;查询一句话,全文和向量两路融合返回。事务、图遍历与图分析都在 OTP 里完成,不需要另外的服务。
一个 OTP 应用:存、搜、算、事务
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(范围);前缀扫描一行搞定。
技术实现
里面是怎么做的
bitcask:Erlang 门面
bitcask.erl 是薄门面,全部操作经 bitcask_cpp_nifs 进入 priv/bitcask_cpp.so,即编译进 NIF 的 libbitcask。耗时操作走 dirty NIF,不阻塞 BEAM 调度器;open 返回 {CaskRef, EmbedderCtx},整体作为句柄传递。
bitcask_txn:事务协调
纯 OTP 实现、引擎零改动:写入缓冲在调用进程里,提交时按 key 升序展开成一条 txn_commit 原子批;bitcask_txn_locker 管理悲观两阶段锁,按分片部署,wait-for 图做死锁检测,选环上最年轻的事务作牺牲者并自动重跑;前缀锁防幻读,提交令牌保证调用方中途被 kill 也不会提前放锁。
嵌入(embedder)
bitcask_embedder 是行为(behaviour),内置 OpenAI 兼容实现;可选的本地后端是独立的第二个 NIF(priv/bitcask_llama.so),由 bitcask_embedder_server 进程持有模型权重,多个库共用一份,slots 配置多路并发推理,proxy 按最短队列分摊。
graphdb:图处理
顶点与边按定宽 key 存进 KV,边经原子批正反双写;邻接遍历走有序前缀 range,支持 BFS、k-hop、双向最短路;graphdb_analytics 把图物化成内存 CSR,跑 PageRank、连通分量、单源最短路。
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,可用于商业项目。
同一个引擎
libbitcask · 嵌入式 KV 与检索引擎
C++23 写的 Bitcask 追加日志 KV,叠上 BM25 全文、向量近邻与 RRF 混合检索。C++ 库直接用,C ABI 供其它语言绑定。