背景 · WHY
为什么需要跨节点共享内存
内存容量墙
数据集增长快过 DRAM 扩容。大内存数据库、大模型训练、科学计算皆受制于单机内存上限。
网络搬运贵
传统 NIC 路径 = 多次拷贝 + 协议栈 + 序列化。时延高、CPU 开销大,数据永远在「路上」。
RDMA 模型重
显式 verb 编程、内存注册。指针语义丢失——远端地址不能解引用,数据结构无法共享。
灵衢 UniBus 的能力
多台服务器经一致性互连共享物理内存,CPU 用普通访存指令直达远端;UB 事务 = EID + TokenID + UBA,由 UMMU 完成翻译与鉴权。
仍然缺失的一环
总线不提供跨节点硬件缓存一致性——多节点并发写同一内存必然产生数据竞争。
OBMM 的答案:所有权(Ownership)—— 任一时刻,仅允许一个节点写入,在软件层补齐一致性。
全景 · ARCHITECTURE
六层软件栈:从 UB 硬件到 malloc
上层定义「怎么用」,下层保证「走得通」。悬停 / 点击任意层查看职责与关键代码路径。
机制 · MECHANISM
三个核心机制
地址翻译:一次远端访问的硬件路径
使用方节点 A
O_SYNC 打开 → NC 窗口
UB 事务
EID · TokenID · UBA
UBC / CNA 硬件路由 · 零软件参与
提供方节点 B
export 时经 dma_map 建立授权
export 建授权(UMMU dma_map)· import 建窗口(decoder MAP)· 访问路径零软件参与
所有权:单写者一致性
obmm_set_ownership(fd, start, end, prot)
释放写权 = 最后写者:SoC cache 写回 + 失效,再排空 UB 写队列(drain)——无硬件一致性下的软件补齐。粒度:页 / 2 MB(PMD)。
交接时序:A 写完 → B 接力
B 等待期间为空权限,不可访问。适合区间固定、写者少、交接不频繁的共享。
预导入 preimport:把建节点移出关键路径
obmm_preimport(pa, len, 链路) → obmm_import(PREIMPORT | NUMA_REMOTE) · 区间按 128 MB 对齐且不重叠 · 维测 /proc/obmm/preimport_info
使用场景 · SCENARIOS
三条使用路径,对号入座
远端内存即本地 NUMA 节点
- NUMA_REMOTE 导入:热插拔上线,内核视为普通节点
- base_dist 控制距离,调度与放置自然倾斜
- 有 struct page:O_DIRECT / io_uring / mbind 全兼容
- preimport 提前建节点,注入即用
/* 使用方:把远端内存上线为 NUMA 节点 */
int numa = -1;
mem_id id = obmm_import(&desc,
OBMM_IMPORT_FLAG_NUMA_REMOTE,
120 /* base_dist */, &numa);
# 业务零改动,照常用 NUMA 工具
numactl --membind=$numa ./db_worker
mbind() / move_pages() # 均可用
malloc 语义的跨节点共享
节点 A obmmalloc_malloc() 返回的指针,节点 B 直接解引用。
- 同 VA 布局:一份 pool.json,全局统一地址
- 去中心协调:共享 bitmap 上的 8B CAS,无单点
- 原生手感:jemalloc 快路径,开销 ≈ 原生 malloc
/* 每个节点执行同一份配置装配 */
obmmalloc_pool_init_file("pool.json");
// 节点 1:分配并发布指针
ring_push(ring,
obmmalloc_malloc(64 * 1024));
// 节点 2:同一池,直接解引用
hdr = (hdr_t *)ring_pop(ring);
边界提示:场景 02 为单写者模型,高频细粒度抢写请走场景 03 的多写者 CAS + 底层 CC;obmmalloc 进程退出后 chunk 按设计不回收,且不能跨进程 free。
组件 · OBMMALLOC
obmmalloc:共享池上的三层分配器
L2
jemalloc 适配
extent hooks(alloc / dalloc / split / merge)挂到专用 arena;extent 元数据驻留进程本地堆,共享池内零残留。
L1
分布式 chunk 分配器
快路径:本地 cache LIFO pop(O(1));慢路径:共享 bitmap 随机起点扫描 + 8B CAS 认领,回填 cache 摊薄开销。
L0
128 TB 同 VA 池
superblock 驻 chunk 0(约 2 MB);所有节点以 MAP_FIXED_NOREPLACE 钉到相同 VA —— 指针全局有效。
同一份 pool.json 装配
① 本地段:sysfs 匹配 export → mmap /dev/obmm_shmdev{N}
② 远端段:vUB decoder 编程 → ioctl IMPORT → mmap
③ 全部段钉到相同槽位 VA → obmmalloc_init()
设计边界
依赖底层 CC 一致性,不使用 ownership;进程退出后 chunk 按设计不回收(无心跳/自动回收);jemalloc 元数据在本地,跨进程 free 无效。
选型 · DECISION
先选消费形态,再谈优化
B · 扩容量
NUMA remote + preimport
页分配器消费内存:容量扩展、冷热分层、容器扩容。业务无感,生态全兼容。
obmm_import(NUMA_REMOTE)
A · 强协同
mmap import + 所有权
直接指针访问:共享缓冲 / 状态区,单写者显式交接,区间固定可提前划分。
obmm_import(ALLOW_MMAP) + set_ownership
C · 要 malloc
obmmalloc
动态对象、多写者并发、指针跨节点传递。底层即 A 的 mmap import。
obmmalloc_pool_init_file() + malloc/free
| 维度 | A · mmap + 所有权 | B · NUMA remote | C · obmmalloc |
|---|---|---|---|
| 一致性模型 | 单写者,显式交接 | 单节点占用 | 多写者 CAS + 底层 CC |
| 内存形态 | VM_PFNMAP,无 struct page | 远程 NUMA,有 struct page | 同 VA 池 |
| 分配粒度 | 手工划分区间 | 页分配器 4K / 2M | malloc 任意大小 |
| VA 语义 | 各进程独立 VA | 透明 NUMA | 全局统一 VA |
生态 · ECOSYSTEM
obmm-ecology 工具链
ubqemu
QEMU 虚拟 UB 控制器。两台 VM 跑通全栈,免真实硬件开发调试。
gitcode ↗obmmctl
Rust CLI:export / import / preimport / query / list / monitor。
gitcode ↗obmm-test
分布式测试框架:多主机用例编排与跨节点行为验证。
gitcode ↗obmmalloc
共享池上的 malloc:jemalloc extent hooks + 128 TB 同 VA 池。
gitcode ↗快速开始 · QUICK START
十分钟跑通双节点
STEP 1
起虚拟集群
git clone https://gitcode.com/obmm-ecology/ubqemu
cd ubqemu && git checkout ub-vub
# 按 README 启动两台 Guest VM
ubqemu 内置虚拟 UB 控制器,双 VM 即完整双节点栈。
STEP 2
导出 / 导入内存
# 节点 0 导出 2G 共享内存
obmmctl export --size 2G
# 节点 1 引入为远端内存
obmmctl import --from 0
obmmctl 亦可查询 / 监控全部 region。
STEP 3
跑 obmmalloc
git clone https://gitcode.com/obmm-ecology/obmmalloc
cd obmmalloc && cmake -B build && cmake --build build
./build/test_l2_malloc # 100×64KB 共享池分配
生产使用:编写 pool.json,调用 obmmalloc_pool_init_file()。