开源竞品全景:Memcached、Aerospike、Dragonfly、Valkey、KeyDB
第二章:开源竞品全景:Memcached、Aerospike、Dragonfly、Valkey、KeyDB
2.1 功能对比矩阵
在深入每个竞品之前,先用一张完整的对比表建立宏观认知:
| 维度 | Redis 7.2 | Memcached 1.6 | Aerospike 6.x | Dragonfly 1.x | Valkey 7.2 | KeyDB 6.x |
|---|---|---|---|---|---|---|
| 数据结构 | 10+ 种 | 纯 KV | KV+List+Map | Redis 兼容 | Redis 兼容 | Redis 兼容 |
| 持久化 | AOF/RDB | 无 | 原生 SSD | 有(快照) | AOF/RDB | AOF/RDB |
| 集群 | Cluster(哈希槽) | 无(客户端分片) | 原生集群 | 原生多主 | Cluster | 多主复制 |
| 线程模型 | 单线程命令+多线程I/O | 多线程 | 多线程/多核 | 每核一线程 | 单线程+I/O多线程 | 多线程 |
| 协议 | RESP2/RESP3 | Memcached 文本/二进制 | 私有协议 | RESP(兼容) | RESP2/RESP3 | RESP2 |
| 最大容量 | 内存上限 | 内存上限 | SSD(TB级) | 内存上限 | 内存上限 | 内存上限 |
| 许可证 | RSALv2+SSPL | BSD | Apache 2.0 | BSL(源码延迟开放) | BSD | BSD |
| 生态成熟度 | 极高 | 高 | 中等 | 低 | 增长中 | 低 |
| 事务支持 | MULTI/Lua | 无 | Lua | MULTI/Lua | MULTI/Lua | MULTI/Lua |
| Pub/Sub | 是 | 否 | 否 | 是 | 是 | 是 |
| Stream | 是 | 否 | 否 | 是(兼容) | 是 | 是 |
2.2 Memcached:简单即美德
2.2.1 架构设计
Memcached 是 Brad Fitzpatrick 2003 年为 LiveJournal 开发的,其设计哲学极其简单:一个多线程的内存哈希表,仅支持 GET/SET/DELETE/CAS 操作。
内部使用 slab allocator 管理内存,将内存划分为固定大小的 chunk 集合(slab class):
Slab Class Chunk Size Total Slabs Per-Slab Items
1 96 bytes 1048576 10922
2 120 bytes 1048576 8738
3 152 bytes 1048576 6898
...
42 1 MB 1048576 1
43 Max(1.25MB) 1048576 1
每个 slab class 有独立的空闲列表,分配时从对应 class 的空闲列表取出,释放时归还。优点:无碎片。缺点:固定 chunk 大小导致内存浪费(存储 65 字节的值需要 120 字节的 chunk,浪费 55 字节)。
2.2.2 多线程模型
Memcached 使用 libevent 的多线程模型:
Main Thread (监听连接)
│
├──→ Worker Thread 0 (处理连接 0, 4, 8...)
├──→ Worker Thread 1 (处理连接 1, 5, 9...)
├──→ Worker Thread 2 (处理连接 2, 6, 10...)
└──→ Worker Thread 3 (处理连接 3, 7, 11...)
每个 Worker Thread 有自己的 libevent 实例,处理分配给它的连接。当多个线程同时访问哈希表时,需要全局锁(一把大锁保护整个 hash table)或分段锁(每个 hash bucket 一把锁)。
slab allocator 的全局锁是 Memcached 多线程模型的主要瓶颈。在 32-core 机器上,吞吐量提升是亚线性的,大约只有 8-10x(而非 32x)。
2.2.3 适用场景与局限
适用:简单 KV 缓存,数据无需持久化,追求最低延迟,不需要复杂数据结构。
局限:
- 无持久化(重启数据全丢)
- 无主从复制(单点故障)
- 无分布式支持(客户端负责一致性哈希)
- 无复杂数据结构(List/Set/Hash 都不支持)
- Value 最大 1MB
在 Redis 出现后,Memcached 的新项目占有率持续下滑。但对于纯缓存场景(数据可重建、不需要持久化),Memcached 依然是有效的选择,其多线程模型在超高并发下可能比 Redis 单线程更有优势。
2.3 Aerospike:突破内存边界
2.3.1 混合内存架构(HMA)
Aerospike 解决了 Redis 最根本的问题:内存容量限制。其核心创新是混合内存架构:
┌─────────────────────────────────────────────────────────┐
│ Aerospike Node │
│ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ DRAM Index │ │ SSD (Device Layer) │ │
│ │ │ │ │ │
│ │ Key Hash → Ptr │────→│ Actual Record Data │ │
│ │ 64 bytes/record │ │ Direct Block I/O │ │
│ │ │ │ (Bypass OS Page Cache) │ │
│ └─────────────────┘ └──────────────────────────┘ │
│ │
│ 内存开销:64B × 记录数 数据容量:SSD 总容量 │
└─────────────────────────────────────────────────────────┘
关键技术细节:
每条记录在 DRAM 中只存 64 字节的索引:
/* 简化的 Aerospike 主索引结构 */
struct as_index {
uint8_t key_hash[20]; // RIPEMD-160 哈希
uint8_t set_id[2]; // set 编号
uint64_t rblock_id; // SSD 上的 record block ID
uint16_t n_rblocks; // 占用的 block 数量
uint32_t generation; // 版本号(CAS 使用)
uint32_t void_time; // TTL 过期时间
uint8_t replication_state; // 副本状态
// ... 共 64 字节(经过 bit packing)
};
绕过文件系统:Aerospike 直接对 SSD 设备做原始块读写(O_DIRECT),跳过操作系统页面缓存。原因:页面缓存按 4KB 页管理数据,对随机小记录(< 1KB)效率低;O_DIRECT 允许 512-byte 对齐的直接 I/O,更适合 SSD 的物理访问模式。
实测数据:在 NVMe SSD 上,Aerospike 的随机读延迟约 0.5-1ms,接近 DRAM 访问延迟的 10-20x,但远低于旋转磁盘的 5-10ms。
2.3.2 Smart Client
Aerospike 的客户端库(Smart Client)包含集群拓扑感知能力:
传统代理架构:
客户端 → Proxy → 数据节点
Aerospike Smart Client:
客户端 → 直接路由 → 正确的数据节点(无代理层)
客户端在启动时获取集群分区映射,将记录哈希值直接映射到对应节点。这消除了代理层的单点故障和延迟开销(通常省去 0.1-0.5ms)。
2.3.3 强一致性 CP 模式
Aerospike 支持两种一致性模式:
Availability 模式(AP):类似 Redis,异步复制,高可用,可能读到旧数据。
Strong Consistency 模式(CP):基于写 quorum(类 Paxos):
写操作流程:
1. 客户端发送写请求到主节点
2. 主节点将记录写入本地 SSD
3. 主节点并发发送复制请求到所有副本节点
4. 等待 (RF/2 + 1) 个节点确认(RF=Replication Factor)
5. 主节点返回 ACK 给客户端
RF=3 时,需要 2 个节点确认(容忍 1 节点故障)。写延迟高于 AP 模式,但保证不丢数据。
2.3.4 适用场景与 Redis 对比
| 场景 | 选 Aerospike | 选 Redis |
|---|---|---|
| 数据量 >> 内存 | ✓ | ✗ |
| 广告竞价(RTB)用户画像 | ✓ | ✗ |
| 简单 KV,数据量在内存内 | ✗ | ✓ |
| 复杂数据结构(List/Stream) | ✗ | ✓ |
| 需要 Pub/Sub / 消息队列 | ✗ | ✓ |
| 毫秒以下延迟 | ✗(SSD 读 0.5ms+) | ✓(< 0.1ms) |
典型案例:某广告平台存储 20 亿条用户画像,每条记录约 500 字节,总数据量约 1TB。用 Redis 需要 1TB 内存(约 $20,000/月云费),用 Aerospike 只需 128GB 内存 + 2TB NVMe SSD(约 $3,000/月),成本差 6-7 倍。
2.4 Dragonfly:重新设计 Redis
2.4.1 shared-nothing 架构
Dragonfly 于 2022 年公开,声称性能是 Redis 的 25 倍。其核心架构是 shared-nothing:
CPU Core 0 CPU Core 1 CPU Core 2 CPU Core 3
│ │ │ │
Thread 0 Thread 1 Thread 2 Thread 3
│ │ │ │
Shard 0 Shard 1 Shard 2 Shard 3
(key space (key space (key space (key space
partition 0) partition 1) partition 2) partition 3)
每个线程独占一部分 key 空间(通过 key hash 确定归属 shard)。线程间无需竞争锁,因为每个 key 只属于一个 shard。跨 shard 操作(如 MGET 涉及多个 shard 的 key)通过内部消息传递协调。
这与 Redis 的单线程命令处理形成鲜明对比:Dragonfly 的吞吐量随 CPU 核心数线性扩展。
2.4.2 dashtable:无锁哈希表
Dragonfly 使用自研的 dashtable(dash = dynamic array of segments with hash)替代传统哈希表:
传统哈希表的问题:resize 时需要全量 rehash,期间需要锁定整个表。Redis 通过渐进式 rehash(每次操作时搬移少量桶)绕过了这个问题,但仍需要在旧表和新表之间维护状态。
dashtable 的设计:
- 将哈希空间分为固定数量的 segment
- 每个 segment 独立扩容,不影响其他 segment
- 查找:计算 key hash → 定位 segment → 在 segment 内线性探测
- 扩容:仅扩容当前 segment,其他 segment 继续服务
2.4.3 性能数据与局限
官方 benchmark(AWS c6gn.12xlarge,48 vCPU,192GB RAM):
Redis 7.0(单实例): ~800,000 SET/s
Dragonfly 1.0(单实例):~20,000,000 SET/s(25x)
注意:这个对比有前提条件——Redis 是单核利用率,Dragonfly 利用了全部 48 vCPU。与 Redis Cluster(48 节点)相比,差距缩小到 2-3x。
局限:
- 源码闭源商业化:Dragonfly 使用 BSL(Business Source License)。源码公开,但商业使用需付费或等待 4 年后转 Apache 2.0。
- 生态不成熟:社区规模远小于 Redis,生产故障案例少,踩坑经验缺乏。
- 部分兼容性问题:声称 Redis 协议完全兼容,但边缘 case(如 Lua 脚本复杂操作、某些 RESP3 特性)存在已知不兼容。
- Cluster 支持有限:Dragonfly 单实例吞吐量高,但分布式模式下的行为与 Redis Cluster 有差异。
2.5 Valkey:开源社区的分叉选择
2.5.1 许可证风波
2024 年 3 月 20 日,Redis Inc. 宣布将 Redis 的开源许可证从 BSD-3 改为双许可证:
- RSALv2(Redis Source Available License v2):允许查看和修改源码,但禁止将 Redis 作为数据库服务提供给第三方(即云厂商无法再以 Redis 名义销售托管服务)
- SSPLv1(Server Side Public License v1):MongoDB 发明的许可证,要求提供同等服务的必须开源整个服务栈(AWS/Google 不可接受)
2024 年 3 月 21 日,Linux Foundation 宣布接管 Redis 7.2.4 的 BSD fork,命名为 Valkey。
2.5.2 Valkey 的发展现状
2024-03-21 Linux Foundation 宣布接管
2024-03-27 AWS、Google、Oracle、Alibaba、Ericsson 宣布加入
2024-04-16 Valkey 7.2.5 发布(首个正式版本)
2024-06-11 Valkey 8.0.0-rc1 发布,开始引入多线程优化
2024-10-01 AWS ElastiCache 默认引擎切换为 Valkey
Valkey 8.0 的重点改进:
- I/O 线程多线程化:命令执行仍单线程,但网络 I/O 读写支持多线程(类似 Redis 6.0 的 io-threads)
- Dual-channel replication:主从复制优化,RDB 传输和 AOF 增量使用独立连接
- Slot migration 性能提升:Cluster 水平扩缩容速度提升 60%
2.5.3 Redis vs Valkey 现在该如何选
对于新项目:
- 自建部署:Valkey 是更明智的选择(BSD 许可证,长期社区支持,云厂商背书)
- 云托管:AWS 上选 ElastiCache for Valkey 或 MemoryDB for Valkey;阿里云 Tair 支持 Valkey 兼容协议
对于存量 Redis 项目:Valkey 与 Redis 7.2 协议完全兼容,迁移零改动。
2.6 KeyDB:多主多写架构
KeyDB 是 Snap(Snapchat 母公司)2019 年开源的 Redis fork(2022 年被 Snap 收购后改为 EX Inc.)。
2.6.1 核心差异:per-thread event loop
Redis(以及 Valkey)的网络 I/O 线程只负责读写,命令执行仍在主线程。KeyDB 将整个事件循环(包括命令解析、执行)都多线程化:
KeyDB 线程模型:
Thread 0: Event Loop 0 → 处理连接 [0..N/K] 的完整生命周期
Thread 1: Event Loop 1 → 处理连接 [N/K..2N/K]
Thread 2: Event Loop 2 → 处理连接 [2N/K..3N/K]
...
线程间通过 MVCC(多版本并发控制)机制协调对共享数据结构的访问。
2.6.2 多主多写(Active-Active Replication)
KeyDB 支持多个主节点同时接受写入,节点间互相同步,解决了 Redis 单主写入的瓶颈:
写入 写入
Client ──────→ Node A ←──────── Client
↕(双向同步)
Node B
写冲突通过 last-write-wins(LWW)或向量时钟解决。适合写多读多、需要多机房双写的场景。
KeyDB 的实际处境:KeyDB 的商业化前景不明朗,社区活跃度低于 Valkey。对于新项目,Valkey 是更稳妥的选择。
2.7 选型决策树
需要键值存储?
├── 数据量 >> 可用内存(> 70%)?
│ ├── 是 → Aerospike(HMA 混合存储)
│ └── 否 → 继续
│
├── 需要复杂数据结构(List/Stream/ZSet)?
│ ├── 是 → Redis/Valkey(生态最丰富)
│ └── 否 → 继续
│
├── 纯缓存,无需持久化,高并发?
│ ├── 是 → Memcached(多线程,简单高效)
│ └── 否 → 继续
│
├── 要求最高吞吐量,单节点?
│ ├── 是,可接受 BSL 许可 → Dragonfly
│ └── 否 → 继续
│
├── 需要多主多写?
│ ├── 是 → KeyDB 或 Redis Enterprise(CRDT)
│ └── 否 → 继续
│
├── 云托管优先?
│ ├── AWS → ElastiCache for Valkey / MemoryDB for Valkey
│ ├── 阿里云 → Tair(增强版,特殊场景)
│ └── 其他 → 各云厂商的 Redis/Valkey 托管服务
│
└── 默认选择:Valkey(最佳开源选择,BSD 许可证,社区活跃)
2.8 小结
Redis 的竞品并非在全面超越 Redis,而是在特定维度上做出不同权衡:
- Memcached:简单、多线程、无持久化,适合纯缓存
- Aerospike:突破内存瓶颈,TB 级数据场景
- Dragonfly:极致单节点吞吐量,但生态不成熟
- Valkey:Redis 的真正开源接班人
- KeyDB:多主写入场景的一个选项
许可证变更事件深刻影响了整个行业:云厂商正在将默认引擎切换到 Valkey,未来 2-3 年 Valkey 可能成为新项目的首选。对于存量 Redis 项目,迁移成本几乎为零。
下一章将深入云厂商的托管服务:ElastiCache、MemoryDB 与阿里云 Tair 的技术细节与选型决策。