openEuler 24.03 SP3 灵衢 UniBus GPL-2.0 / Mulan PSL v2

OBMM
基于所有权的跨节点内存管理

Ownership Based Memory Management —— 在缺乏跨节点硬件缓存一致性的互连上,实现安全、透明、可编程的多节点内存共享。普通 load / store,直达远端内存。

128 TBobmmalloc 同 VA 共享池
131,072× 1 GB chunk 槽位
8 BCAS 协调单元
0daemon · 跨进程锁

背景 · WHY

为什么需要跨节点共享内存

内存容量墙

数据集增长快过 DRAM 扩容。大内存数据库、大模型训练、科学计算皆受制于单机内存上限。

网络搬运贵

传统 NIC 路径 = 多次拷贝 + 协议栈 + 序列化。时延高、CPU 开销大,数据永远在「路上」。

RDMA 模型重

显式 verb 编程、内存注册。指针语义丢失——远端地址不能解引用,数据结构无法共享。

灵衢 UniBus 的能力

多台服务器经一致性互连共享物理内存,CPU 用普通访存指令直达远端;UB 事务 = EID + TokenID + UBA,由 UMMU 完成翻译与鉴权。

仍然缺失的一环

总线不提供跨节点硬件缓存一致性——多节点并发写同一内存必然产生数据竞争。

OBMM 的答案:所有权(Ownership)—— 任一时刻,仅允许一个节点写入,在软件层补齐一致性。

全景 · ARCHITECTURE

六层软件栈:从 UB 硬件到 malloc

上层定义「怎么用」,下层保证「走得通」。悬停 / 点击任意层查看职责与关键代码路径。

机制 · MECHANISM

三个核心机制

地址翻译:一次远端访问的硬件路径

使用方节点 A

应用 · load / store
页表:VA → PA
decoder 窗口:PA

O_SYNC 打开 → NC 窗口

UB 事务

EID · TokenID · UBA

UBC / CNA 硬件路由 · 零软件参与

提供方节点 B

UMMU:TokenID 鉴权
翻译 → 物理页
导出 DRAM(hugetlb)

export 时经 dma_map 建立授权

export 建授权(UMMU dma_map)· import 建窗口(decoder MAP)· 访问路径零软件参与

所有权:单写者一致性

空 · PROT_NONE
读 · READ
写 · WRITE

obmm_set_ownership(fd, start, end, prot)

全局约束:多读 或 单写,不可同时

释放写权 = 最后写者:SoC cache 写回 + 失效,再排空 UB 写队列(drain)——无硬件一致性下的软件补齐。粒度:页 / 2 MB(PMD)。

交接时序:A 写完 → B 接力

节点 A
取写权写入数据释放
交接cache WB + INVAL · drain
节点 B
取权直接访问

B 等待期间为空权限,不可访问。适合区间固定、写者少、交接不频繁的共享。

预导入 preimport:把建节点移出关键路径

无 preimport
创建远程 NUMA 节点 · 慢注入
import 全程阻塞,业务等待
有 preimport
提前建隔离节点 · 非关键路径
注入
import 只做注入上线

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 提前建节点,注入即用
大内存数据库AI 训练 checkpoint冷热分层容器扩容
/* 使用方:把远端内存上线为 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() # 均可用

单写者所有权协同

  1. A 取写权 set_ownership(WRITE)
  2. A 直接写 普通 store
  3. A 释放 cache 写回 + 失效
  4. B 取权 读 / 写接力
  5. B 访问 普通 load
分布式缓存实时行情协同流水线主备高可用
/* 映射远端共享区(先给空权限)*/
fd  = open("/dev/obmm_shmdev7", O_RDWR);
ptr = mmap(NULL, SZ_2M, PROT_NONE,
           MAP_SHARED, fd, 0);

/* A:取写权 → 写 → 释放交接 */
obmm_set_ownership(fd, ptr,
        ptr + SZ_2M, PROT_WRITE);
strcpy(ptr, "hello-from-A");
obmm_set_ownership(fd, ptr,
        ptr + SZ_2M, PROT_NONE);

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 remoteC · obmmalloc
一致性模型单写者,显式交接单节点占用多写者 CAS + 底层 CC
内存形态VM_PFNMAP,无 struct page远程 NUMA,有 struct page同 VA 池
分配粒度手工划分区间页分配器 4K / 2Mmalloc 任意大小
VA 语义各进程独立 VA透明 NUMA全局统一 VA

快速开始 · 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()。