Dragonfly:让内存数据库吃满多核的硬核设计
Dragonfly通过Shared-Nothing架构、VLL锁管理器和Dash哈希表等技术,实现25倍于Redis的吞吐量,兼容协议且内存效率极高,是Redis与Memcached的现代替代者。

Dragonfly:让内存数据库吃满多核的硬核设计
作为一个被 Redis 单线程模型“驯化”多年的老兵,我一度以为高并发缓存的极限就是加机器、分片、读写分离。直到我看到 Dragonfly 的 benchmark 数据——384万 QPS,是 Redis 的 25 倍。那一刻,我意识到:我们可能正站在一场缓存基础设施变革的前夜。
这不只是性能数字的堆砌,而是一次对旧时代架构的系统性重构。它没有选择在单线程模型上修修补补,而是直接掀桌子,用现代 C++ 和共享无(Shared-Nothing)架构,把内存数据库重新做了一遍。
架构设计:从单核独舞到多核共舞
Redis 的单线程模型曾是其稳定性的基石,但也成了它的天花板。哪怕你有 64 核 CPU,Redis 也只能用一个核心,其余 63 个只能干瞪眼。而 Dragonfly 的解法简单粗暴:每个 CPU 核心独立管理一个数据分片(shard),彼此完全隔离。
这种 Shared-Nothing 架构意味着:
- 每个 shard 有自己的线程、内存空间和数据结构
- 所有操作都在本地完成,无需跨线程加锁
- 扩展性直接与 CPU 核心数线性相关
你可以把它想象成从“一个窗口排队打饭”变成了“十个窗口同时开放”,而且每个窗口都有独立的厨师和食材库。这才是真正的并行处理。
整个请求路径如下:
客户端 -> 网络层(SO_REUSEPORT) -> Shard 路由 -> 本地操作 -> 返回结果
其中 SO_REUSEPORT 让多个进程/线程可以监听同一个端口,内核自动负载均衡到不同线程,避免了传统代理层的开销。
核心模块深挖:论文级技术落地生产
1. VLL 锁管理器:无锁实现多 key 原子操作
传统多线程数据库在执行 MGET 或事务时,必须协调多个 key 的锁,极易引发死锁或性能下降。而 Dragonfly 引入了来自论文《VLL: a lock manager redesign for main memory database systems》的 Versioned Lock Log (VLL) 技术。
它的核心思想是:
- 每个 key 的访问记录版本号和持有状态
- 多 key 操作前先预检所有 key 是否可获取
- 若冲突,则快速回滚并重试,而非阻塞等待
这使得像 MSET, DEL, 甚至未来支持的事务都能在无全局锁的情况下完成。虽然目前仍禁用 MULTI/EXEC,但底层机制已经就位。
2. Dash 哈希表:为内存数据库量身定制
Dragonfly 并未使用 std::unordered_map 或 Redis 自研的哈希表,而是采用了基于 Dash 改造的高性能哈希结构。Dash 本为持久内存设计,但 Dragonfly 团队将其改造为纯内存版本,带来了以下优势:
- 渐进式 rehash:避免一次性扩容导致的延迟毛刺
- 无状态迭代器(stateless scan):支持
SCAN命令无需保存游标状态 - 更好的缓存局部性:减少 cache miss
更重要的是,Dash 在高负载下仍能保持 O(1) 查找性能,而传统哈希表在冲突严重时会退化为链表遍历。
代码亮点赏析:优雅与性能并存
我们来看一段典型的启动配置代码,感受一下它的设计理念:
bash
## 使用 Docker 快速部署 Dragonfly 实例
docker run -p 6379:6379 dragonflydb/dragonfly
## 输出说明:
## -p 6379:6379 将容器内的 6379 端口映射到主机
## dragonflydb/dragonfly 是官方镜像,开箱即用
## 默认启用 Redis 兼容模式,无需额外配置
再看一个生产级启动命令,包含关键调优参数:
bash
./dragonfly-x86_64 \
--logtostderr \ # 日志输出到标准错误
--requirepass=securepassword \ # 启用密码认证
--cache_mode=true \ # 开启缓存优化模式(LRU逐出)
--maxmemory=12gb \ # 设置最大内存使用量
--port=6379 \ # 监听端口
--bind=localhost \ # 绑定地址
--dbfilename=dump.rdb \ # RDB 持久化文件名
--keys_output_limit=12288 # 限制 KEYS 命令返回数量,防 OOM
注意 --cache_mode=true 这个参数,它启用了 LRU-K 风格的淘汰策略,且内存开销极低——不像 Redis 需要额外存储 idle time。这是“零内存开销淘汰算法”的实际体现。
最后是一个高级特性配置,用于自动化运维:
ini
## 在配置文件中设置 cron 表达式,定时触发快照
snapshot_cron=* */2 * * *
## 解释:每两小时执行一次自动快照(分钟 小时 日 月 星期)
这个功能结合其 Fork-less 快照机制,真正实现了“高性能 + 高可用”的兼顾。传统 Redis 的 bgsave 会 fork 子进程,导致写时复制(Copy-on-Write)带来巨大内存压力;而 Dragonfly 通过引用计数和增量写日志,在不 fork 的情况下完成快照,内存几乎不增长。
性能与设计背后的权衡
Dragonfly 的性能提升并非没有代价。目前最明显的短板是 复制功能尚未完成(README 明确标注为 experimental)。这意味着你暂时无法构建主从集群,也无法实现故障转移。但这更像是阶段性取舍——先把单机性能做到极致,再解决分布式问题。
另一个值得注意的设计是:禁止某些危险命令,如 KEYS * 默认受限。这看似不“自由”,实则是为了防止误操作拖垮整个实例。毕竟在百万 QPS 的系统里,一次全量扫描足以引发雪崩。
适用场景与局限
适合谁用?
- 高并发缓存场景(如电商秒杀、推荐系统)
- 对尾延迟敏感的服务(P99.9 < 2.5ms)
- 已使用 Redis/Memcached 协议,希望无缝升级
- 拥有多核服务器资源但长期无法充分利用
不适合谁用?
- 需要强一致主从复制的生产环境(当前阶段)
- 重度依赖 Lua 脚本或复杂事务逻辑
- 社区支持要求高的企业(项目较新,生态待成熟)
如果你问我:“现在能不能上生产?”我的回答是:非核心链路可以试,核心链路等等再看。但它绝对值得你在测试环境中跑起来,亲自压测一番。
写给 Java 开发者的建议
如果你的应用使用 Jedis 或 Lettuce 连接 Redis,迁移成本几乎为零。只需要改一行配置:
java
// 原来的 Redis 地址
RedisClient.create("redis://localhost:6379");
// 现在指向 Dragonfly
RedisClient.create("redis://localhost:6379"); // 地址不变,协议兼容!
然后用 Gatling 或 JMH 写个压测脚本,对比同样硬件下的 QPS 和延迟分布。你会发现,原来那台跑满 100% CPU 的 Redis,只是在“假装努力”。
结语:这不是进化,是革命
Dragonfly 不是在 Redis 的基础上优化,而是在说:“我们重新思考一下这个问题。” 它把学术界的前沿成果(VLL、Dash)带进了生产环境,用 C++ 写出了兼具性能与安全的系统。
它提醒我们:有时候技术瓶颈不在业务逻辑,而在基础设施本身。当你还在为 Redis 的单线程头疼时,有人已经造好了火箭。
明年面试官如果问:“为什么 Dragonfly 比 Redis 快?” 别再说‘因为它用了多线程’——太浅了。你应该说:‘因为它用 Shared-Nothing 架构消除了锁竞争,用 VLL 实现无锁多 key 操作,用 Fork-less 快照降低内存开销……’
这才是硬核开发者应有的答案。