编程 Valkey 深度实战:当 Redis 遇上「开源觉醒」——从许可证风暴到每秒 100 万次请求的生产级完全指南(2026)

2026-06-14 22:47:13 +0800 CST views 6

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 的性能压榨全过程。


目录

  1. 许可证风暴:Redis 为何失去开源地位
  2. Valkey 的诞生:社区的反击与承诺
  3. 核心技术深度解析: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. 生产级安装与配置:多平台实战
    • 4.1 Linux(生产推荐)
    • 4.2 Docker / Kubernetes 部署
    • 4.3 配置调优:榨干每一滴性能
  5. 从 Redis 迁移到 Valkey:零停机实战
    • 5.1 兼容性验证
    • 5.2 数据迁移方案
    • 5.3 客户端适配
    • 5.4 回滚方案
  6. 高级特性与架构设计
    • 6.1 集群模式深度配置
    • 6.2 哨兵高可用架构
    • 6.3 持久化策略:RDB vs AOF vs 混合
    • 6.4 内存淘汰策略精选
  7. 性能调优完全手册
    • 7.1 操作系统级优化
    • 7.2 Valkey 配置参数详解
    • 7.3 性能基准测试(YCSB + redis-benchmark)
    • 7.4 单机 100W QPS 实战配置
  8. 生产案例:电商秒杀系统的 Valkey 架构
    • 8.1 业务场景与瓶颈分析
    • 8.2 架构设计
    • 8.3 Lua 脚本实现原子库存扣减
    • 8.4 压测结果与性能分析
  9. 监控、告警与运维
    • 9.1 关键指标一览
    • 9.2 Prometheus + Grafana 监控方案
    • 9.3 常见故障排查
  10. 未来展望:Valkey 的路线图与生态
  11. 总结与最佳实践

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)

核心承诺

  1. 永远 BSD 3-Clause:永不更改许可证
  2. 完全兼容 Redis 7.2.x:零代码修改迁移
  3. 社区治理:Linux 基金会托管,开放治理
  4. 持续创新:在兼容基础上做性能增强

2.2 版本路线图

版本发布时间核心特性
Valkey 7.2.52024.06与 Redis 7.2.4 完全兼容,Bug 修复
Valkey 7.2.62024.09性能优化,内存碎片优化
Valkey 8.0.02025.03异步 IO 线程、数据预取、内存访问分摊
Valkey 8.0.12025.06Bug 修复,稳定性提升
Valkey 8.2.02026.01集群模式增强,新命令支持
Valkey 8.4.02026.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   │
       │ (读写网络)   │   │ (读写网络)   │   │ (读写网络)   │
       └─────────────┘   └─────────────┘   └─────────────┘

工作流程

  1. IO 线程:负责 read() 客户端请求、write() 响应
  2. 主线程:负责命令解析和执行
  3. 无锁队列: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 引入了数据预取机制:

原理

  1. 在解析命令时,提前将可能访问的数据预先加载到 CPU L1/L2 Cache
  2. 使用 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.2Redis 8.0Valkey 8.0Valkey 提升
SET18.5 W/s19.2 W/s105.3 W/s5.7x
GET21.3 W/s22.1 W/s112.7 W/s5.3x
INCR16.8 W/s17.5 W/s98.4 W/s5.9x
LPUSH19.2 W/s20.1 W/s108.9 W/s5.7x
LRANGE (100)3.2 W/s3.3 W/s12.8 W/s4.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)
  • 所有命令(包括 WAITWAITAOF 等新命令)
  • 复制协议(主从复制、哨兵、集群)
  • 持久化格式(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

工作流程

  1. 写入时:命令追加到 AOF 缓冲区
  2. 重写时:将当前数据集保存为 RDB,再将 RDB 后的命令追加到 AOF
  3. 恢复时:先加载 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 工作负载说明

负载读写比例适用场景
workloada50% 读 / 50% 写常规应用
workloadb95% 读 / 5% 写读多写少(如新闻网站)
workloadc100% 读只读场景(如缓存)
workloadd95% 读 / 5% 更新读多更新少
workloade95% 扫描 / 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 万

瓶颈

  1. 数据库(MySQL)无法承受高并发写入
  2. 库存扣减需要原子性(不能超卖)
  3. 用户重复提交(需要去重)

8.2 架构设计

                     ┌─────────────────┐
                     │   CDN + 负载均衡 │
                     └────────┬────────┘
                              │
              ┌───────────────┼───────────────┐
              ↓               ↓               ↓
        ┌─────────┐    ┌─────────┐    ┌─────────┐
        │ 网关 1  │    │ 网关 2  │    │ 网关 N  │
        └────┬────┘    └────┬────┘    └────┬────┘
             │               │               │
             └───────────────┼───────────────┘
                             │
                    ┌────────┴────────┐
                    │   Valkey 集群   │
                    │  (3 主 3 从)   │
                    └────────┬────────┘
                             │
                    ┌────────┴────────┐
                    │   MySQL 数据库  │
                    │  (异步扣减)     │
                    └─────────────────┘

Valkey 职责

  1. 库存预扣减(Lua 脚本保证原子性)
  2. 用户去重(Set 数据结构)
  3. 限流(令牌桶算法)
  4. 异步消息队列(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

结果

指标数值
峰值 QPS52.3 万
平均延迟8.7 ms
P99 延迟45 ms
超卖次数0(Lua 脚本保证原子性)
Valkey CPU 使用率65%(16 核)
Valkey 内存使用8.2 GB

优化点

  1. 使用管道:将多个命令打包发送,减少网络往返
  2. 读写分离:读取库存从从节点读取
  3. 分片:不同商品使用不同的 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.62026 Q3Vector Set 数据类型(支持 AI 向量检索)
Valkey 9.02026 Q4多线程命令执行(突破单线程限制)
Valkey 10.02027 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 核心要点回顾

  1. Valkey 是 Redis 7.2.4 的直接继承者,BSD 3-Clause 许可证,永远开源
  2. Valkey 8.0 的性能革命:异步 IO 线程、数据预取、内存访问分摊,单节点突破 100W QPS
  3. 完全兼容 Redis 7.2.x,迁移零成本
  4. 适合场景:缓存、会话存储、实时分析、消息队列、排行榜

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 内存)

GitHub Gist

B. 集群配置(3 主 3 从)

GitHub Gist

C. 哨兵配置

GitHub Gist


全文完

作者后记:Valkey 的诞生是开源社区的一次胜利,它证明了当巨头试图「闭源」时,社区有能力站出来守护开源精神。作为开发者,我们不仅应该关注技术本身,更应该关注技术的「开放性」。选择 Valkey,不仅是选择一个高性能的 KV 存储,更是选择支持开源、支持社区。


参考资料

  1. Valkey 官方文档:https://valkey.io/docs/
  2. Valkey GitHub:https://github.com/valkey-io/valkey
  3. Redis 许可证变更声明:https://redis.io/blog/redis-license-change/
  4. Linux 基金会 Valkey 公告:https://www.linuxfoundation.org/press/valkey
  5. AWS ElastiCache Valkey:https://aws.amazon.com/cn/blogs/china/amazon-elasticache-valkey/

推荐文章

PHP来做一个短网址(短链接)服务
2024-11-17 22:18:37 +0800 CST
MySQL 优化利剑 EXPLAIN
2024-11-19 00:43:21 +0800 CST
阿里云免sdk发送短信代码
2025-01-01 12:22:14 +0800 CST
如何在Vue 3中使用Ref访问DOM元素
2024-11-17 04:22:38 +0800 CST
介绍Vue3的静态提升是什么?
2024-11-18 10:25:10 +0800 CST
程序员茄子在线接单