Valkey 深度拆解:当 Redis 的守护者变成掠夺者——从 BSD 分叉到 2000 节点 10 亿 RPS 的开源逆袭之路
引言:一场许可证风暴引发的开源地震
2024 年 3 月,Redis Labs 将这个统治内存数据库市场十五年的项目许可证从 BSD-3-Clause 变更为 RSALv2 + SSPLv1 双重限制性许可。这一决定的核心矛盾在于:RSALv2 明确禁止云厂商将 Redis 作为托管服务提供给第三方,直接冲击 AWS、Google Cloud、Oracle 等巨头的数据库即服务业务;SSPLv1 则要求提供"程序即服务"时公开整个服务端代码。
对于依赖 Redis 的企业和云服务商而言,这意味着法律风险和供应商锁定的双重威胁。仅仅一个月后,Linux 基金会联合 AWS、Google Cloud、Oracle、Snap、Ericsson 等巨头,从 Redis 7.2.4(最后一个 BSD 版本)分叉出 Valkey。其核心使命清晰而坚定:
"保留一个社区所有、采用宽松 Apache/BSD 许可的真正开源替代方案,杜绝任何单一厂商单方面改变规则的可能。"
短短两年,Valkey GitHub Stars 突破 25.4k,Fork 数达 1.1k。2025 年底调查显示,42% 的用户已迁移或计划迁移到 Valkey。2025 年 12 月,Valkey 9.0 正式发布,支持 2000 节点集群、每秒超 10 亿次请求处理能力。这不是一个简单的 fork——这是一场开源世界对商业化的集体反击。
第一章:架构剖析——在兼容中超越
1.1 单线程事件循环的继承与突破
Valkey 完全继承 Redis 的单线程事件循环模型,确保命令执行的原子性和无锁优势。所有客户端命令严格按序执行,不需要加锁,不需要考虑并发竞态条件。这是 Redis 十五年稳定运行的基石,Valkey 毫不犹豫地保留了这一核心设计。
但在此基础上,Valkey 8.0 进行了三项革命性的架构升级。
1.2 异步 I/O 线程重写:从 20 万到 120 万 QPS 的飞跃
Redis 6.0 引入了多线程 I/O 特性,将网络数据的读写和协议解析从主线程卸载到 I/O 线程。但 Redis 6.0 的多线程 I/O 存在根本性缺陷:
主线程阻塞等待:主线程会阻塞等待所有 I/O 线程完成读写操作,最慢的 I/O 线程成为性能瓶颈。
任务分配不均:需要先将所有可读客户端加入队列,再通过 RR 算法分配给 I/O 线程。在主线程遍历客户端期间,I/O 线程全部空闲。
卸载不彻底:I/O 线程仅执行读取解析和写入操作,主线程仍然承担事件轮询(epoll_wait)、对象内存释放、命令查找等大量工作。
Valkey 8.0 彻底重写了这一层,核心改进包括:
无锁环形缓冲区:每个 I/O 线程拥有一个静态、无锁、固定大小(2048)的环形缓冲区作为任务队列。主线程发送任务后立即返回,I/O 线程异步并行执行。
事件轮询卸载:epoll_wait 等昂贵的套接字轮询系统调用从主线程卸载到 I/O 线程。任意时刻最多只有一个线程执行 epoll_wait,避免竞争条件。
命令查找卸载:I/O 线程在解析命令时同步完成命令字典查找,将结果存储在客户端字段中,主线程执行命令时直接使用。
对象释放卸载:命令参数的内存释放分配给执行该参数解析的同一个 I/O 线程,通过客户端 ID 标识,保持良好的缓存局部性。
动态线程调度:根据实时可读/写事件数量,动态调整活跃 I/O 线程数量(最大 15 个)。减少线程时通过加锁使其暂停轮询,增加时释放锁即可,避免不必要的空轮询。
性能数据(AWS c7g.4xlarge,16 vCPU):
| 指标 | Redis 6.0 多线程 IO | Valkey 8.0 异步 IO | 提升幅度 |
|---|---|---|---|
| 吞吐量 | ~200K RPS | 1.19M RPS | +495% |
| 平均延迟 | ~2ms | 0.542ms | -73% |
| P99 延迟 | ~5ms | 0.927ms | -81% |
1.3 数据预取(Prefetch)与内存访问分摊(MAA)
异步 I/O 线程将并行度拉满后,分析发现主线程大部分时间花销在访问内存查找 key。Valkey 的字典是链式哈希实现,遍历哈希链表时每次访问 dictEntry 结构体、键指针或值对象,都可能需要昂贵的外部内存访问。
数据预取(Prefetching):现代 CPU 运算速度远超内存速度,当 CPU 需要从内存读取数据时可能需要等待,导致性能瓶颈。Valkey 8.0 在执行命令之前,通过 __builtin_prefetch() 对所有即将操作的命令参数、key 及对应的 value 进行批量预取到 L1 高速缓存,减少内存访问延迟。
内存访问分摊(MAA):这是一种通过降低内存访问延迟影响来优化动态数据结构性能的技术。核心思想是:批量执行操作比单独执行每个操作更高效。Valkey 8.0 每次创建最多包含 16 条命令的批次,循环遍历每个 key 交错执行预取步骤——先预取 key A 的 bucket,不等结果,立即预取 key B 的 bucket,再预取 key C 的 bucket。当所有 key 完成第一步预取后,开始第二步时第一步的数据已经到达 L1 缓存。
通过交错执行所有 key 的预取动作,分摊内存访问时间,结合批量处理,单节点 Valkey 访问请求可达每秒 120 万次。
1.4 CPU 缓存友好的字典结构
Valkey 8.0 重新实现了核心哈希表,将键直接嵌入字典条目(dictEntry),每个键减少 8 字节开销,整体内存效率提升约 20%。这对于海量小 key 场景(如会话存储、设备状态)意义重大——同样的硬件可以存储更多数据。
1.5 双通道复制(Dual Channel Replication)
Valkey 8.0 引入双通道复制机制:
- 全量同步期间同时流式传输 RDB 快照和复制积压日志
- 使用独立连接进行 RDB 传输,释放主进程处理客户端查询
- 大幅缩短主从切换时的窗口期
这意味着在主从同步期间,主节点依然可以正常响应客户端请求,不会出现同步期间服务降级的问题。
第二章:Valkey 9.0——从缓存到通用数据库的进化
2.1 原子级槽位迁移
Valkey 9.0 最重要的改进是原子级槽位迁移(Atomic Slot Migration)。此前的逐步迁移模式可能在传输过程中改变槽位归属,导致过渡性错误。新版的原子迁移方式确保键路由的一致性与可预测的交接。
在 Valkey 中,所有键被映射为 16,384 个槽位之一,每个节点负责一个或多个槽位。Valkey 9.0 中迁移不再是按键迁移,而是一次迁移整个槽位,并通过 AOF 格式进行原子移动。
这从根本上改变了容量规划和运维风险管理方式——扩容将变得可预测,而不再是痛苦的过程。
2.2 哈希字段过期(Hash Field Expiration)
此前,Valkey 的哈希结构只能整体过期,若需字段级过期,用户只能拆分为多个键。Valkey 9.0 允许哈希中的每个字段独立过期,采用主动过期机制清理已过期的哈希字段。
基准测试表明,字段级过期可以在不牺牲内存效率或延迟的情况下加入 Valkey。额外内存开销保持可控,指令吞吐未受影响。
典型应用场景:
# 用户会话管理:不同字段不同过期时间
client.hset("session:abc123", mapping={
"user_id": "10086",
"token": "xyz789",
"last_activity": "1690000000",
"cart_items": "[1,2,3]"
})
# token 30 分钟过期,cart 7 天过期
client.hexpire("session:abc123", 1800, "token")
client.hexpire("session:abc123", 604800, "cart_items")
2.3 集群模式多数据库支持
Redis 以及 Valkey 8.x 中,集群模式只能使用单一数据库(db0)。Valkey 9.0 取消了这一限制,引入对编号数据库的完整集群支持。
编号数据库是一种命名空间机制,最直接的使用场景是需要逻辑上隔离数据,同时能够接受资源共享带来的影响。例如,将不同客户的数据分隔开,或在资源不成问题的情况下整合多个应用到同一个集群中。
2.4 2000 节点集群与 10 亿 RPS
Valkey 9.0 在集群规模上实现了突破,测试配置支持 2000 节点(1000 主 + 1000 副本),达到 10 亿 RPS 的聚合吞吐量。关键优化包括:
- 多主节点故障处理:引入排名机制防止投票冲突,50% 主节点故障时仍能自动恢复
- 连接节流:防止大规模故障时的重连风暴
- Gossip 优化:Radix Tree 按秒分组故障报告,减少冗余处理
- 轻量化 Pub/Sub:头部从 ~2KB 降至 ~30 字节
第三章:RDMA 支持——网络层的降维打击
Valkey 在 2024 年 7 月开始实验性支持 RDMA(远程直接内存访问)作为传输层,这是 Redis 目前尚未提供的原生能力。
技术原理:绕过内核网络栈,直接内存到内存传输,零拷贝减少 CPU 参与。适合低延迟、高吞吐的 HPC/AI 场景。
性能表现(1KB KV 场景,Intel Xeon Platinum + Mellanox ConnectX-5):
| 命令 | TCP QPS | RDMA QPS | 提升 | 延迟降低 |
|---|---|---|---|---|
| PING | 214K | 512K | 2.4x | 56μs vs 132μs |
| SET | 161K | 267K | 1.7x | 109μs vs 177μs |
| GET | 179K | 347K | 1.9x | 83μs vs 157μs |
2025 年 5 月,libvalkey 0.1.0 正式发布,原生集成 RDMA 支持,valkey-cli 和 valkey-benchmark 均已支持 --rdma 参数。
第四章:Valkey-Search——向量搜索与 AI 支撑
4.1 架构定位
Valkey 官方推出 Valkey-Search 模块(BSD 许可),作为 Redis Search 的兼容替代,专注于向量搜索场景:
[文本/图像] → [Embedding 模型] → [Valkey-Search 向量索引] → [KNN/ANN 查询] → [Top-K 结果]
核心特性:
- HNSW ANN 算法:时间复杂度 O(log N),支持 L2、内积、余弦相似度
- 混合查询:向量相似度 + 数值/标签过滤(AND/OR/NOT)
- 多线程查询:CPU 核数线性提升查询吞吐
- RDB 快照集成:索引定义和向量数据随快照持久化,避免重建
4.2 实战:语义搜索
-- 创建向量索引(768 维,余弦相似度)
FT.CREATE doc_idx ON HASH PREFIX 1 doc:
SCHEMA title TEXT
content VECTOR HNSW 6 DIM 768 DISTANCE_METRIC COSINE
category TAG
-- 添加文档(向量由外部模型生成)
HSET doc:1 title "Valkey 入门" content <768-dim-vector> category "database"
-- 向量搜索(找最相似的 5 条)
FT.SEARCH doc_idx "*=>[KNN 5 @content $vec]"
PARAMS 2 vec <query-vector>
RETURN 3 title category score
4.3 AI 场景支撑矩阵
| AI 场景 | Valkey 能力 | 实现方式 |
|---|---|---|
| 语义缓存 | Valkey-Search | 缓存 LLM 查询结果,命中时直接返回 |
| 对话历史 | Hash / Stream | HSET 存储上下文,TTL 自动过期 |
| 实时特征 | Sorted Set | 时间序列特征,ZADD 更新 |
| 向量检索 | Valkey-Search | HNSW 索引,毫秒级 Top-K |
| 模型结果缓存 | String + TTL | 缓存推理结果,避免重复计算 |
第五章:生产部署实战
5.1 编译优化
# 克隆源码
git clone https://github.com/valkey-io/valkey.git
cd valkey
# 高性能编译(生产推荐)
make BUILD_TLS=yes \
BUILD_RDMA=module \
CFLAGS="-DUSE_PROCESSOR_CLOCK -O3" \
MALLOC=jemalloc
# 安装并创建兼容符号链接
make install
# 自动生成 redis-server → valkey-server 等软链接,平滑迁移
5.2 关键配置调优
# valkey.conf 生产模板
# === 网络与 I/O ===
port 6379
io-threads 8 # 启用多线程 I/O,建议等于 CPU 核数
io-threads-do-reads yes # 读操作也走 I/O 线程
tcp-keepalive 60
# === 内存管理 ===
maxmemory 8gb
maxmemory-policy allkeys-lru # 全量键 LRU 淘汰
maxmemory-samples 10
activedefrag yes # 自动碎片整理
# === 持久化 ===
appendonly yes
appendfsync everysec # 每秒刷盘,平衡性能与安全
no-appendfsync-on-rewrite yes # 重写时暂停 AOF 同步
save 900 1 # RDB:15 分钟至少 1 次变更则快照
save 300 10
save 60 10000
# === 集群 ===
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-require-full-coverage no
# === 慢查询监控 ===
slowlog-log-slower-than 10000 # 10ms 阈值
slowlog-max-len 128
# === 多可用区(云环境)===
availability-zone "cn-north-1a"
5.3 Docker Compose 快速部署
version: '3.8'
services:
valkey-master:
image: valkey/valkey:8-alpine
command: valkey-server --appendonly yes --requirepass secret
ports:
- "6379:6379"
valkey-replica:
image: valkey/valkey:8-alpine
command: valkey-server --replicaof valkey-master 6379 --masterauth secret
depends_on:
- valkey-master
sentinel-1:
image: valkey/valkey:8-alpine
command: valkey-sentinel /etc/sentinel.conf
volumes:
- ./sentinel.conf:/etc/sentinel.conf
5.4 集群创建
# 启动 6 个节点(3 主 3 从)
for port in 6379 6380 6381 6382 6383 6384; do
valkey-server --port $port --cluster-enabled yes \
--cluster-config-file nodes-$port.conf \
--appendonly yes --daemonize yes
done
# 组建集群
valkey-cli --cluster create \
127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 \
127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 \
--cluster-replicas 1
5.5 Java 集成:Spring Data Valkey
2026 年 4 月,Spring Data Valkey 正式发布,标志着 Valkey 在 Java 生态中获得"一等公民"地位。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-valkey</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.valkey</groupId>
<artifactId>valkey-java-client</artifactId>
<version>5.0.0</version>
</dependency>
@Configuration
public class ValkeyConfig {
@Bean
public ValkeyConnectionFactory valkeyConnectionFactory() {
ValkeyClusterConfiguration clusterConfig = new ValkeyClusterConfiguration(
Arrays.asList("node1:6379", "node2:6379", "node3:6379")
);
clusterConfig.setMaxRedirects(3);
ClientConfiguration clientConfig = ValkeyClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
return new LettuceValkeyConnectionFactory(clusterConfig, clientConfig);
}
@Bean
public ValkeyTemplate<String, Object> valkeyTemplate(
ValkeyConnectionFactory factory) {
ValkeyTemplate<String, Object> template = new ValkeyTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
业务层使用:
@Service
public class CacheService {
@Autowired
private StringValkeyTemplate valkeyTemplate;
// 缓存 + TTL
public void cacheUser(String userId, User user) {
valkeyTemplate.opsForValue().set(
"user:" + userId, user, Duration.ofMinutes(30)
);
}
// 分布式锁(Lua 保证原子性)
public boolean tryLock(String lockKey, String requestId, int expireSeconds) {
String lua = "if valkey.call('setnx', KEYS[1], ARGV[1]) == 1 then " +
"return valkey.call('expire', KEYS[1], ARGV[2]) " +
"else return 0 end";
Long result = valkeyTemplate.execute(
new DefaultValkeyScript<>(lua, Long.class),
Collections.singletonList(lockKey),
requestId, String.valueOf(expireSeconds)
);
return result != null && result == 1;
}
// 排行榜(Sorted Set)
public List<TypedTuple<String>> getTop10(String board) {
return valkeyTemplate.opsForZSet()
.reverseRangeWithScores(board, 0, 9);
}
}
5.6 Python 集成:valkey-py
from valkey import Valkey
from valkey.cluster import ValkeyCluster
from valkey.sentinel import Sentinel
# 单机/主从模式
client = Valkey(
host='localhost',
port=6379,
db=0,
decode_responses=True,
max_connections=50,
socket_keepalive=True
)
# 哨兵模式(高可用)
sentinel = Sentinel([
('sentinel1', 26379),
('sentinel2', 26379),
('sentinel3', 26379)
])
master = sentinel.master_for('mymaster', socket_timeout=0.5)
# 集群模式
startup_nodes = [
{"host": "192.168.1.10", "port": "6379"},
{"host": "192.168.1.11", "port": "6379"},
{"host": "192.168.1.12", "port": "6379"}
]
cluster = ValkeyCluster(
startup_nodes=startup_nodes,
decode_responses=True,
skip_full_coverage_check=True,
max_connections_per_node=20,
read_from_replicas=True
)
# 限流器
def rate_limit(user_id: str, max_requests: int = 100, window: int = 60):
key = f"rate:{user_id}"
pipe = cluster.pipeline()
pipe.incr(key)
pipe.expire(key, window)
current, _ = pipe.execute()
return current <= max_requests
# Stream 消息队列(消费组模式)
def consume_events(stream: str, group: str, consumer: str):
messages = cluster.xreadgroup(
group, consumer,
{stream: '>'},
count=10,
block=5000
)
for stream_name, msgs in messages:
for msg_id, fields in msgs:
process_event(fields)
cluster.xack(stream, group, msg_id)
5.7 监控指标清单
| 指标 | 命令 | 告警阈值 |
|---|---|---|
| 内存使用率 | INFO memory | > 85% |
| 主从复制延迟 | INFO replication | > 1s |
| 慢查询数量 | SLOWLOG LEN | > 100/min |
| 连接数 | INFO clients | > 80% maxclients |
| 集群节点状态 | CLUSTER NODES | 任何节点 fail |
| 每秒命令数 | INFO stats | 基线偏差 > 30% |
第六章:Valkey vs Redis——选型决策树
| 维度 | Valkey 8.x/9.0 | Redis 8.x | 差异分析 |
|---|---|---|---|
| 许可证 | BSD 3-Clause | RSALv2 + SSPL + AGPLv3 | 根本差异 |
| 核心性能 | 1.19M RPS(8 I/O 线程) | ~820K RPS | Valkey 领先 45% |
| 多线程 I/O | 异步 I/O 线程重写 | 改进版 I/O 线程 | Valkey 扩展性更优 |
| RDMA | 实验性支持 | 无原生支持 | Valkey 独有 |
| 集群规模 | 2000 节点测试通过 | 标准规模 | Valkey 扩展更强 |
| 多逻辑数据库 | 9.0 支持 | 不支持 | Valkey 独有 |
| Spring Data | 官方 Spring Data Valkey | Spring Data Redis | 平等地位 |
| 向量搜索 | Valkey-Search(BSD) | Redis Search(AGPL) | 许可证不同 |
| JSON/TimeSeries | 基础模块 | 核心集成 | Redis 更完整 |
| 语义缓存 | 需自行实现 | 原生支持 | Redis AI 生态更成熟 |
选型决策树:
开始
│
├─ 许可证敏感?(金融/上市公司/云厂商)
│ └─ 是 → Valkey(BSD 零风险)
│ └─ 否 → 继续评估
│
├─ 需要 Redis Stack 高级功能?(TimeSeries/JSON原生集成/语义缓存)
│ └─ 是 → Redis 8.x(功能更全)
│ └─ 否 → 继续评估
│
├─ 追求极致性能/大规模集群?
│ └─ 是 → Valkey(230% 吞吐提升,2000 节点)
│ └─ 否 → 均可
│
└─ 需要 RDMA/HPC 场景?
└─ 是 → Valkey(唯一选择)
└─ 否 → 均可
第七章:AI 时代的定位——从缓存到实时智能数据层
Valkey 在 AI 时代的角色正在从"缓存"进化为**"实时智能数据层"**:
- 特征存储:毫秒级读写用户实时行为特征,支撑在线推理
- 向量检索:Valkey-Search 提供低延迟语义搜索,替代专用向量数据库在简单场景的地位
- 语义缓存:缓存 LLM 查询结果,降低推理成本
- 流式处理:Stream 数据结构支撑实时事件管道,对接 ML 特征工程
社区路线图:
| 时间 | 方向 | 目标 |
|---|---|---|
| 2026 | 时间序列数据结构 | 原生支持 IoT/监控场景 |
| 2026+ | 持久化增强 | 从"缓存"进化为"一致性通用数据库" |
| 长期 | 硬件加速 | GPU/RDMA 深度集成,支撑 HPC/AI 训练 |
总结
Valkey 的崛起证明了一个开源真理:当守护者变成掠夺者,社区会创造新的守护者。
在 AI 时代,选择一个由社区共同拥有、性能持续突破、许可证永不变更的数据基础设施,是对技术栈长期安全最负责任的投资。如果你的应用当前使用 Redis 7.2 及以下版本,或对新项目的许可证合规性有顾虑,Valkey 是毫无争议的最佳选择。迁移成本趋近于零,性能收益立竿见影,法律风险彻底消除。
Valkey 8.0 的异步 I/O 线程重写将单节点吞吐从 20 万提升到 120 万 QPS,数据预取和内存访问分摊技术消除了内存瓶颈。Valkey 9.0 的原子级槽位迁移和 2000 节点集群支持,使其从"Redis 替代品"进化为"下一代分布式内存数据库"。RDMA 支持和 Valkey-Search 向量搜索,则为其在 HPC 和 AI 场景中开辟了新的战场。
这不是 Redis 的影子,这是开源社区自主进化的产物。当许可证不再安全,当性能不再满足需求,当架构不再适应场景——Valkey 用代码证明,最好的开源项目不是被创造出来的,而是被社区需要出来的。