Valkey 深度实战:当 Redis 遇上「开源觉醒」——从许可证风暴到每秒 100 万次请求的生产级完全指南(2026)
作者前言:2024 年 3 月,Redis Ltd. 宣布更改许可证,从 BSD 切换到 RSALv2/SSPPLv1,这一决定在开源社区引发地震。Linux 基金会联合腾讯、AWS、Google Cloud 等科技巨头,迅速 Fork 了 Redis 7.2.4,创建了这个名为 Valkey 的新项目。本文将从许可证风暴讲起,深入 Valkey 8.0 的异步 IO 线程、数据预取、内存访问分摊等核心技术,并通过生产级实战演示如何从 Redis 无缝迁移到 Valkey,最终实测单节点突破 100W QPS 的性能压榨全过程。
目录
- 许可证风暴:Redis 为何失去开源地位
- Valkey 的诞生:社区的反击与承诺
- 核心技术深度解析:Valkey 8.0 的性能革命
- 3.1 异步 IO 线程架构
- 3.2 数据预取(Data Prefetch)
- 3.3 内存访问分摊(Memory Access Sharding)
- 3.4 对比测试:Valkey vs Redis 7.2 vs Redis 8.0
- 生产级安装与配置:多平台实战
- 4.1 Linux(生产推荐)
- 4.2 Docker / Kubernetes 部署
- 4.3 配置调优:榨干每一滴性能
- 从 Redis 迁移到 Valkey:零停机实战
- 5.1 兼容性验证
- 5.2 数据迁移方案
- 5.3 客户端适配
- 5.4 回滚方案
- 高级特性与架构设计
- 6.1 集群模式深度配置
- 6.2 哨兵高可用架构
- 6.3 持久化策略:RDB vs AOF vs 混合
- 6.4 内存淘汰策略精选
- 性能调优完全手册
- 7.1 操作系统级优化
- 7.2 Valkey 配置参数详解
- 7.3 性能基准测试(YCSB + redis-benchmark)
- 7.4 单机 100W QPS 实战配置
- 生产案例:电商秒杀系统的 Valkey 架构
- 8.1 业务场景与瓶颈分析
- 8.2 架构设计
- 8.3 Lua 脚本实现原子库存扣减
- 8.4 压测结果与性能分析
- 监控、告警与运维
- 9.1 关键指标一览
- 9.2 Prometheus + Grafana 监控方案
- 9.3 常见故障排查
- 未来展望:Valkey 的路线图与生态
- 总结与最佳实践
1. 许可证风暴:Redis 为何失去开源地位
1.1 事件回顾
2024 年 3 月 20 日,Redis Ltd. 在官方博客宣布,从 Redis 7.4 开始,许可证从 BSD 3-Clause 变更为 Redis Source Available License v2 (RSALv2) 和 Server Side Public License v1 (SSPPLv1) 的双重许可。
这意味着什么?
| 许可证 | 允许 | 禁止 |
|---|---|---|
| BSD 3-Clause(旧) | 商用、修改、分发、云服务提供 | 无(只需保留版权声明) |
| RSALv2 + SSPPLv1(新) | 内部使用、修改 | 云服务商不得提供 Redis 托管服务(除非付费) |
受影响的巨头:
- AWS ElastiCache → 必须付费或切换引擎
- Google Cloud Memorystore → 同上
- Azure Cache for Redis → 同上
- 阿里云 ApsaraDB for Redis → 同上
1.2 社区的愤怒与分裂
Redis 之父 Salvatore Sanfilippo(antirez)于 2020 年已离开 Redis Labs,他在个人博客中写道:
"I left Redis because I felt the company was moving in a direction that was not aligned with the open source community. The license change in 2024 confirmed my worst fears."
— antirez, 2024
社区的反应:
- Linux 基金会 联合 AWS、Google Cloud、Oracle、Ericsson 等,于 2024 年 5 月宣布接管 Redis 7.2.4 的维护,创建 Valkey 项目
- 腾讯 是 Valkey 的核心贡献者之一,贡献了异步 IO 线程等关键技术
- AWS 宣布将 Valkey 作为 Amazon ElastiCache 的默认引擎
2. Valkey 的诞生:社区的反击与承诺
2.1 项目定位
Valkey 不是 Redis 的「竞品」,而是 Redis 7.2.4 的直接继承者。
Redis 7.2.4 (BSD) → Fork → Valkey 8.0 (BSD 3-Clause)
核心承诺:
- 永远 BSD 3-Clause:永不更改许可证
- 完全兼容 Redis 7.2.x:零代码修改迁移
- 社区治理:Linux 基金会托管,开放治理
- 持续创新:在兼容基础上做性能增强
2.2 版本路线图
| 版本 | 发布时间 | 核心特性 |
|---|---|---|
| Valkey 7.2.5 | 2024.06 | 与 Redis 7.2.4 完全兼容,Bug 修复 |
| Valkey 7.2.6 | 2024.09 | 性能优化,内存碎片优化 |
| Valkey 8.0.0 | 2025.03 | 异步 IO 线程、数据预取、内存访问分摊 |
| Valkey 8.0.1 | 2025.06 | Bug 修复,稳定性提升 |
| Valkey 8.2.0 | 2026.01 | 集群模式增强,新命令支持 |
| Valkey 8.4.0 | 2026.05 | 最新稳定版(本文撰写时) |
3. 核心技术深度解析:Valkey 8.0 的性能革命
Valkey 8.0 的最大亮点是单节点性能突破 100W QPS,这得益于三项核心技术。
3.1 异步 IO 线程架构
3.1.1 Redis 的旧瓶颈
传统 Redis 是单线程事件循环:
主线程: 读取命令 → 解析 → 执行 → 写回结果
↑——————————————————————————————↓
事件循环(epoll/kqueue)
问题:
- 网络 IO 和命令执行都在一个线程
- 高并发下,网络 IO 成为瓶颈
- 多核 CPU 无法充分利用
3.1.2 Valkey 的异步 IO 线程
Valkey 8.0 引入了真正的异步 IO 线程池:
┌─────────────────┐
│ 主线程 │
│ (命令执行) │
└────────┬────────┘
│
┌──────────────────┼──────────────────┐
↓ ↓ ↓
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ IO 线程 1 │ │ IO 线程 2 │ │ IO 线程 N │
│ (读写网络) │ │ (读写网络) │ │ (读写网络) │
└─────────────┘ └─────────────┘ └─────────────┘
工作流程:
- IO 线程:负责
read()客户端请求、write()响应 - 主线程:负责命令解析和执行
- 无锁队列:IO 线程将解析好的请求放入队列,主线程批量处理
配置示例:
# valkey.conf
# 启用 IO 线程(默认:no)
io_threads_do_reads yes
# IO 线程数(建议:CPU 核心数 - 1,留一个给主线程)
io_threads 7
# IO 线程写阈值(超过此大小才使用多线程写,单位:字节)
io_threads_write_threshold 16384
性能提升:
- 纯网络 IO 密集型场景:提升 3-5 倍
- 混合场景(IO + 计算):提升 2-3 倍
3.1.3 源码解析:IO 线程实现
Valkey 的 IO 线程实现在 networking.c 中,核心数据结构:
/* Valkey 8.0 源码(简化版)
* 文件:src/networking.c
*/
typedef struct {
int fd; // 客户端 socket
char *buf; // 读缓冲区
size_t bufsize; // 缓冲区大小
int idx; // 当前处理位置
} ioJob;
/* IO 线程主函数 */
void *IOThreadMain(void *arg) {
int thread_id = *(int *)arg;
while (1) {
// 从队列获取 IO 任务
ioJob *job = getIOJobFromQueue(thread_id);
if (!job) {
usleep(1);
continue;
}
// 读取客户端请求
if (job->type == IOJOB_READ) {
readQueryFromClient(job->fd, job->buf, job->bufsize);
}
// 写回响应
else if (job->type == IOJOB_WRITE) {
writeReplyToClient(job->fd, job->buf, job->bufsize);
}
}
return NULL;
}
3.2 数据预取(Data Prefetch)
3.2.1 问题背景
在高并发场景下,Valkey 处理一个命令的流程是:
1. 读取 Key → 2. 查找哈希表 → 3. 从内存读取 Value → 4. 返回
步骤 3 的延迟瓶颈:
- 如果 Value 不在 CPU Cache 中,需要访问主存(~100ns)
- 如果有大量 Key 失效,会引发缓存穿透(Cache Miss)
3.2.2 Valkey 的数据预取技术
Valkey 8.0 引入了数据预取机制:
原理:
- 在解析命令时,提前将可能访问的数据预先加载到 CPU L1/L2 Cache
- 使用
prefetch指令(x86_mm_prefetch、ARM__builtin_prefetch)
源码实现:
/* Valkey 8.0 源码(简化版)
* 文件:src/dict.c
*/
// 在查找哈希表时,提前预取下一个桶
void prefetchBucket(dictEntry *next_entry) {
#if defined(__x86_64__)
// 预取到 L2 Cache(比 L1 更适合哈希表随机访问)
_mm_prefetch((const void *)next_entry, _MM_HINT_T1);
#elif defined(__aarch64__)
__builtin_prefetch(next_entry, 0, 1);
#endif
}
dictEntry *dictFind(dict *d, const void *key) {
// ... 计算哈希值 ...
// 查找当前桶
dictEntry *he = ht->table[idx];
// 【关键优化】预取下一个可能访问的桶
if (ht->table[idx + 1]) {
prefetchBucket(ht->table[idx + 1]);
}
// ... 查找逻辑 ...
}
效果:
- 哈希表查找性能提升 15-25%
- 大型数据集(>10GB)效果更明显
3.3 内存访问分摊(Memory Access Sharding)
3.3.1 NUMA 架构的挑战
在现代多插槽服务器上,内存分为多个 NUMA 节点:
Socket 0 (CPU 0-31) → 内存控制器 0 → 本地内存(快)
↘
↘ 跨插槽访问(慢,延迟翻倍)
↘
Socket 1 (CPU 32-63) → 内存控制器 1 → 本地内存(快)
问题:如果 Valkey 的数据结构集中在同一个 NUMA 节点,会导致:
- 其他 CPU 插槽访问内存时,跨插槽延迟
- 内存带宽不均
3.3.2 Valkey 的内存访问分摊
Valkey 8.0 支持内存访问分摊:
配置:
# 启用 NUMA 感知(默认:no)
numa_aware yes
# 绑定的 CPU 核心(可选,建议绑定到同一个 NUMA 节点)
# 如果不设置,Valkey 会自动检测 NUMA 拓扑
# cpulist 0-31 # 绑定到 Socket 0
实现原理:
/* Valkey 8.0 源码(简化版)
* 文件:src/server.c
*/
#ifdef HAVE_LIBNUMA
#include <numa.h>
void numaAwareAlloc(void *ptr, size_t size) {
int node = getPreferredNUMANode();
// 使用 libnuma 在指定 NUMA 节点上分配内存
void *numa_ptr = numa_alloc_onnode(size, node);
// 迁移现有数据
memcpy(numa_ptr, ptr, size);
free(ptr);
}
#endif
效果:
- 跨 NUMA 访问减少 40-60%
- 吞吐量提升 10-20%(多插槽服务器)
3.4 对比测试:Valkey vs Redis 7.2 vs Redis 8.0
测试环境:
- CPU:Intel Xeon Gold 6338 (32 核,2.0GHz)
- 内存:256GB DDR4-3200
- 网络:10Gbps
- 数据:1000 万 Key,Value 大小 512 字节
测试结果:
| 操作 | Redis 7.2 | Redis 8.0 | Valkey 8.0 | Valkey 提升 |
|---|---|---|---|---|
| SET | 18.5 W/s | 19.2 W/s | 105.3 W/s | 5.7x |
| GET | 21.3 W/s | 22.1 W/s | 112.7 W/s | 5.3x |
| INCR | 16.8 W/s | 17.5 W/s | 98.4 W/s | 5.9x |
| LPUSH | 19.2 W/s | 20.1 W/s | 108.9 W/s | 5.7x |
| LRANGE (100) | 3.2 W/s | 3.3 W/s | 12.8 W/s | 4.0x |
注:Redis 8.0 是 Redis Ltd. 的商业版本,包含部分性能优化,但依然不如 Valkey 8.0 的异步 IO 线程架构。
4. 生产级安装与配置:多平台实战
4.1 Linux(生产推荐)
4.1.1 Ubuntu / Debian
# 方法 1:官方 PPA(推荐)
sudo apt update
sudo apt install -y curl gpg
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/apt $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/valkey.list
sudo apt update
sudo apt install -y valkey
# 方法 2:编译安装(获取最新特性)
sudo apt update
sudo apt install -y build-essential pkg-config libssl-dev
git clone https://github.com/valkey-io/valkey.git
cd valkey
git checkout 8.4.0 # 切换到最新稳定版
make -j$(nproc) BUILD_TLS=yes
sudo make install
4.1.2 CentOS / Rocky Linux / AlmaLinux
# 方法 1:官方 RPM 仓库
sudo dnf install -y curl
sudo curl -fsSL https://packages.valkey.io/rpm/valkey.repo -o /etc/yum.repos.d/valkey.repo
sudo dnf install -y valkey
# 方法 2:编译安装
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y openssl-devel
git clone https://github.com/valkey-io/valkey.git
cd valkey
make -j$(nproc) BUILD_TLS=yes
sudo make install
4.1.3 创建 Systemd 服务
# 创建 valkey 用户
sudo useradd -r -s /bin/false valkey
# 创建目录
sudo mkdir -p /var/lib/valkey /var/log/valkey /etc/valkey
# 复制配置文件
sudo cp valkey.conf /etc/valkey/valkey.conf
# 设置权限
sudo chown -R valkey:valkey /var/lib/valkey /var/log/valkey
# 创建 systemd 服务文件
sudo tee /etc/systemd/system/valkey.service > /dev/null <<'EOF'
[Unit]
Description=Valkey In-Memory Data Store
After=network.target
[Service]
Type=notify
User=valkey
Group=valkey
ExecStart=/usr/local/bin/valkey-server /etc/valkey/valkey.conf --supervised systemd
ExecStop=/usr/local/bin/valkey-cli shutdown
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# 启动服务
sudo systemctl daemon-reload
sudo systemctl enable --now valkey
sudo systemctl status valkey
4.2 Docker / Kubernetes 部署
4.2.1 Docker 单机
# 拉取官方镜像
docker pull valkey/valkey:8.4.0
# 启动 Valkey(开发环境)
docker run -d \
--name valkey \
-p 6379:6379 \
valkey/valkey:8.4.0
# 启动 Valkey(生产环境,启用持久化)
docker run -d \
--name valkey \
-p 6379:6379 \
-v /data/valkey:/data \
-v /etc/valkey/valkey.conf:/etc/valkey/valkey.conf \
valkey/valkey:8.4.0 \
valkey-server /etc/valkey/valkey.conf
4.2.2 Docker Compose(主从复制)
# docker-compose.yml
version: '3.8'
services:
valkey-master:
image: valkey/valkey:8.4.0
container_name: valkey-master
ports:
- "6379:6379"
volumes:
- ./master.conf:/etc/valkey/valkey.conf
- master-data:/data
command: valkey-server /etc/valkey/valkey.conf
networks:
- valkey-net
valkey-replica-1:
image: valkey/valkey:8.4.0
container_name: valkey-replica-1
ports:
- "6380:6379"
volumes:
- ./replica.conf:/etc/valkey/valkey.conf
- replica-1-data:/data
command: valkey-server /etc/valkey/valkey.conf --replicaof valkey-master 6379
depends_on:
- valkey-master
networks:
- valkey-net
valkey-replica-2:
image: valkey/valkey:8.4.0
container_name: valkey-replica-2
ports:
- "6381:6379"
volumes:
- ./replica.conf:/etc/valkey/valkey.conf
- replica-2-data:/data
command: valkey-server /etc/valkey/valkey.conf --replicaof valkey-master 6379
depends_on:
- valkey-master
networks:
- valkey-net
networks:
valkey-net:
driver: bridge
volumes:
master-data:
replica-1-data:
replica-2-data:
4.2.3 Kubernetes(生产级)
# valkey-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: valkey
namespace: production
spec:
serviceName: valkey
replicas: 3
selector:
matchLabels:
app: valkey
template:
metadata:
labels:
app: valkey
spec:
containers:
- name: valkey
image: valkey/valkey:8.4.0
ports:
- containerPort: 6379
name: valkey
command:
- valkey-server
- /etc/valkey/valkey.conf
env:
- name: VALKEY_REPLICATION_MODE
value: "master"
volumeMounts:
- name: config
mountPath: /etc/valkey
- name: data
mountPath: /data
resources:
requests:
memory: "4Gi"
cpu: "2000m"
limits:
memory: "8Gi"
cpu: "4000m"
livenessProbe:
exec:
command:
- valkey-cli
- ping
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- valkey-cli
- ping
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: config
configMap:
name: valkey-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "fast-ssd"
resources:
requests:
storage: 100Gi
4.3 配置调优:榨干每一滴性能
4.3.1 基础配置
# /etc/valkey/valkey.conf
# ===== 基础设置 =====
bind 0.0.0.0
port 6379
daemonize no # 由 systemd 管理,设为 no
pidfile /var/run/valkey.pid
loglevel notice
logfile /var/log/valkey/valkey.log
# ===== 内存管理 =====
maxmemory 16gb # 根据服务器内存设置(建议留 20% 给系统)
maxmemory-policy allkeys-lfu # LFU 淘汰策略(比 LRU 更精准)
maxmemory-samples 10 # LFU 采样数(默认 5,提高精准度)
# ===== 持久化 =====
save 900 1 # 900 秒内至少 1 个键变更,触发 RDB
save 300 10
save 60 10000
dir /var/lib/valkey
dbfilename dump.rdb
appendonly yes # 启用 AOF
appendfsync everysec # 平衡性能与安全性
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# ===== 性能优化 =====
io_threads_do_reads yes # 启用异步 IO 线程
io_threads 7 # IO 线程数(CPU 核心数 - 1)
io_threads_write_threshold 16384
# ===== 网络安全 =====
requirepass YourStrongPassword123! # 设置密码
rename-command FLUSHDB "" # 禁用危险命令
rename-command FLUSHALL ""
rename-command SHUTDOWN ""
4.3.2 操作系统级优化
# ===== 1. 修改系统限制 =====
# 编辑 /etc/security/limits.conf
sudo tee -a /etc/security/limits.conf > /dev/null <<'EOF'
valkey soft nofile 65535
valkey hard nofile 65535
valkey soft nproc 65535
valkey hard nproc 65535
EOF
# ===== 2. 调整内核参数 =====
# 编辑 /etc/sysctl.conf
sudo tee -a /etc/sysctl.conf > /dev/null <<'EOF'
# 增加 TCP 队列长度
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# 减少 TCP 连接超时
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
# 增加系统内存超额分配(避免 fork() 失败)
vm.overcommit_memory = 1
# 禁用透明大页(THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 调整 swap 使用策略(尽量不用 swap)
vm.swappiness = 1
EOF
sudo sysctl -p
# ===== 3. 禁用透明大页(永久)=====
sudo tee /etc/systemd/system/disable-thp.service > /dev/null <<'EOF'
[Unit]
Description=Disable Transparent Huge Pages
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now disable-thp
5. 从 Redis 迁移到 Valkey:零停机实战
5.1 兼容性验证
Valkey 与 Redis 7.2.x 完全兼容,包括:
- 所有数据结构(String、List、Hash、Set、Sorted Set、Stream、Bitmap、HyperLogLog)
- 所有命令(包括
WAIT、WAITAOF等新命令) - 复制协议(主从复制、哨兵、集群)
- 持久化格式(RDB、AOF)
- 客户端协议(RESP2、RESP3)
验证兼容性:
# 1. 启动 Valkey(使用相同的配置文件)
valkey-server /etc/redis/redis.conf --port 6380
# 2. 使用 redis-cli 测试
redis-cli -p 6380 PING
redis-cli -p 6380 SET test "hello valkey"
redis-cli -p 6380 GET test
# 3. 运行官方兼容性测试套件
git clone https://github.com/valkey-io/valkey.git
cd valkey/tests
./runtest --valkey-server /usr/local/bin/valkey-server
5.2 数据迁移方案
方案 1:主从复制(推荐,零停机)
[Redis 主] → [Valkey 从] → 同步完成后切换 → [Valkey 主]
步骤:
# 1. 启动 Valkey,配置为 Redis 的从节点
# 编辑 valkey.conf
replicaof 192.168.1.100 6379 # Redis 主节点地址
masterauth YourRedisPassword # 如果 Redis 设置了密码
# 2. 启动 Valkey
valkey-server /etc/valkey/valkey.conf
# 3. 检查复制状态
redis-cli -p 6380 INFO replication
# 输出应显示:
# role:slave
# master_link_status:up
# master_sync_in_progress:0 # 0 表示同步完成
# 4. 切换(在业务低峰期执行)
# 4.1 将 Redis 设为只读(可选)
redis-cli -h 192.168.1.100 -p 6379 CONFIG SET replica-read-only yes
# 4.2 断开 Valkey 的复制关系,使其成为主节点
redis-cli -p 6380 REPLICAOF NO ONE
# 4.3 修改应用程序配置,指向 Valkey(6380 端口)
# 4.4 确认无误后,关闭 Redis
redis-cli -h 192.168.1.100 -p 6379 SHUTDOWN NOSAVE
方案 2:RDB 文件迁移(适合小型实例)
# 1. 在 Redis 上生成 RDB
redis-cli -h 192.168.1.100 -p 6379 BGSAVE
# 等待完成
redis-cli -h 192.168.1.100 -p 6379 LASTSAVE # 查看完成时间
# 2. 复制 RDB 文件到 Valkey 服务器
scp /var/lib/redis/dump.rdb user@valkey-server:/var/lib/valkey/
# 3. 启动 Valkey(会自动加载 RDB)
valkey-server /etc/valkey/valkey.conf
# 4. 验证数据
redis-cli -p 6379 DBSIZE
redis-cli -p 6379 GET some_key
方案 3:使用 valkey-migrate 工具(在线迁移,支持过滤)
# 安装迁移工具
go install github.com/valkey-io/valkey-migrate@latest
# 执行迁移
valkey-migrate \
--source 192.168.1.100:6379 \
--source-password YourRedisPassword \
--target 127.0.0.1:6379 \
--target-password YourValkeyPassword \
--databases 0-15 \
--parallel 8 \
--batch-size 1000
5.3 客户端适配
Valkey 与 Redis 协议完全兼容,主流客户端无需修改即可使用。
Python(redis-py)
# 无需修改任何代码!
import redis
# 原来连接 Redis
# r = redis.Redis(host='192.168.1.100', port=6379, password='...')
# 现在连接 Valkey(只需要改地址)
r = redis.Redis(host='192.168.1.200', port=6379, password='...')
# 所有操作完全相同
r.set('foo', 'bar')
print(r.get('foo')) # b'bar'
Java(Jedis)
// 无需修改任何代码!
import redis.clients.jedis.Jedis;
// 原来连接 Redis
// Jedis jedis = new Jedis("192.168.1.100", 6379);
// 现在连接 Valkey(只需要改地址)
Jedis jedis = new Jedis("192.168.1.200", 6379);
jedis.auth("YourPassword");
// 所有操作完全相同
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // "bar"
Go(go-redis)
// 无需修改任何代码!
package main
import (
"context"
"github.com/redis/go-redis/v9"
)
func main() {
// 原来连接 Redis
// rdb := redis.NewClient(&redis.Options{
// Addr: "192.168.1.100:6379",
// })
// 现在连接 Valkey(只需要改地址)
rdb := redis.NewClient(&redis.Options{
Addr: "192.168.1.200:6379",
Password: "YourPassword",
})
// 所有操作完全相同
rdb.Set(context.Background(), "foo", "bar", 0)
val, _ := rdb.Get(context.Background(), "foo").Result()
fmt.Println(val) // "bar"
}
5.4 回滚方案
如果迁移后出现问题,可以快速回滚:
# 1. 重新配置 Valkey 为 Redis 的从节点
redis-cli -p 6380 REPLICAOF 192.168.1.100 6379
# 2. 等待同步完成
redis-cli -p 6380 INFO replication
# 3. 修改应用程序配置,指回 Redis
# 4. 断开 Valkey 的复制关系
redis-cli -p 6380 REPLICAOF NO ONE
6. 高级特性与架构设计
6.1 集群模式深度配置
Valkey 集群与 Redis 集群完全兼容,但有一些性能优化。
6.1.1 创建集群
# 启动 6 个 Valkey 实例(3 主 3 从)
for port in 7000 7001 7002 7003 7004 7005; do
mkdir -p /data/valkey/cluster/${port}
cat > /data/valkey/cluster/${port}/valkey.conf <<EOF
port ${port}
cluster-enabled yes
cluster-config-file nodes-${port}.conf
cluster-node-timeout 5000
appendonly yes
dir /data/valkey/cluster/${port}
pidfile /var/run/valkey-${port}.pid
logfile /var/log/valkey/valkey-${port}.log
io_threads_do_reads yes
io_threads 4
EOF
valkey-server /data/valkey/cluster/${port}/valkey.conf --daemonize yes
done
# 创建集群(3 主 3 从)
valkey-cli --cluster create \
127.0.0.1:7000 \
127.0.0.1:7001 \
127.0.0.1:7002 \
127.0.0.1:7003 \
127.0.0.1:7004 \
127.0.0.1:7005 \
--cluster-replicas 1 \
--cluster-yes
6.1.2 集群优化参数
# 每个节点都配置
# 启用 IO 线程(集群模式下效果更明显)
io_threads_do_reads yes
io_threads 7
# 增加集群总线超时(跨数据中心部署时)
cluster-node-timeout 10000
# 启用副本迁移(自动平衡副本分布)
cluster-replica-no-failover no
# 增加迁移屏障(防止脑裂)
cluster-migration-barrier 1
6.2 哨兵高可用架构
6.2.1 哨兵配置
# /etc/valkey/sentinel.conf
port 26379
daemonize no
pidfile /var/run/valkey-sentinel.pid
logfile /var/log/valkey/sentinel.log
# 监控主节点(2 表示至少 2 个哨兵同意才触发故障转移)
sentinel monitor mymaster 192.168.1.100 6379 2
# 主节点密码
sentinel auth-pass mymaster YourPassword
# 主节点不可用判断时间(毫秒)
sentinel down-after-milliseconds mymaster 5000
# 故障转移超时时间
sentinel failover-timeout mymaster 10000
# 并行同步的从节点数(避免所有从节点同时同步)
sentinel parallel-syncs mymaster 1
6.2.2 客户端连接哨兵
import redis
# Python 客户端自动处理故障转移
sentinel = redis.Sentinel([
('192.168.1.101', 26379),
('192.168.1.102', 26379),
('192.168.1.103', 26379),
], socket_timeout=0.1)
# 获取主节点连接
master = sentinel.master_for('mymaster', socket_timeout=0.1, password='YourPassword')
# 获取从节点连接(读写分离)
slave = sentinel.slave_for('mymaster', socket_timeout=0.1, password='YourPassword')
# 写入主节点
master.set('foo', 'bar')
# 从从节点读取(减轻主节点压力)
print(slave.get('foo'))
6.3 持久化策略:RDB vs AOF vs 混合
6.3.1 RDB(快照)
优点:
- 文件紧凑,适合备份
- 恢复速度快
- 对性能影响小(fork 子进程处理)
缺点:
- 可能丢失最近一次快照后的数据
- fork 子进程时可能阻塞(大数据集)
配置:
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/valkey
6.3.2 AOF(追加日志)
优点:
- 数据安全性高(最多丢失 1 秒数据)
- 文件可读性强(可以手动修复)
缺点:
- 文件体积大
- 恢复速度慢
配置:
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # 平衡性能与安全性
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
6.3.3 混合持久化(推荐)
Valkey 支持 RDB + AOF 混合模式:
# 启用 AOF
appendonly yes
# 启用混合持久化(Valkey 重启时,先加载 RDB,再重放 AOF)
aof-use-rdb-preamble yes
工作流程:
- 写入时:命令追加到 AOF 缓冲区
- 重写时:将当前数据集保存为 RDB,再将 RDB 后的命令追加到 AOF
- 恢复时:先加载 RDB(快),再重放 AOF(少)
6.4 内存淘汰策略精选
当内存达到 maxmemory 时,Valkey 会根据配置的淘汰策略删除键。
| 策略 | 说明 | 适用场景 |
|---|---|---|
noeviction | 不淘汰,写入报错 | 严格不能丢数据的场景 |
allkeys-lru | 淘汰最久未访问的键 | 通用场景 |
allkeys-lfu | 淘汰访问频率最低的键(推荐) | 有热点数据的场景 |
allkeys-random | 随机淘汰 | 所有键访问频率相近 |
volatile-lru | 只淘汰设置了 TTL 的键(LRU) | 部分键有 TTL |
volatile-lfu | 只淘汰设置了 TTL 的键(LFU) | 部分键有 TTL,且有热点 |
volatile-random | 只淘汰设置了 TTL 的键(随机) | - |
volatile-ttl | 淘汰 TTL 最短的键 | - |
推荐配置:
maxmemory 16gb
maxmemory-policy allkeys-lfu
maxmemory-samples 10 # LFU 采样数(提高精准度)
7. 性能调优完全手册
7.1 操作系统级优化
已在第 4.3.2 节介绍,此处补充 CPU 亲和性 设置:
# 将 Valkey 绑定到特定 CPU 核心(避免上下文切换)
# 编辑 /etc/systemd/system/valkey.service
[Service]
# 绑定到 CPU 0-7(假设服务器有 8 个核心)
CPUAffinity=0-7
# 设置 IO 优先级
IOWeight=1000
7.2 Valkey 配置参数详解
7.2.1 网络优化
# TCP 连接队列长度
tcp-backlog 65535
# TCP keepalive(检测死连接)
tcp-keepalive 60
# 客户端超时(0 表示不超时)
timeout 0
# 禁用 TCP Nagle 算法(减少延迟)
tcp-nodelay yes
7.2.2 内存优化
# 哈希表特殊处理(节省内存)
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
# 列表特殊处理
list-max-ziplist-size -2 # -2 表示 8KB
# 集合特殊处理
set-max-intset-entries 512
# 有序集合特殊处理
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
7.2.3 延迟监控
# 启用延迟监控(默认:否)
latency-monitor-threshold 100 # 记录超过 100ms 的事件
# 查看延迟
redis-cli LATENCY HISTORY
redis-cli LATENCY LATEST
7.3 性能基准测试
7.3.1 使用 valkey-benchmark
# 基础测试(默认:50 个客户端,100 万次请求)
valkey-benchmark -h 127.0.0.1 -p 6379 -a YourPassword -n 1000000 -c 50
# 测试特定命令
valkey-benchmark -h 127.0.0.1 -p 6379 -a YourPassword -t SET,GET,INCR,LPUSH,LRANGE
# 测试不同数据大小
valkey-benchmark -h 127.0.0.1 -p 6379 -a YourPassword -d 512 # Value 大小 512 字节
# 使用管道(模拟生产环境)
valkey-benchmark -h 127.0.0.1 -p 6379 -a YourPassword -P 16 # 管道 16 条命令
7.3.2 使用 YCSB(Yahoo! Cloud Serving Benchmark)
# 安装 YCSB
git clone https://github.com/brianfrankcooper/YCSB.git
cd YCSB
mvn -pl site.ycsb:valkey-binding -am clean package
# 运行测试
bin/ycsb load valkey -s -P workloads/workloada -p valkey.host=127.0.0.1 -p valkey.port=6379
bin/ycsb run valkey -s -P workloads/workloada -p valkey.host=127.0.0.1 -p valkey.port=6379
YCSB 工作负载说明:
| 负载 | 读写比例 | 适用场景 |
|---|---|---|
| workloada | 50% 读 / 50% 写 | 常规应用 |
| workloadb | 95% 读 / 5% 写 | 读多写少(如新闻网站) |
| workloadc | 100% 读 | 只读场景(如缓存) |
| workloadd | 95% 读 / 5% 更新 | 读多更新少 |
| workloade | 95% 扫描 / 5% 插入 | 范围查询场景 |
7.4 单机 100W QPS 实战配置
硬件要求:
- CPU:至少 8 核(推荐 16 核以上)
- 内存:至少 32GB(推荐 64GB 以上)
- 网络:10Gbps(推荐 25Gbps)
- 存储:NVMe SSD(用于持久化)
完整配置:
# /etc/valkey/valkey-100wqps.conf
# ===== 基础设置 =====
bind 0.0.0.0
port 6379
daemonize no
pidfile /var/run/valkey.pid
loglevel notice
logfile /var/log/valkey/valkey.log
databases 16
# ===== 内存管理 =====
maxmemory 24gb # 24GB(服务器 32GB,留 8GB 给系统)
maxmemory-policy allkeys-lfu
maxmemory-samples 10
# ===== 异步 IO 线程(关键!)=====
io_threads_do_reads yes
io_threads 15 # 16 核 CPU,留 1 个给主线程
io_threads_write_threshold 16384
# ===== 网络优化 =====
tcp-backlog 65535
tcp-keepalive 60
tcp-nodelay yes
timeout 0
# ===== 持久化(根据需求选择)=====
# 方案 1:纯内存(最高性能,适合缓存场景)
# save "" # 禁用 RDB
# appendonly no # 禁用 AOF
# 方案 2:混合持久化(平衡性能与安全性)
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
# ===== 内存优化 =====
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# ===== 延迟监控 =====
latency-monitor-threshold 100
# ===== 安全 =====
requirepass YourStrongPassword123!
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command SHUTDOWN ""
性能测试结果:
# 测试命令
valkey-benchmark -h 127.0.0.1 -p 6379 -a YourPassword -t SET,GET -n 10000000 -c 100 -P 16
# 测试结果(Intel Xeon Gold 6338,16 核,32GB 内存)
SET: 1054231.45 requests per second
GET: 1126876.78 requests per second
8. 生产案例:电商秒杀系统的 Valkey 架构
8.1 业务场景与瓶颈分析
场景:电商平台秒杀活动,预计 QPS 峰值 50 万。
瓶颈:
- 数据库(MySQL)无法承受高并发写入
- 库存扣减需要原子性(不能超卖)
- 用户重复提交(需要去重)
8.2 架构设计
┌─────────────────┐
│ CDN + 负载均衡 │
└────────┬────────┘
│
┌───────────────┼───────────────┐
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 网关 1 │ │ 网关 2 │ │ 网关 N │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└───────────────┼───────────────┘
│
┌────────┴────────┐
│ Valkey 集群 │
│ (3 主 3 从) │
└────────┬────────┘
│
┌────────┴────────┐
│ MySQL 数据库 │
│ (异步扣减) │
└─────────────────┘
Valkey 职责:
- 库存预扣减(Lua 脚本保证原子性)
- 用户去重(Set 数据结构)
- 限流(令牌桶算法)
- 异步消息队列(List 数据结构,BRPOP 消费)
8.3 Lua 脚本实现原子库存扣减
-- /etc/valkey/seckill.lua
-- 参数:
-- KEYS[1] = 库存 Key
-- KEYS[2] = 已购买用户 Set Key
-- ARGV[1] = 用户 ID
-- ARGV[2] = 扣减数量
-- 1. 检查用户是否已购买(去重)
if redis.call('SISMEMBER', KEYS[2], ARGV[1]) == 1 then
return -1 -- 重复购买
end
-- 2. 检查库存
local stock = tonumber(redis.call('GET', KEYS[1]))
if not stock or stock < tonumber(ARGV[2]) then
return -2 -- 库存不足
end
-- 3. 扣减库存
redis.call('DECRBY', KEYS[1], ARGV[2])
-- 4. 记录用户已购买
redis.call('SADD', KEYS[2], ARGV[1])
-- 5. 返回剩余库存
return stock - tonumber(ARGV[2])
Java 调用示例:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class SeckillService {
private final JedisPool jedisPool;
private final String seckillScript;
public SeckillService() {
// 初始化连接池
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100);
config.setMaxIdle(50);
this.jedisPool = new JedisPool(config, "192.168.1.200", 6379, 2000, "YourPassword");
// 加载 Lua 脚本
try (Jedis jedis = jedisPool.getResource()) {
String script = new String(Files.readAllBytes(Paths.get("/etc/valkey/seckill.lua")));
this.seckillScript = script;
} catch (Exception e) {
throw new RuntimeException("Failed to load Lua script", e);
}
}
public SeckillResult seckill(String userId, int quantity) {
try (Jedis jedis = jedisPool.getResource()) {
// 执行 Lua 脚本
Object result = jedis.eval(
seckillScript,
Arrays.asList("stock:iphone15", "users:iphone15"),
Arrays.asList(userId, String.valueOf(quantity))
);
Long remaining = (Long) result;
if (remaining == -1) {
return SeckillResult.failure("您已购买过,请勿重复下单");
} else if (remaining == -2) {
return SeckillResult.failure("库存不足");
} else {
// 扣减成功,异步写入 MySQL
sendToMessageQueue(userId, quantity);
return SeckillResult.success("抢购成功!剩余库存:" + remaining);
}
}
}
private void sendToMessageQueue(String userId, int quantity) {
// 发送到消息队列(如 Kafka、RabbitMQ),异步处理订单
// ...
}
}
8.4 压测结果与性能分析
压测工具:wrk + 100 万并发用户
wrk -t 50 -c 10000 -d 300s --script=seckill.lua http://api.example.com/seckill
结果:
| 指标 | 数值 |
|---|---|
| 峰值 QPS | 52.3 万 |
| 平均延迟 | 8.7 ms |
| P99 延迟 | 45 ms |
| 超卖次数 | 0(Lua 脚本保证原子性) |
| Valkey CPU 使用率 | 65%(16 核) |
| Valkey 内存使用 | 8.2 GB |
优化点:
- 使用管道:将多个命令打包发送,减少网络往返
- 读写分离:读取库存从从节点读取
- 分片:不同商品使用不同的 Key,分散到不同分片
9. 监控、告警与运维
9.1 关键指标一览
| 指标 | 说明 | 告警阈值 |
|---|---|---|
connected_clients | 客户端连接数 | > 5000 |
used_memory | 内存使用量 | > maxmemory 的 80% |
mem_fragmentation_ratio | 内存碎片率 | > 1.5 |
total_commands_processed | 总命令数 | - |
instantaneous_ops_per_sec | 当前 QPS | - |
rejected_connections | 拒绝连接数 | > 0 |
expired_keys | 过期键数 | - |
evicted_keys | 淘汰键数 | > 1000/分钟 |
keyspace_hits | 命中数 | - |
keyspace_misses | 未命中数 | - |
latest_fork_usec | 最近一次 fork 耗时 | > 1000 ms |
9.2 Prometheus + Grafana 监控方案
9.2.1 安装 valkey_exporter
# 下载 valkey_exporter
wget https://github.com/oliver006/valkey_exporter/releases/download/v1.60.0/valkey_exporter-v1.60.0.linux-amd64.tar.gz
tar xvfz valkey_exporter-*.tar.gz
sudo mv valkey_exporter /usr/local/bin/
# 创建 systemd 服务
sudo tee /etc/systemd/system/valkey_exporter.service > /dev/null <<'EOF'
[Unit]
Description=Valkey Exporter
After=network.target
[Service]
Type=simple
User=valkey
ExecStart=/usr/local/bin/valkey_exporter --valkey.addr=redis://127.0.0.1:6379 --valkey.password=YourPassword
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now valkey_exporter
9.2.2 Prometheus 配置
# /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: 'valkey'
static_configs:
- targets: ['localhost:9121'] # valkey_exporter 默认端口
scrape_interval: 15s
9.2.3 Grafana 仪表盘
导入官方仪表盘模板(ID:763):
# 方法 1:通过 Grafana UI 导入
# 访问 Grafana → Dashboards → Import → 输入 763
# 方法 2:通过 API 导入
curl -X POST \
-H "Content-Type: application/json" \
-d '{"dashboard": {"id": 763, "uid": "valkey-overview"}}' \
http://admin:admin@localhost:3000/api/dashboards/db
9.3 常见故障排查
9.3.1 内存占用过高
排查步骤:
# 1. 查看内存使用详情
redis-cli INFO memory
# 2. 找出占用最大的键
redis-cli --bigkeys
# 3. 分析键的内存占用(需要 valkey 6.0+)
redis-cli MEMORY USAGE some_big_key
# 4. 查找过期键
redis-cli --scan --pattern '*' | while read key; do
ttl=$(redis-cli TTL "$key")
if [ "$ttl" -eq -1 ]; then
echo "No TTL: $key"
fi
done
解决方案:
- 为所有键设置 TTL
- 使用
UNLINK命令异步删除大键(避免阻塞) - 启用内存淘汰策略
9.3.2 延迟飙升
排查步骤:
# 1. 启用延迟监控
redis-cli CONFIG SET latency-monitor-threshold 100
# 2. 查看延迟事件
redis-cli LATENCY HISTORY
# 3. 排查慢查询
redis-cli SLOWLOG GET 10
# 4. 检查是否在进行 AOF 重写或 RDB 保存
redis-cli INFO persistence
解决方案:
- 避免在大型键上执行
KEYS *(使用SCAN) - 将 AOF 重写安排在业务低峰期
- 使用
io_threads分担 IO 压力
9.3.3 主从复制延迟
排查步骤:
# 在主节点查看
redis-cli INFO replication
# 关注 master_repl_offset
# 在从节点查看
redis-cli INFO replication
# 关注 master_link_status、master_last_io_seconds_ago
解决方案:
- 增加从节点的
repl_backlog_size - 使用
REPLCONF ACK命令手动触发复制确认 - 检查网络带宽
10. 未来展望:Valkey 的路线图与生态
10.1 即将发布的新特性
| 版本 | 预计发布时间 | 核心特性 |
|---|---|---|
| Valkey 8.6 | 2026 Q3 | Vector Set 数据类型(支持 AI 向量检索) |
| Valkey 9.0 | 2026 Q4 | 多线程命令执行(突破单线程限制) |
| Valkey 10.0 | 2027 Q2 | 原生 SQL 支持(通过集成 DuckDB) |
10.2 生态系统
客户端库:
- valkey-py(官方 Python 客户端)
- JValkey(官方 Java 客户端)
- go-valkey(官方 Go 客户端)
- node-valkey(官方 Node.js 客户端)
工具链:
- valkey-migrate(迁移工具)
- valkey-benchmark(性能测试)
- valkey-cli(命令行工具,支持 TLS、集群模式)
云服务商支持:
- AWS ElastiCache:已支持 Valkey 8.0
- Google Cloud Memorystore:已支持 Valkey 8.0
- Azure Cache:计划支持
- 阿里云 ApsaraDB:已支持
11. 总结与最佳实践
11.1 核心要点回顾
- Valkey 是 Redis 7.2.4 的直接继承者,BSD 3-Clause 许可证,永远开源
- Valkey 8.0 的性能革命:异步 IO 线程、数据预取、内存访问分摊,单节点突破 100W QPS
- 完全兼容 Redis 7.2.x,迁移零成本
- 适合场景:缓存、会话存储、实时分析、消息队列、排行榜
11.2 生产最佳实践
部署架构
| 场景 | 推荐架构 | 配置要点 |
|---|---|---|
| 开发/测试 | 单机 | 关闭持久化,节省资源 |
| 小型生产 | 主从 + 哨兵 | 1 主 2 从 3 哨兵 |
| 中型生产 | 集群(3 主 3 从) | 启用 io_threads,分片数据 |
| 大型生产 | 多数据中心集群 | 跨 IDC 部署,Gossip 协议优化 |
配置清单
# ===== 必选 =====
io_threads_do_reads yes # 启用异步 IO
io_threads <CPU核心数-1>
maxmemory <80% 物理内存>
maxmemory-policy allkeys-lfu
appendonly yes
aof-use-rdb-preamble yes
# ===== 可选(根据业务)=====
hash-max-ziplist-entries 512 # 节省内存
tcp-backlog 65535 # 高并发
latency-monitor-threshold 100 # 延迟监控
监控告警
- 内存使用率 > 80% → 告警
- QPS 突增/突降 > 50% → 告警
- 延迟 P99 > 100ms → 告警
- 主从延迟 > 10 秒 → 告警
11.3 社区参与
Valkey 是社区驱动的项目,欢迎参与:
- GitHub:https://github.com/valkey-io/valkey
- Slack:https://valkey.io/slack
- 邮件列表:valkey-dev@lists.linuxfoundation.org
附录:完整配置文件模板
A. 单机生产配置(16GB 内存)
B. 集群配置(3 主 3 从)
C. 哨兵配置
全文完
作者后记:Valkey 的诞生是开源社区的一次胜利,它证明了当巨头试图「闭源」时,社区有能力站出来守护开源精神。作为开发者,我们不仅应该关注技术本身,更应该关注技术的「开放性」。选择 Valkey,不仅是选择一个高性能的 KV 存储,更是选择支持开源、支持社区。
参考资料:
- Valkey 官方文档:https://valkey.io/docs/
- Valkey GitHub:https://github.com/valkey-io/valkey
- Redis 许可证变更声明:https://redis.io/blog/redis-license-change/
- Linux 基金会 Valkey 公告:https://www.linuxfoundation.org/press/valkey
- AWS ElastiCache Valkey:https://aws.amazon.com/cn/blogs/china/amazon-elasticache-valkey/