RogueMap 性能白皮书
概述
RogueMap 是一个高性能的嵌入式键值存储引擎,专注于解决 Java 应用中堆内存受限和数据持久化的痛点。本文档将客观、全面地展示 RogueMap 的性能表现,并说明其设计权衡。
设计理念:不可能三角的选择
在键值存储领域存在一个经典的"不可能三角":
极致速度
/\
/ \
/ \
/ \
/________\
存储突破 并发安全三个维度:
- 极致速度 - 纯内存操作,无序列化开销(如 HashMap、FastUtil)
- 存储突破 - 突破 JVM 堆内存限制,支持磁盘映射和持久化
- 并发安全 - 线程安全,支持高并发读写
三者只能取其二:
- HashMap/FastUtil:选择"速度 + 并发安全",放弃"存储突破"
- RogueMap:选择"存储突破 + 并发安全",在速度上做出权衡
为什么 RogueMap 选择后两者?
现代 Java 应用面临的核心痛点:
- 堆内存受限 - 大数据量导致频繁 Full GC,应用卡顿
- 数据易失 - 进程重启数据全部丢失
- 内存成本高 - 堆内存扩容成本远高于磁盘
这些问题是 HashMap、FastUtil、Caffeine 等纯内存方案无法解决的。因此,RogueMap 选择:
- ✅ 存储突破 - 堆外内存 + 磁盘 mmap 映射,减少 84.7% 堆内存占用
- ✅ 并发安全 - 64 段分段锁 + StampedLock 乐观锁
- ⚠️ 速度权衡 - 读取涉及序列化,约为 HashMap 的 1/4
但速度仍然很快
虽然做出了权衡,但 RogueMap 在速度优化上投入了大量精力:
- 写入优化 - 只写索引不写数据,比 HashMap 快 1.45 倍
- 零拷贝序列化 - 原始类型直接内存布局
- Slab 内存分配器 - 7 个 size class,减少碎片
- 分段锁优化 - 64 段并发,降低锁竞争
- 操作系统优化 - mmap 页缓存加速
结果:在 Linux 2C4G 机器上,RogueMap 读取吞吐达到 155 万 ops/s,这个性能:
- 比 Redis 网络快 15.6 倍(Redis 网络: 100,000 ops/s)
- 比 Redis 本地快 1.56 倍(Redis 本地: 1,000,000 ops/s)
- 比 MapDB 快 12.0 倍(MapDB: 129,718 ops/s)
- 满足绝大多数业务场景
测试环境
硬件配置:
- CPU: Linux 2 核
- 内存: 4GB
- 存储: SSD
测试数据:
- 数据量: 100 万条记录
- 对象结构: 包含 10 个属性的 PO 值对象
- 测试类型: 顺序写入 + 随机读取
性能数据说明:
- RogueMap、HashMap、FastUtil、Caffeine: 实测数据,基于真实测试结果
- MapDB: 实测数据,基于真实测试结果(来自独立性能测试)
- Redis 本地: 估算值,基于 Unix socket 本地通信的典型性能(~1μs 延迟)
- Redis 网络: 估算值,基于 TCP/IP 网络通信的典型性能(~100μs 延迟)
完整性能对比
综合性能表现
基于 Linux 2C4G 服务器,100 万条数据测试结果:
| 方案 | 写入时间 | 读取时间 | 写吞吐量 | 读吞吐量 | 堆内存占用 | 持久化 |
|---|---|---|---|---|---|---|
| HashMap | 1,535ms | 158ms | 651,465 ops/s | 6,329,113 ops/s | 311.31 MB | ❌ |
| FastUtil | 600ms | 32ms | 1,666,666 ops/s | 31,250,000 ops/s | 275.69 MB | ❌ |
| Caffeine | 1,107ms | 2,298ms | 903,342 ops/s | 435,161 ops/s | 351.69 MB | ❌ |
| RogueMap OffHeap | 1,924ms | 854ms | 519,750 ops/s | 1,170,960 ops/s | 47.81 MB | ❌ |
| RogueMap Mmap 持久化 | 1,057ms | 642ms | 946,073 ops/s | 1,557,632 ops/s | 47.63 MB | ✅ |
| RogueMap Mmap 临时 | 1,113ms | 704ms | 898,472 ops/s | 1,420,454 ops/s | 47.66 MB | ❌ |
| MapDB OffHeap | 8,259ms | 8,451ms | 121,080 ops/s | 118,329 ops/s | 11.14 MB | ❌ |
| MapDB 临时文件 | 9,002ms | 7,717ms | 111,086 ops/s | 129,584 ops/s | 7.71 MB | ❌ |
| MapDB 持久化 | 8,117ms | 7,709ms | 123,198 ops/s | 129,718 ops/s | 7.71 MB | ✅ |
| Redis (本地) | ~1500ms | ~1000ms | ~666,667 ops/s | ~1,000,000 ops/s | 0 MB (外部服务) | ✅ |
| Redis (网络) | ~15000ms | ~10000ms | ~66,667 ops/s | ~100,000 ops/s | 0 MB (外部服务) | ✅ |
性能可视化
📊 写入性能排行 (越低越好)
| 排名 | 方案 | 耗时 | 性能评级 | 相对基准 |
|---|---|---|---|---|
| 🥇 | FastUtil | 600ms | ⭐⭐⭐⭐⭐ | 1.0x (最快) |
| 🥈 | RogueMap(持久化模式) | 1,057ms | ⭐⭐⭐⭐ | 1.8x |
| 🥉 | Caffeine | 1,107ms | ⭐⭐⭐⭐ | 1.8x |
| 4 | RogueMap(临时文件模式) | 1,113ms | ⭐⭐⭐⭐ | 1.9x |
| 5 | Redis(本地) | 1,500ms | ⭐⭐⭐ | 2.5x |
| 6 | HashMap | 1,535ms | ⭐⭐⭐ | 2.6x |
| 7 | RogueMap(堆外内存模式) | 1,924ms | ⭐⭐ | 3.2x |
| 8 | MapDB(持久化模式) | 8,117ms | ⭐ | 13.5x |
| 9 | MapDB(堆外内存模式) | 8,259ms | ⭐ | 13.8x |
| 10 | MapDB(临时文件模式) | 9,002ms | ⭐ | 15.0x |
| 11 | Redis(网络) | 15,000ms | ⭐ | 25.0x |
📊 读取性能排行 (越低越好)
| 排名 | 方案 | 耗时 | 性能评级 | 相对基准 |
|---|---|---|---|---|
| 🥇 | FastUtil | 32ms | ⭐⭐⭐⭐⭐ | 1.0x (最快) |
| 🥈 | HashMap | 158ms | ⭐⭐⭐⭐⭐ | 4.9x |
| 🥉 | RogueMap(持久化模式) | 642ms | ⭐⭐⭐ | 20.1x |
| 4 | RogueMap(临时文件模式) | 704ms | ⭐⭐ | 22.0x |
| 5 | RogueMap(堆外内存模式) | 854ms | ⭐⭐ | 26.7x |
| 6 | Redis(本地) | 1,000ms | ⭐⭐ | 31.3x |
| 7 | Caffeine | 2,298ms | ⭐ | 71.8x |
| 8 | MapDB(持久化模式) | 7,709ms | ⭐ | 240.9x |
| 9 | MapDB(临时文件模式) | 7,717ms | ⭐ | 241.2x |
| 10 | MapDB(堆外内存模式) | 8,451ms | ⭐ | 264.1x |
| 11 | Redis(网络) | 10,000ms | ⭐ | 312.5x |
💾 堆内存占用排行 (越低越好)
| 排名 | 方案 | 内存占用 | 性能评级 | 相对基准 |
|---|---|---|---|---|
| 🥇 | MapDB(临时文件模式) | 7.71 MB | ⭐⭐⭐⭐⭐ | 1.0x (最优) |
| 🥇 | MapDB(持久化模式) | 7.71 MB | ⭐⭐⭐⭐⭐ | 1.0x |
| 🥈 | MapDB(堆外内存模式) | 11.14 MB | ⭐⭐⭐⭐⭐ | 1.4x |
| 🥉 | RogueMap(持久化模式) | 47.63 MB | ⭐⭐⭐⭐⭐ | 6.2x |
| 4 | RogueMap(临时文件模式) | 47.66 MB | ⭐⭐⭐⭐⭐ | 6.2x |
| 5 | RogueMap(堆外内存模式) | 47.81 MB | ⭐⭐⭐⭐⭐ | 6.2x |
| 6 | FastUtil | 275.69 MB | ⭐⭐ | 35.8x |
| 7 | HashMap | 311.31 MB | ⭐⭐ | 40.4x |
| 8 | Caffeine | 351.69 MB | ⭐ | 45.6x |
💡 关键发现
- 持久化方案最快: RogueMap(持久化模式) 在所有支持持久化的方案中性能最优
- 写入: 1,057ms,比 HashMap(1,535ms) 快 31%,比 MapDB(8,117ms) 快 7.7 倍
- 读取: 642ms (155万 ops/s),比 MapDB(7,709ms) 快 12 倍,比 Redis 网络(10,000ms) 快 15.6 倍
- 内存占用大幅优化: RogueMap(47.63 MB) 比 HashMap(311.31 MB) 节省 84.7% 堆内存
- 综合性价比最高: 在持久化 + 性能 + 内存三方面取得最佳平衡
深度分析
RogueMap 的核心优势
1. 堆内存占用减少 84.7%
对比 HashMap:
- HashMap: 311.31 MB
- RogueMap: 47.63 MB
- 节省: 263.68 MB(84.7%)
意义:
- 大幅降低 GC 压力,减少应用卡顿
- 支持更大数据量(6.5 倍以上)
- 避免 OOM 风险
2. 写入性能提升 1.45 倍
对比 HashMap:
- HashMap: 1,535ms (651,465 ops/s)
- RogueMap Mmap: 1,057ms (946,073 ops/s)
- 提升: 1.45 倍
原因:
- 只写索引,不写数据(延迟序列化)
- mmap 页缓存优化
- 顺序写入优化
3. 百万级读取吞吐
RogueMap Mmap 持久化:
- 读取时间: 642ms
- 读吞吐量: 1,557,632 ops/s(155 万 ops/s)
- 单次读取延迟: 约 0.64 μs
对比:
- 比 HashMap 慢约 4 倍(因为涉及反序列化)
- 但 155 万 ops/s 对于 2C4G 机器已经非常优秀
- 比 Redis(网络)快 15.6 倍(Redis 网络: 100,000 ops/s)
- 比 Redis(本地)快 1.56 倍(Redis 本地: 1,000,000 ops/s)
- 比 MapDB 快 12.0 倍(MapDB 平均: 129,718 ops/s)
4. 同类持久化方案中性能最优
持久化方案对比:
| 方案 | 持久化 | 写吞吐量 | 读吞吐量 | 性能综合 |
|---|---|---|---|---|
| HashMap | ❌ | 651,465 | 6,329,113 | 纯内存,不支持持久化 |
| FastUtil | ❌ | 1,666,666 | 31,250,000 | 纯内存,不支持持久化 |
| Caffeine | ❌ | 903,342 | 435,161 | 纯内存,不支持持久化 |
| RogueMap Mmap | ✅ | 946,073 | 1,557,632 | 持久化方案中最快 |
| MapDB 持久化 | ✅ | 123,198 | 129,718 | RogueMap 比它快 7.7 倍写入,12.0 倍读取 |
| Redis (本地) | ✅ | ~666,667 | ~1,000,000 | 外部服务,需网络通信 |
| Redis (网络) | ✅ | ~66,667 | ~100,000 | 网络开销大 |
关键发现:
- RogueMap 是唯一同时满足高性能 + 持久化 + 嵌入式的解决方案
- 比 MapDB 写入快 7.7 倍,读取快 12.0 倍
- 比 Redis 本地调用略快,且无需外部服务