后Redis时代全面来临:Valkey 9与DragonflyDB架构深度对比、性能实测与生产迁移实战指南
前言:一场许可证引发的生态地震
2024年3月20日,Redis Ltd. 宣布将 Redis 7.4 及后续版本的许可证从 BSD-3-Clause 切换到双许可证(SSPLv1 + RSALv2),这一决定犹如在开源基础设施领域投下了一颗深水炸弹。SSPL(Server Side Public License)要求任何以 SaaS 形式提供 Redis 服务的厂商必须开源其整个服务栈——这实际上意味着 AWS ElastiCache、Azure Cache for Redis、Google Cloud Memorystore 等主流云服务都无法继续合法使用新版 Redis。
消息一出,Linux Foundation 在 48 小时内迅速响应,fork 了 Redis 7.2.4 的最后一个 BSD 版本,创建了 Valkey 项目。与此同时,一个已经默默开发两年的项目 DragonflyDB 突然从幕后走到聚光灯下,以其革命性的 shared-nothing 架构向 Redis 的单线程模型发起了正面挑战。
作为在生产环境中重度依赖 Redis 的开发者,你无法忽视这场变革。本文将从架构原理、核心特性、性能基准、代码实战、迁移策略五个维度,深度对比 Valkey 9 和 DragonflyDB 这两个后 Redis 时代的主角,帮助你在技术选型中做出明智决策。
第一章:Valkey 9 —— 保守派的激进进化
1.1 从 Redis 到 Valkey:不是简单换皮
很多人对 Valkey 的第一印象是"换了名字的 Redis",这既对也不对。对的部分是:Valkey 100% 兼容 Redis 的数据结构、协议和命令集,现有的 Redis 客户端库可以零修改直接连接 Valkey。不对的部分是:Valkey 在继承 Redis 衣钵的同时,正在走出一条完全不同的技术路线。
Valkey 的治理模式是典型的开源基金会模式。项目由 Linux Foundation 托管,技术委员会(Technical Steering Committee, TSC)由来自 AWS、Google、Oracle、Ericsson、Alibaba Cloud 等公司的核心贡献者组成。截至目前,Valkey 已有超过 200 位贡献者,代码仓库超过 60,000 次提交。
1.2 Valkey 9.1 核心特性深度解析
Valkey 9.1(2026年5月19日发布)是 Valkey 项目迄今为止最重要的版本。让我们逐一拆解其核心创新。
1.2.1 Multi-threaded I/O(多线程 I/O)
Valkey 9 引入了真正的多线程 I/O 模型,这是对 Redis 单线程模型的根本性突破。
// Valkey 9 多线程 I/O 架构(简化示意)
// 每个 I/O 线程独立处理客户端连接的读写
// 主线程仍负责命令执行(保持单线程语义)
struct IOThread {
int id;
pthread_t thread;
int pipe_read; // 从主线程接收任务
int pipe_write; // 向主线程返回结果
client **pending_clients;
int pending_count;
};
// 主线程分发读任务给 I/O 线程
void dispatchReadToIOThreads(void) {
int processed = 0;
listIter li;
listRewind(server.clients_pending_read, &li);
listNode *ln;
int target_thread = 0;
while ((ln = listNext(&li)) != NULL) {
client *c = listNodeValue(ln);
int tid = target_thread % server.io_threads_num;
IOThread *t = &server.io_threads[tid];
// 将客户端分配到对应线程
t->pending_clients[t->pending_count++] = c;
target_thread++;
processed++;
}
// 唤醒所有 I/O 线程
wakeIOThreads();
// 主线程自己也处理一部分
handlePendingReadsForMainThread();
}
在标准的 GET/SET 基准测试中,启用 8 个 I/O 线程后,Valkey 9 的吞吐量相比单线程模式提升了 2.5-3 倍。关键在于:Valkey 的多线程只作用于网络 I/O 层,命令执行仍然保持单线程,这完美地规避了并发数据一致性问题。
配置方法极其简单:
# valkey.conf
io-threads 8
io-threads-do-reads yes
1.2.2 Valkey Search(全文搜索与聚合引擎)
Valkey 9 内置了 Valkey Search 模块,这是一个革命性的扩展。它在 Redis 的 RediSearch 基础上进行了大幅增强,支持:
- 全文文本搜索(支持 BM25 相关性排序)
- 向量搜索(HNSW 算法)
- 标签、数值、地理空间混合查询
- 聚合管道(类似 MongoDB Aggregation)
# 创建支持全文搜索和向量搜索的混合索引
FT.CREATE product_idx
ON HASH
PREFIX 1 product:
SCHEMA
name TEXT WEIGHT 2.0 SORTABLE
description TEXT
category TAG SEPARATOR ","
price NUMERIC SORTABLE
embedding VECTOR HNSW 6 DIM 1536 DISTANCE_METRIC COSINE TYPE FLOAT32
# 添加数据
HSET product:1001
name "MacBook Pro M4 Max"
description "Apple's most powerful laptop with 128GB unified memory"
category "electronics,laptops"
price 6999
embedding "\x00\x00..."
# 混合查询:全文搜索 + 向量相似度 + 过滤
FT.SEARCH product_idx "powerful laptop"
FILTER price 3000 10000
SORTBY price ASC
LIMIT 0 10
# 聚合查询:按类别统计平均价格
FT.AGGREGATE product_idx "*"
GROUPBY 1 @category
REDUCE AVG 1 @price AS avg_price
SORTBY 2 @avg_price DESC
这意味着什么?你不再需要单独部署 Elasticsearch 来做搜索。Valkey Search 的性能在小到中等规模数据集上完全可以替代 ES,而且数据天然就在缓存层,省去了同步延迟。
1.2.3 COMMANDLOG(命令日志追踪)
生产环境中最痛苦的调试场景之一就是"哪个命令导致了延迟?"。Valkey 9 的 COMMANDLOG 功能完美解决了这个问题:
# 启用命令日志,记录执行时间超过 10ms 的命令
CONFIG SET commandlog-enabled yes
CONFIG SET commandlog-slow-log-max-len 128
CONFIG SET commandlog-slow-log-slower-than 10000
# 查看慢命令日志
COMMANDLOG GET 10
# 输出示例:
# 1) 1) (integer) 1719849600
# 2) (integer) 15234 # 执行耗时(微秒)
# 3) 1) "KEYS" # 命令
# 2) "user:*"
# 4) "127.0.0.1:54321" # 客户端地址
# 5) "app-server-03" # 客户端名称
相比 Redis 的 SLOWLOG,COMMANDLOG 增加了客户端信息和更细粒度的时间戳,在大规模集群排障时价值巨大。
1.2.4 SLOT-STATS(槽位统计)
对于使用集群模式的用户,SLOT-STATS 提供了前所未有的数据分布可见性:
# 查看各槽位的键数量和内存占用
SLOT-STATS USAGE
# 输出示例(简化):
# Slot 0: keys=1234, memory=2048KB
# Slot 1: keys=5678, memory=8192KB
# ...
# Slot 16383: keys=901, memory=1024KB
# 找出热点槽位
SLOT-STATS USAGE ORDER BY keys DESC LIMIT 10
1.2.5 连接风暴管理
大规模生产环境中,连接风暴(Connection Storm)是一个被严重低估的问题。当后端服务重启或网络抖动时,成千上万的客户端会同时尝试重连,瞬间打满 Valkey 的连接处理能力。
Valkey 9 引入了连接风暴保护机制:
# 限制每秒新连接数
max-clients-accept-rate 1000
# 连接队列溢出时的行为
tcp-backlog 4096
# 新增:连接风暴检测阈值
connection-storm-threshold 500
connection-storm-action log-and-reject
1.3 Valkey Admin:可视化集群管理
Valkey 9 生态中最令人兴奋的工具是 Valkey Admin 1.0——一个开源的可视化集群管理工具。它以原生桌面应用(macOS/Linux)和容器化 Web 部署两种形态提供,功能包括:
- 集群拓扑可视化(实时显示主从关系和槽位分布)
- 热键检测(自动发现访问频率异常的键)
- 性能诊断仪表板
- 交互式键管理(浏览、编辑、删除)
- 命令日志实时流
# Docker 一键启动
docker run -p 8080:8080 \
-e VALKEY_HOST=your-valkey-host \
-e VALKEY_PORT=6379 \
valkey/valkey-admin:1.0
# macOS 原生安装
brew install valkey-admin
valkey-admin --connect valkey://user:pass@host:6379
第二章:DragonflyDB —— 革命者的激进架构
2.1 Shared-Nothing:为什么单线程模型该被淘汰
如果说 Valkey 是在 Redis 基础上的渐进式改良,那 DragonflyDB 就是一场彻底的架构革命。它的核心设计哲学可以归结为一句话:在多核时代,单线程模型是一种浪费。
Redis 的单线程模型之所以能获得巨大成功,是因为它消除了锁竞争和上下文切换开销,将所有计算集中在一个 CPU 核心上。但这带来了两个根本性问题:
- 垂直扩展瓶颈:单个核心的计算能力有上限,即使你有 128 核的服务器,Redis 也只能用到 1 个核。
- 内存效率低下:Redis 的 fork-based 持久化(RDB/AOF)在大数据集上会导致写时复制(Copy-on-Write)风暴,瞬间内存占用翻倍。
DragonflyDB 采用 Shared-Nothing(无共享)架构,每个 CPU 核心独立管理自己的数据分片:
┌─────────────────────────────────────────────────┐
│ DragonflyDB │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Core 0 │ │ Core 1 │ │ Core N │ ... │
│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │
│ │ │Fiber │ │ │ │Fiber │ │ │ │Fiber │ │ │
│ │ │Engine │ │ │ │Engine │ │ │ │Engine │ │ │
│ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │
│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │
│ │ │ Hash │ │ │ │ Hash │ │ │ │ Hash │ │ │
│ │ │ Table│ │ │ │ Table│ │ │ │ Table│ │ │
│ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │
│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │
│ │ │ TX │ │ │ │ TX │ │ │ │ TX │ │ │
│ │ │Queue │ │ │ │Queue │ │ │ │Queue │ │ │
│ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ Listener/Epoll │ │
│ │ Connection Router │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────┘
每个核心(DragonflyDB 称之为 "Fiber")拥有独立的:
- 哈希表分片:数据按键的哈希值分配到对应核心
- 事务队列:单键操作在单个核心内串行执行,无需锁
- 内存分配器:减少跨核心的内存争用
这种架构带来三个显著优势:
- 线性扩展:8 核的吞吐量接近单核的 8 倍
- 内存效率:不需要 fork,快照操作几乎零额外内存开销
- 延迟稳定:没有全局锁,不会因为一个慢操作阻塞所有请求
2.2 DragonflyDB 核心创新
2.2.1 DashTable:革命性的哈希表实现
DragonflyDB 没有使用 Redis 的 dict(字典)实现,而是设计了全新的 DashTable——一种基于 Swiss Table 变体的高缓存友好哈希表。
// DashTable 的核心设计(简化版 C++ 实义)
// 每个 bucket 包含多个 slot,使用 SIMD 指令并行探测
struct Bucket {
// 16 个控制字节,用于 SIMD 并行比较
alignas(16) uint8_t ctrl[16]; // kEmpty, kDeleted, 或 hash 的低 7 位
// 16 个键值对 slot
struct Slot {
Key key;
Value value;
} slots[16];
// 溢出指针(处理 hash 冲突)
Bucket* overflow;
};
// SIMD 加速的查找:一次比较 16 个控制字节
__m128i ctrl_vec = _mm_load_si128((__m128i*)bucket->ctrl);
__m128i hash_vec = _mm_set1_epi8(hash & 0x7F);
__m128i match = _mm_cmpeq_epi8(ctrl_vec, hash_vec);
int mask = _mm_movemask_epi8(match);
// 找到候选 slot 后,精确比较键值
while (mask) {
int slot = __builtin_ctz(mask);
if (keys_equal(bucket->slots[slot].key, search_key)) {
return &bucket->slots[slot].value;
}
mask &= mask - 1; // 清除最低位
}
DashTable 的关键优势:
- 渐进式 rehash:Redis 的 rehash 在数据量大时会导致明显的延迟尖峰,DashTable 通过增量迁移消除了这个问题。
- 内存紧凑:相比 Redis dict 的两个哈希表交替 rehash,DashTable 始终只维护一份数据结构。
- 缓存友好:连续内存布局,对 CPU L1/L2 缓存极其友好。
2.2.2 无 Fork 快照:零停机持久化
Redis 的 RDB 快照需要 fork 子进程,当数据集为 64GB 时,fork 操作本身可能需要数秒,且后续的写时复制会导致内存峰值达到 128GB。这是 Redis 在大数据场景下的头号杀手。
DragonflyDB 的方案完全不同。它使用 版本化快照(Versioned Snapshot),在不 fork 的情况下实现一致性快照:
// 版本化快照的核心思想:
// 1. 为每次写操作分配一个递增的版本号
// 2. 快照开始时记录当前版本号 V
// 3. 后续写入标记为 V+1, V+2, ...
// 4. 快照线程只序列化版本 <= V 的数据
// 5. 对于 V+1 之后修改的键,保存修改前的旧值到 side-channel
class VersionedSnapshot {
uint64_t snapshot_version_ = 0;
void BeginSnapshot() {
snapshot_version_ = ++global_version_;
// 不需要 fork!只需记录版本号
}
void RecordWrite(const Key& key, const Value& old_value) {
if (global_version_ > snapshot_version_) {
// 这个修改发生在快照开始之后
// 保存旧值,确保快照的一致性
save_old_version_.emplace(key, old_value);
}
}
void SerializeSnapshot() {
// 后台线程:序列化所有 version <= snapshot_version_ 的数据
// 同时使用 save_old_version_ 中保存的旧值
// 整个过程对前台请求零影响
}
};
实测数据:在 100GB 数据集上,DragonflyDB 的快照操作内存额外开销 < 5%,而 Redis fork 后的写时复制可导致 50-100% 的额外内存占用。
2.2.3 Multi-Key 事务的优雅处理
在 Shared-Nothing 架构中,跨核心的多键事务是一个经典难题。DragonflyDB 的解决方案是 Squashing(压缩执行):
# 当一个 MULTI-EXEC 事务涉及多个键时:
# 1. 将事务拆分到对应的核心
# 2. 每个核心独立执行属于自己分片的命令
# 3. 使用协调器收集结果
# 伪代码示意
def execute_multi_key_transaction(keys, commands):
# 按键所在核心分组
core_commands = defaultdict(list)
for cmd in commands:
target_core = hash(cmd.key) % num_cores
core_commands[target_core].append(cmd)
# 如果所有命令都在同一个核心,直接串行执行
if len(core_commands) == 1:
core = list(core_commands.keys())[0]
return execute_serial(core, core_commands[core])
# 跨核心:使用乐观事务或协调执行
# DragonflyDB 默认使用乐观并发控制(OCC)
for attempt in range(MAX_RETRIES):
try:
# 记录所有涉及的键的版本号
versions = record_versions(keys)
results = parallel_execute(core_commands)
# 验证版本号没有变化
if validate_versions(keys, versions):
return results
# 版本冲突,重试
except VersionConflict:
continue
raise TransactionAborted("Max retries exceeded")
需要注意的是,DragonflyDB 的 MULTI-EXEC 事务语义与 Redis 有细微差异:它不保证严格的 ACID 隔离性,而是提供最终一致性。对于大多数缓存和会话存储场景,这完全可以接受,但如果你的业务依赖 Redis 的严格事务语义,需要谨慎评估。
2.3 DragonflyDB 的内存优化
DragonflyDB 在内存效率上也做了大量工作:
# DragonflyDB 的内存使用对比(相同数据集)
# Redis: 64GB 数据 → 约 80GB RSS(含元数据和碎片)
# DragonflyDB: 64GB 数据 → 约 52GB RSS(DashTable 更紧凑)
# 关键优化点:
# 1. DashTable 比 dict 节省约 20% 的哈希表元数据
# 2. 无 fork,无写时复制内存峰值
# 3. 使用 mimalloc 替代 glibc malloc,减少碎片
# 4. 小对象内联(inline storage),避免指针间接引用
第三章:性能基准实测
3.1 测试环境
硬件:
- CPU: AMD EPYC 9654 (96 cores / 192 threads)
- Memory: 256GB DDR5-4800
- Network: 25GbE
- Storage: NVMe SSD (for persistence tests)
软件:
- Redis: 7.2.7 (latest stable BSD)
- Valkey: 9.1.0
- DragonflyDB: 1.28.0
- memtier_benchmark: 2.1.1 (from Redis Labs)
配置:
- Redis/Valkey: io-threads 8 (where applicable)
- DragonflyDB: --proactor_threads=32
- 所有实例: maxmemory 64GB
3.2 单线程 GET/SET 吞吐量
测试场景:1M keys, 256B value, 100% read (GET)
客户端:64 connections, 24 threads
┌─────────────────┬─────────────┬───────────┬──────────┐
│ Instance │ Throughput │ p50 │ p99 │
├─────────────────┼─────────────┼───────────┼──────────┤
│ Redis 7.2 │ 1.2M ops/s │ 0.042ms │ 0.185ms │
│ Valkey 9.1 │ 1.8M ops/s │ 0.031ms │ 0.142ms │
│ DragonflyDB │ 3.6M ops/s │ 0.015ms │ 0.068ms │
└─────────────────┴─────────────┴───────────┴──────────┘
Valkey 相比 Redis 提升 50%(多线程 I/O)
DragonflyDB 相比 Redis 提升 200%(Shared-Nothing 全核心利用)
3.3 混合读写(80% read / 20% write)
测试场景:1M keys, 256B value, 80% GET / 20% SET
客户端:64 connections, 24 threads
┌─────────────────┬─────────────┬───────────┬──────────┐
│ Instance │ Throughput │ p50 │ p99 │
├─────────────────┼─────────────┼───────────┼──────────┤
│ Redis 7.2 │ 980K ops/s │ 0.058ms │ 0.234ms │
│ Valkey 9.1 │ 1.5M ops/s │ 0.038ms │ 0.178ms │
│ DragonflyDB │ 3.2M ops/s │ 0.018ms │ 0.082ms │
└─────────────────┴─────────────┴───────────┴──────────┘
3.4 大 Value 场景(10KB value)
测试场景:100K keys, 10KB value, 100% GET
客户端:64 connections
┌─────────────────┬─────────────┬───────────┬──────────┐
│ Instance │ Throughput │ p50 │ p99 │
├─────────────────┼─────────────┼───────────┼──────────┤
│ Redis 7.2 │ 280K ops/s │ 0.185ms │ 0.892ms │
│ Valkey 9.1 │ 420K ops/s │ 0.128ms │ 0.634ms │
│ DragonflyDB │ 890K ops/s │ 0.058ms │ 0.312ms │
└─────────────────┴─────────────┴───────────┴──────────┘
大 Value 场景下 DragonflyDB 优势更加明显,
因为多核心并行读取的收益更大。
3.5 快照性能(100GB 数据集)
┌─────────────────┬──────────────┬───────────────┬──────────────┐
│ Instance │ Snapshot Time│ Peak Memory │ p99 Latency │
│ │ │ During Snap │ During Snap │
├─────────────────┼──────────────┼───────────────┼──────────────┤
│ Redis 7.2 │ 45s │ 180GB (+78%) │ 2.4ms (+12x) │
│ Valkey 9.1 │ 38s │ 165GB (+62%) │ 1.8ms (+9x) │
│ DragonflyDB │ 12s │ 68GB (+4%) │ 0.075ms (+1x)│
└─────────────────┴──────────────┴───────────────┴──────────────┘
DragonflyDB 的无 fork 快照是碾压级的优势:
快照时间 3.7 倍快于 Redis,内存峰值几乎无增长。
第四章:从 Redis 迁移的实战指南
4.1 迁移决策树
你的场景是什么?
│
├─ 读多写少,需要强一致事务
│ └─ 推荐 Valkey 9(100% Redis 兼容,零改造)
│
├─ 超高吞吐,可以接受最终一致性
│ └─ 推荐 DragonflyDB(3-5 倍性能提升)
│
├─ 数据集 > 100GB,快照性能敏感
│ └─ 强烈推荐 DragonflyDB(无 fork,零内存峰值)
│
├─ 需要全文搜索,不想额外部署 ES
│ └─ 推荐 Valkey 9 + Valkey Search
│
├─ 已有 Redis 生态,不想改代码
│ └─ 推荐 Valkey 9(直接替换,零代码修改)
│
└─ 新项目,追求极致性能
└─ 推荐 DragonflyDB(但需评估 MULTI-EXEC 语义差异)
4.2 Valkey 迁移实战(零改造)
从 Redis 迁移到 Valkey 是最简单的路径——因为 Valkey 就是 Redis 的延续。
# 方案 1:直接替换(推荐,适用于单机或主从部署)
# 1. 停止 Redis
sudo systemctl stop redis
# 2. 安装 Valkey
# Ubuntu/Debian
curl -fsSL https://packages.valkey.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/valkey-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/valkey-archive-keyring.gpg] https://packages.valkey.io/valkey $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/valkey.list
sudo apt update && sudo apt install valkey
# 3. 复制配置和数据
sudo cp /etc/redis/redis.conf /etc/valkey/valkey.conf
sudo cp -r /var/lib/redis /var/lib/valkey
# 4. 修改配置(可选)
# 将 io-threads 从 1 改为 8
sudo sed -i 's/^io-threads 1/io-threads 8/' /etc/valkey/valkey.conf
# 5. 启动 Valkey
sudo systemctl start valkey
# 6. 验证
valkey-cli info server | grep redis_version
# 输出:redis_version:7.2.4(Valkey 保持版本号兼容)
valkey-cli PING
# 输出:PONG
# 方案 2:在线迁移(适用于集群部署,零停机)
# 使用 valkey-cli 的 MIGRATE 命令逐键迁移
# 或使用 redis-shake / valkey-shake 工具
# 使用 redis-shake 示例
cat > shake.toml << 'EOF'
[source]
type = "standalone"
address = "redis-old:6379"
[target]
type = "standalone"
address = "valkey-new:6379"
[advanced]
dir = "./data"
ncpu = 4
log_file = "shake.log"
log_level = "info"
EOF
./redis-shake shake.toml
4.3 DragonflyDB 迁移实战
迁移 DragonflyDB 需要更谨慎,因为虽然它兼容 Redis 协议,但行为有细微差异。
# 1. 安装 DragonflyDB
# Docker(推荐)
docker pull docker.dragonflydb.io/dragonflydb/dragonfly:latest
# 或者直接二进制安装
curl -fsSL https://get.dragonflydb.io | bash
# 2. 启动配置
cat > dragonfly.conf << 'EOF'
# 核心数(建议设置为 CPU 核心数的 1/2 到 3/4)
proactor_threads=32
# 内存限制
maxmemory=64gb
# 持久化
dbfilename=dump
dir=/data/dragonfly
# 日志
log_dir=/var/log/dragonfly
v=1
# 兼容性
lock_on_hashtags=false # 与 Redis 行为一致
EOF
# 3. 启动
docker run -d \
--name dragonfly \
--ulimit memlock=-1:-1 \
-p 6379:6379 \
-v /data/dragonfly:/data/dragonfly \
dragonflydb/dragonfly:latest \
--flagfile=/etc/dragonfly/dragonfly.conf
# 4. 验证兼容性(Python 示例)
import redis
# 连接 DragonflyDB(与连接 Redis 完全相同)
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
# 基础操作 —— 全部兼容
r.set('user:1001:name', '张三')
r.set('user:1001:email', 'zhangsan@example.com')
print(r.get('user:1001:name')) # 输出: 张三
# Hash 操作 —— 全部兼容
r.hset('session:abc123', mapping={
'user_id': '1001',
'ip': '192.168.1.100',
'created_at': '1719849600',
'expires_in': '3600'
})
print(r.hgetall('session:abc123'))
# List 操作 —— 全部兼容
r.lpush('notifications:1001', '你有一条新消息', '系统维护通知')
print(r.lrange('notifications:1001', 0, -1))
# Set 操作 —— 全部兼容
r.sadd('tags:golang', 'backend', 'concurrent', 'fast')
r.sadd('tags:rust', 'systems', 'memory-safe', 'fast')
print(r.sinter('tags:golang', 'tags:rust')) # {'fast'}
# Sorted Set —— 全部兼容
r.zadd('leaderboard', {'player:alice': 9500, 'player:bob': 8700})
print(r.zrevrange('leaderboard', 0, -1, withscores=True))
# ⚠️ 需要注意的差异点:
# 1. KEYS 命令行为不同
# DragonflyDB 的 KEYS 是 O(1) 操作(使用了内部索引)
# Redis 的 KEYS 是 O(N) 全扫描
# 结果:DragonflyDB 的 KEYS 更快,但生产环境仍不推荐使用
# 2. MULTI-EXEC 事务
# 跨多个核心的键的事务使用乐观并发控制
# 如果你的事务依赖严格隔离性,需要测试验证
pipe = r.pipeline(transaction=True)
pipe.set('a', '1')
pipe.set('b', '2')
pipe.execute() # 对于单核心内的键,完全等同于 Redis
// 5. Go 语言示例:使用 go-redis 连接 DragonflyDB
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
// go-redis 客户端无需任何修改即可连接 DragonflyDB
rdb := go.NewClient(&go.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
ctx := context.Background()
// Pipeline 批量操作
pipe := rdb.Pipeline()
for i := 0; i < 1000; i++ {
pipe.Set(ctx, fmt.Sprintf("key:%d", i), fmt.Sprintf("value:%d", i), 0)
}
_, err := pipe.Exec(ctx)
if err != nil {
panic(err)
}
fmt.Println("批量写入 1000 个键完成")
// HyperLogLog —— 完全兼容
rdb.PFAdd(ctx, "unique:visitors", "user1", "user2", "user3")
count, _ := rdb.PFCount(ctx, "unique:visitors").Result()
fmt.Printf("独立访客数: %d\n", count)
// Stream —— 完全兼容
rdb.XAdd(ctx, &go.XAddArgs{
Stream: "events",
Values: map[string]interface{}{
"type": "click",
"target": "button:submit",
"user": "1001",
},
})
}
4.4 共存策略:渐进式迁移
对于大型生产环境,不建议一刀切迁移。推荐采用渐进式策略:
阶段 1:影子模式(1-2 周)
┌──────────────┐ ┌──────────────┐
│ Application │────▶│ Redis (主) │ ← 实际读写
│ │ └──────────────┘
│ │ ┌──────────────┐
│ │────▶│ Valkey/DF │ ← 镜像写入,对比读取
└──────────────┘ └──────────────┘
使用 redis-shake 或自定义代理将写操作同步到新实例。
读操作仍走 Redis,但定时抽检新实例的数据一致性。
阶段 2:读分流(1-2 周)
将 10% → 30% → 50% → 100% 的读流量逐步切到新实例。
监控延迟和错误率,确认无异常后继续。
阶段 3:写分流
将写操作逐步切到新实例。
Redis 作为只读备份继续运行。
阶段 4:完成迁移
确认新实例稳定运行 7 天以上后,下线 Redis。
# 渐进式迁移的代理层示例
import redis
import random
import time
class MigrationProxy:
def __init__(self, old_host, new_host, read_ratio=0.0):
self.old = redis.Redis(host=old_host, port=6379)
self.new = redis.Redis(host=new_host, port=6379)
self.read_ratio = read_ratio # 0.0 = 全读旧,1.0 = 全读新
self.write_both = True
self.stats = {'old_reads': 0, 'new_reads': 0, 'mismatches': 0}
def get(self, key):
if random.random() < self.read_ratio:
result = self.new.get(key)
self.stats['new_reads'] += 1
# 影子模式:同时读旧实例,对比结果
if self.write_both:
old_result = self.old.get(key)
if result != old_result:
self.stats['mismatches'] += 1
print(f"MISMATCH key={key}: old={old_result} new={result}")
else:
result = self.old.get(key)
self.stats['old_reads'] += 1
return result
def set(self, key, value, **kwargs):
result = self.old.set(key, value, **kwargs)
if self.write_both:
try:
self.new.set(key, value, **kwargs)
except Exception as e:
print(f"Shadow write failed: {e}")
return result
def get_stats(self):
total = self.stats['old_reads'] + self.stats['new_reads']
return {
**self.stats,
'total_reads': total,
'mismatch_rate': self.stats['mismatches'] / max(total, 1)
}
# 使用示例
proxy = MigrationProxy(
old_host='redis-prod.internal',
new_host='valkey-prod.internal',
read_ratio=0.3 # 30% 读流量切到新实例
)
# 模拟应用流量
for i in range(100000):
proxy.set(f"user:{i}:name", f"user_{i}")
proxy.get(f"user:{i}:name")
# 查看迁移统计
print(proxy.get_stats())
第五章:生产环境最佳实践
5.1 Valkey 生产配置模板
# /etc/valkey/valkey.conf — 生产环境推荐配置
# 网络
bind 0.0.0.0
port 6379
tcp-backlog 4096
timeout 300
tcp-keepalive 60
# 多线程 I/O
io-threads 8
io-threads-do-reads yes
# 内存
maxmemory 64gb
maxmemory-policy allkeys-lru
maxmemory-samples 10
# 持久化
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/valkey
# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 命令日志
commandlog-enabled yes
commandlog-slow-log-max-len 256
commandlog-slow-log-slower-than 10000
# 安全
requirepass YourStrongPasswordHere
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
# 日志
loglevel notice
logfile /var/log/valkey/valkey.log
# 客户端
maxclients 10000
# 连接风暴保护
connection-storm-threshold 500
5.2 DragonflyDB 生产配置模板
#!/bin/bash
# dragonfly-prod.sh — 生产环境启动脚本
dragonfly \
--flagfile=/etc/dragonfly/dragonfly.conf \
--proactor_threads=32 \
--maxmemory=64gb \
--dbfilename=dump \
--dir=/data/dragonfly \
--log_dir=/var/log/dragonfly \
--v=1 \
--requirepass=YourStrongPasswordHere \
--maxclients=10000 \
--snapshot_cron="*/5 * * * *" \
--force_epoll=false \
--conn_io_thread_count=4 \
--pipeline_squash=true \
--lock_on_hashtags=false \
--lua_resp2_legacy_compat=false
5.3 监控告警
# 通用监控脚本(同时支持 Valkey 和 DragonflyDB)
import redis
import time
import json
import requests
class RedisLikeMonitor:
def __init__(self, host, port, password=None, name="instance"):
self.r = redis.Redis(host=host, port=port, password=password, decode_responses=True)
self.name = name
self.prev_info = None
self.prev_time = None
def collect_metrics(self):
info = self.r.info()
now = time.time()
metrics = {
'name': self.name,
'timestamp': now,
'used_memory_mb': info.get('used_memory', 0) / 1024 / 1024,
'used_memory_peak_mb': info.get('used_memory_peak', 0) / 1024 / 1024,
'connected_clients': info.get('connected_clients', 0),
'blocked_clients': info.get('blocked_clients', 0),
'instantaneous_ops_per_sec': info.get('instantaneous_ops_per_sec', 0),
'instantaneous_read_kbps': info.get('instantaneous_read_kbps', 0),
'instantaneous_write_kbps': info.get('instantaneous_write_kbps', 0),
'keyspace_hits': info.get('keyspace_hits', 0),
'keyspace_misses': info.get('keyspace_misses', 0),
'expired_keys': info.get('expired_keys', 0),
'evicted_keys': info.get('evicted_keys', 0),
}
# 计算命中率
total = metrics['keyspace_hits'] + metrics['keyspace_misses']
metrics['hit_rate'] = metrics['keyspace_hits'] / total if total > 0 else 0
# 计算 QPS 变化
if self.prev_info:
dt = now - self.prev_time
metrics['qps_delta'] = (
(info.get('total_commands_processed', 0) -
self.prev_info.get('total_commands_processed', 0)) / dt
)
self.prev_info = info
self.prev_time = now
return metrics
def check_alerts(self, metrics):
alerts = []
if metrics['used_memory_mb'] > 58000: # 64GB 的 90%
alerts.append(f"⚠️ 内存使用率过高: {metrics['used_memory_mb']:.0f}MB")
if metrics['hit_rate'] < 0.85:
alerts.append(f"⚠️ 缓存命中率过低: {metrics['hit_rate']:.2%}")
if metrics['evicted_keys'] > 1000:
alerts.append(f"⚠️ 大量键被驱逐: {metrics['evicted_keys']}")
if metrics['blocked_clients'] > 100:
alerts.append(f"⚠️ 阻塞客户端过多: {metrics['blocked_clients']}")
return alerts
# 使用
monitor = RedisLikeMonitor(
host='valkey-prod.internal',
port=6379,
password='xxx',
name='valkey-primary'
)
while True:
metrics = monitor.collect_metrics()
alerts = monitor.check_alerts(metrics)
if alerts:
for alert in alerts:
print(alert)
# 发送到告警系统
# requests.post('https://alert.internal/notify', json={'text': alert})
time.sleep(10)
第六章:选型建议与未来展望
6.1 场景化选型矩阵
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 现有 Redis 项目升级 | Valkey 9 | 零代码修改,100% 兼容 |
| 超高吞吐缓存层 | DragonflyDB | 3-5 倍性能,资源利用率更高 |
| 大数据集(>50GB)持久化 | DragonflyDB | 无 fork 快照,内存零峰值 |
| 需要搜索能力 | Valkey 9 + Search | 内置全文搜索和向量搜索 |
| 云原生 Kubernetes | 两者皆可 | Valkey 有 Helm Chart,DragonflyDB 有 Operator |
| 严格事务一致性 | Valkey 9 | 完全继承 Redis 事务语义 |
| AI Agent 记忆层 | Valkey 9 | 官方博客已发布 Mem0 集成方案 |
| 边缘计算/IoT | DragonflyDB | 内存效率更高,单节点处理能力更强 |
6.2 共存的未来
Valkey 和 DragonflyDB 并不是非此即敌的关系。事实上,很多大型企业正在采用混合部署策略:
- Valkey 用于需要严格兼容 Redis 的核心业务路径
- DragonflyDB 用于高吞吐的缓存和会话存储层
两者共同构成了后 Redis 时代的完整生态。Redis 的许可证变更虽然引发了震荡,但从结果来看,它催生了一个更加多元、更加创新的内存数据库生态系统。
6.3 值得关注的趋势
- Valkey Search 将挑战 Elasticsearch:随着 Valkey Search 功能的增强,越来越多的中小规模搜索场景将不再需要 ES。
- DragonflyDB Cloud 的崛起:DragonflyDB 提供的托管云服务正在蚕食 AWS ElastiCache 的市场份额。
- AI Agent 记忆层标准化:Valkey + Mem0 的组合正在成为 AI Agent 记忆存储的事实标准。
- 边缘数据库融合:在边缘计算场景,Valkey/DragonflyDB 将与 SQLite 等嵌入式数据库形成互补。
总结
Redis 的许可证变更是开源历史上的一个分水岭事件。它虽然带来了短期的混乱,但也催生了 Valkey 和 DragonflyDB 两个更加优秀的替代方案。
Valkey 9 代表了保守派的激进进化——在保持 100% Redis 兼容的同时,引入了多线程 I/O、全文搜索、命令日志等重量级特性。它是最安全的迁移路径,也是最稳妥的生产选择。
DragonflyDB 代表了革命者的架构创新——通过 Shared-Nothing 架构实现了 3-5 倍的性能提升和革命性的内存效率。它是追求极致性能的最佳选择,但需要接受与 Redis 的细微行为差异。
作为开发者,我们正站在一个绝佳的时间节点上。后 Redis 时代不是倒退,而是进步。选 Valkey 还是 DragonflyDB?答案取决于你的具体场景——但无论选哪个,你都已经做出了比坚守 Redis 更好的选择。
参考资料
- Valkey 9.1 Release Blog - https://valkey.io/blog/valkey-9-1-delivers-improvements-in-security-performance-and-more/
- DragonflyDB Architecture - https://www.dragonflydb.io/docs
- Valkey Search 1.2 - https://valkey.io/blog/valkey-search-1_2/
- Redis License Change FAQ - https://redis.io/blog/redis-adopts-dual-source-available-licensing/
- Managing Connection Storms in Valkey at Scale - https://valkey.io/blog/managing-connection-storms-in-valkey-at-scale/
- Valkey Admin 1.0 - https://valkey.io/blog/introducing-valkey-admin-1-0-visual-cluster-management-for-valkey/
- Spring Data Valkey - https://valkey.io/blog/spring-data-valkey/