编程 Redis 8 vs Valkey 深度拆解:当开源内存数据库决定「分家」——从 BSD 到 AGPL,一个 12K Star 的 Linux Foundation 分支如何用向量搜索和语义缓存重新定义缓存基础设施的终极形态

2026-08-05 11:50:16 +0800 CST views 6

Redis 8 vs Valkey 深度拆解:当开源内存数据库决定「分家」——从 BSD 到 AGPL,一个 12K Star 的 Linux Foundation 分支如何用向量搜索和语义缓存重新定义缓存基础设施的终极形态

引言:一场改变内存数据库格局的许可证战争

2024年3月,内存数据库领域发生了一件大事:Linux Foundation 宣布成立 Valkey 项目,作为 Redis 7.2.4 的开源分支。这不是一次普通的 fork——它标志着一个运行了15年的开源项目,在许可证变更的风暴中,走上了两条截然不同的道路。

与此同时,Redis 的创始人 Salvatore "antirez" Sanfilippo 回归,亲自操刀 Redis 8 系列的向量搜索和语义缓存功能。一年内连续发布四个主要版本(8.0→8.2→8.4→8.6),吞吐量提升5倍,延迟降低87%。

2026年8月,Redis 8.10.0 正式发布。Valkey 9.0 也在稳步推进。两个项目从同一个代码库出发,正在快速分化。

如果你还在纠结选 Redis 还是 Valkey,这篇文章会给你一个清晰的答案。

本文将从许可证与治理、架构分化、性能基准、数据模型对比、AI 能力差距、迁移策略六个维度,深度拆解这场内存数据库的"分家"。


第一章:许可证战争——BSD vs AGPL 的生死抉择

1.1 Redis 的许可证演变

Redis 的许可证变更是一场持续两年的"渐进式封闭":

时间版本许可证影响
2009-2024.021.0 → 7.2.xBSD 3-Clause完全开源,无限制
2024.037.4.xRSALv2 + SSPLv1(双许可)商用需付费,云厂商被针对
2025.058.0RSALv2 + SSPLv1 + AGPLv3(三许可)新增 AGPL 选项,但有传染性

关键条款解读

# RSALv2 限制条款(禁止云服务商提供托管服务)
# SSPLv1 要求:如果提供 SaaS 服务,必须开源整个服务栈
# AGPLv3 要求:如果修改 Redis 并通过网络提供服务,必须开源修改部分

# 简单说:你不能基于 Redis 8 构建一个竞品云服务而不付费或开源

对开发者的实际影响

// 场景1:个人/小团队项目 —— 几乎无影响
// BSD/AGPL 对你没有约束,放心用

// 场景2:企业内部使用 —— 需要评估
// AGPLv3 要求:如果修改了 Redis 源码并通过网络提供给内部员工
// 可能需要公开修改后的源码(取决于"内部使用"的法律解释)

// 场景3:SaaS 产品 —— 必须选择
// RSALv2:禁止提供 Redis 托管服务
// AGPLv3:修改部分必须开源
// SSPLv1:整个服务栈必须开源

1.2 Valkey 的 BSD 3-Clause 理想

Valkey 从 Redis 7.2.4 fork 而来,继承了 BSD 3-Clause 许可证:

BSD 3-Clause: 你几乎可以做任何事
├── 商业使用 ✅
├── 修改和分发 ✅
├── 私有用途 ✅
├── 仅需保留版权声明 ✅
└── 无传染性条款 ✅

Linux Foundation 治理模型

Valkey 治理结构
├── Linux Foundation(托管方)
├── 多厂商贡献者委员会
│   ├── AWS(主要贡献者)
│   ├── Google Cloud
│   ├── Oracle
│   ├── Ericsson
│   └── 更多...
├── 没有单一厂商控制权
└── 许可证变更需委员会批准

这意味着:没有任何单一公司能像 Redis Inc. 那样单方面改变 Valkey 的许可证。

1.3 开发者如何选择?

选择 Redis 8 的情况:
├── 需要原生 JSON、Time Series、向量搜索等高级数据类型
├── 需要企业级支持和 SLA(Redis Cloud 99.999%)
├── 需要语义缓存(LangCache)降低 LLM 成本
├── 能接受 AGPLv3 或付费许可
└── 团队有能力评估许可证合规性

选择 Valkey 的情况:
├── 对许可证敏感,需要真正的 BSD 开源
├── 不需要 Redis 8 的高级数据类型
├── 想要多厂商治理,避免单点风险
├── 已有 Redis 7.2 工作负载,兼容性完美
└── 想参与社区贡献,影响项目方向

第二章:架构分化——从同一个起点走向不同方向

2.1 Redis 8 的架构革新

Redis 8 系列最大的变化是核心数据模型的扩展——从纯粹的键值存储变成了多模型数据库:

Redis 8 核心架构
├── 传统数据类型(兼容 Redis 7.2)
│   ├── Strings
│   ├── Lists
│   ├── Sets / Sorted Sets
│   ├── Hashes
│   └── Streams
├── 新增原生数据类型(8.0+)
│   ├── JSON(原生 JSONPath 支持)
│   ├── Time Series(时间序列)
│   ├── Vector Sets(向量集合,beta)
│   ├── Bloom Filter(布隆过滤器)
│   ├── Cuckoo Filter(布谷鸟过滤器)
│   ├── Count-Min Sketch
│   ├── Top-K
│   └── t-digest
└── Redis Search 引擎(集成在核心)
    ├── 全文搜索
    ├── 向量搜索
    ├── 混合搜索(FT.HYBRID)
    └── 聚合管道

Vector Set 实现原理

# Redis 8 Vector Set 示例:向量相似度搜索
import redis

r = redis.Redis()

# 创建向量集合
r.vadd("products", [1.0, 0.5, 0.3], "product:1")
r.vadd("products", [0.9, 0.6, 0.2], "product:2")
r.vadd("products", [0.1, 0.8, 0.9], "product:3")

# 查询最相似的2个向量
similar = r.vsim("products", [0.95, 0.55, 0.25], num=2)
print(f"最相似的产品: {similar}")
# 输出: ['product:1', 'product:2']

# 向量集合还支持集合操作
r.vunionstore("all_products", ["products:eu", "products:us"])
r.vinterstore("common", ["products:eu", "products:us"])

混合搜索(FT.HYBRID)架构

# Redis 8.4 混合搜索:全文+向量+地理+过滤 一次查询
import redis

r = redis.Redis()

# 创建混合搜索索引
r.execute_command(
    "FT.CREATE", "products_idx",
    "ON", "HASH",
    "PREFIX", "1", "product:",
    "SCHEMA",
    "name", "TEXT", "WEIGHT", "10",
    "description", "TEXT",
    "embedding", "VECTOR", "HNSW", "6",
        "TYPE", "FLOAT32", "DIM", "768",
        "DISTANCE_METRIC", "COSINE",
    "price", "NUMERIC", "SORTABLE",
    "location", "GEO"
)

# 混合查询:全文匹配 + 向量相似 + 价格过滤 + 地理范围
results = r.execute_command(
    "FT.SEARCH", "products_idx",
    "(@name:手机 OR @description:智能手机) "
    "[KNN 5 @embedding $vec AS score] "
    "@price:[1000 5000] "
    "@location:[-73.9857,40.7484,10km]",
    "PARAMS", "2", "vec", vector_bytes,
    "SORTBY", "score", "DESC",
    "LIMIT", "0", "5",
    "DIALECT", "4"
)

for doc in results[1:]:
    name = doc[1][b'name'].decode()
    score = doc[1][b'score']
    print(f"{name} - 相关度: {score}")

2.2 Valkey 9 的务实路线

Valkey 9.0 选择了更保守但更稳定的路线:

Valkey 9.0 新特性
├── 多数据库支持(集群模式)
│   └── SELECT 命令在集群模式下可用(Redis 集群一直不支持)
├── 原子槽迁移
│   └── CLUSTER SETSLOT IMPORTING/MIGRATING 改为原子操作
├── 官方模块(BSD 许可)
│   ├── Valkey JSON(基于 Redis JSON fork)
│   ├── Valkey Bloom(布隆过滤器)
│   └── Valkey Search(搜索模块)
├── 每槽位可观测性
│   └── CLUSTER INFO 返回每个槽位的详细指标
├── 实验性 RDMA 支持
│   └── 远程直接内存访问,超低延迟
└── Rust 集成进行中
    └── 核心路径用 Rust 重写以提升安全性和性能

Valkey 多数据库集群支持(Redis 一直没有的功能)

# Valkey 9.0: 集群模式下使用多个数据库
redis-cli -c -h valkey-cluster

# 在集群模式下创建多个数据库
127.0.0.1:7000> SELECT 0
OK
127.0.0.1:7000> SET db0_key "value0"
OK

127.0.0.1:7000> SELECT 1
OK
127.0.0.1:7000> SET db1_key "value1"
OK

# 这在 Redis 集群中是做不到的!
# Redis 集群只有一个数据库(db0)

原子槽迁移的优势

# 传统 Redis 集群槽迁移(非原子)
# 步骤1: CLUSTER SETSLOT 1234 MIGRATING <target-node>
# 步骤2: 逐个迁移 key(可能出现中间状态)
# 步骤3: CLUSTER SETSLOT 1234 NODE <target-node>
# 问题:步骤2期间可能出现数据不一致

# Valkey 9.0 原子槽迁移
# 一次性完成,无中间状态
CLUSTER SETSLOT 1234 ATOMIC-MIGRATE <target-node>
# 保证:要么完全迁移成功,要么完全回滚

第三章:性能基准——5倍吞吐量差距的背后

3.1 Redis 8.6 的性能数据

Redis 官方发布的基准测试:

Redis 8.6 vs 7.2 性能对比(单节点)
├── 吞吐量: 5x 提升(每秒请求数)
├── 延迟: 87% 降低(P99 延迟)
├── 内存: 92% 减少(JSON 数组场景)
├── Sorted Set: 35% 延迟降低
├── Vector Set 查询: 58% 加速
└── Sorted Set 内存: 30.5% 减少

3.2 实际基准测试代码

# Redis 8 vs Valkey 9 性能对比测试
import redis
import time
import statistics

def benchmark_set_ops(client, num_ops=100000, key_prefix="bench"):
    """测试 SET 操作性能"""
    times = []
    for i in range(num_ops):
        start = time.perf_counter()
        client.set(f"{key_prefix}:{i}", f"value_{i}")
        end = time.perf_counter()
        times.append(end - start)
    return {
        "total_time": sum(times),
        "ops_per_sec": num_ops / sum(times),
        "avg_latency_us": statistics.mean(times) * 1_000_000,
        "p99_latency_us": sorted(times)[int(len(times) * 0.99)] * 1_000_000
    }

def benchmark_pipeline(client, num_ops=100000, batch_size=100):
    """测试 Pipeline 批量操作性能"""
    pipe = client.pipeline(transaction=False)
    start = time.perf_counter()
    for i in range(num_ops):
        pipe.set(f"pipe:{i}", f"value_{i}")
        if (i + 1) % batch_size == 0:
            pipe.execute()
            pipe = client.pipeline(transaction=False)
    pipe.execute()
    end = time.perf_counter()
    return {
        "total_time": end - start,
        "ops_per_sec": num_ops / (end - start),
    }

def benchmark_hash_field_ttl(client, num_fields=10000):
    """测试 Hash 字段级 TTL(Redis 8 新特性)"""
    pipe = client.pipeline(transaction=False)
    for i in range(num_fields):
        pipe.hset("user:session", f"field_{i}", f"value_{i}")
        pipe.hexpire("user:session", 3600, f"field_{i}")  # 1小时过期
    start = time.perf_counter()
    pipe.execute()
    end = time.perf_counter()
    
    # 查询字段剩余 TTL
    start2 = time.perf_counter()
    for i in range(0, num_fields, 100):
        client.httl("user:session", f"field_{i}")
    end2 = time.perf_counter()
    
    return {
        "set_with_ttl_time": end - start,
        "httl_query_time": end2 - start2,
        "httl_ops_per_sec": (num_fields // 100) / (end2 - start2)
    }

# 运行测试
if __name__ == "__main__":
    # 连接 Redis 8
    r8 = redis.Redis(host='localhost', port=6379, db=0)
    # 连接 Valkey 9
    v9 = redis.Redis(host='localhost', port=6380, db=0)
    
    print("=== SET 操作基准 ===")
    r8_result = benchmark_set_ops(r8)
    v9_result = benchmark_set_ops(v9)
    print(f"Redis 8: {r8_result['ops_per_sec']:.0f} ops/sec, "
          f"P99: {r8_result['p99_latency_us']:.1f}μs")
    print(f"Valkey 9: {v9_result['ops_per_sec']:.0f} ops/sec, "
          f"P99: {v9_result['p99_latency_us']:.1f}μs")
    
    print("\n=== Pipeline 批量操作 ===")
    r8_pipe = benchmark_pipeline(r8)
    v9_pipe = benchmark_pipeline(v9)
    print(f"Redis 8: {r8_pipe['ops_per_sec']:.0f} ops/sec")
    print(f"Valkey 9: {v9_pipe['ops_per_sec']:.0f} ops/sec")
    
    print("\n=== Hash 字段级 TTL ===")
    r8_ttl = benchmark_hash_field_ttl(r8)
    v9_ttl = benchmark_hash_field_ttl(v9)
    print(f"Redis 8: {r8_ttl['set_with_ttl_time']:.3f}s set, "
          f"{r8_ttl['httl_ops_per_sec']:.0f} TTL ops/sec")
    print(f"Valkey 9: {v9_ttl['set_with_ttl_time']:.3f}s set, "
          f"{v9_ttl['httl_ops_per_sec']:.0f} TTL ops/sec")

3.3 向量搜索性能对比

# 向量搜索性能对比:Redis 8 Vector Set vs Valkey Search Module
import redis
import numpy as np
import time

def create_vectors(client, num_vectors=100000, dim=768):
    """批量创建向量"""
    pipe = client.pipeline(transaction=False)
    for i in range(num_vectors):
        vec = np.random.rand(dim).astype(np.float32).tobytes()
        pipe.execute_command(
            "VADD", "vectors", vec, f"doc:{i}"
        )
        if (i + 1) % 10000 == 0:
            pipe.execute()
            pipe = client.pipeline(transaction=False)
    pipe.execute()

def benchmark_vector_search(client, num_queries=1000, k=10):
    """测试向量搜索性能"""
    query = np.random.rand(768).astype(np.float32).tobytes()
    
    times = []
    for _ in range(num_queries):
        start = time.perf_counter()
        results = client.execute_command(
            "VSIM", "vectors", query, "NUM", k
        )
        end = time.perf_counter()
        times.append(end - start)
    
    return {
        "qps": num_queries / sum(times),
        "avg_latency_ms": statistics.mean(times) * 1000,
        "p95_latency_ms": sorted(times)[int(len(times) * 0.95)] * 1000,
        "p99_latency_ms": sorted(times)[int(len(times) * 0.99)] * 1000
    }

# 结果示例(实际值取决于硬件)
# Redis 8 Vector Set:
#   QPS: 12,500
#   Avg Latency: 0.08ms
#   P99 Latency: 0.15ms
#
# Valkey Search Module (HNSW):
#   QPS: 8,200
#   Avg Latency: 0.12ms
#   P99 Latency: 0.28ms

第四章:数据模型深度对比

4.1 JSON 支持对比

# Redis 8 原生 JSON
import redis

r = redis.Redis()

# Redis 8: 原生 JSON 数据类型
r.json().set("user:1", "$", {
    "name": "张三",
    "age": 30,
    "scores": [85, 92, 78],
    "address": {
        "city": "北京",
        "district": "朝阳"
    }
})

# JSONPath 查询
age = r.json().get("user:1", "$.age")  # [30]
scores = r.json().get("user:1", "$.scores[*]")  # [85, 92, 78]
city = r.json().get("user:1", "$.address.city")  # ["北京"]

# JSON 数组操作
r.json().arr_append("user:1", "$.scores", 95)
r.json().arr_pop("user:1", "$.scores", 1)

# Redis 8.4: JSON 数组内存优化(减少 92%)
# 对于大型数值数组,内存占用从 ~8 bytes/number 降到 ~0.6 bytes/number
# Valkey: 通过官方模块支持 JSON
# 需要安装 Valkey JSON 模块
import redis

r = redis.Redis()

# Valkey JSON 模块(功能与 Redis JSON 基本相同)
r.execute_command("JSON.SET", "user:2", "$", '{"name":"李四","age":25}')
name = r.execute_command("JSON.GET", "user:2", "$.name")

# 注意:Valkey JSON 是独立模块,需要单独安装和管理
# Redis 8 的 JSON 是核心内置,无需额外模块

4.2 时间序列对比

# Redis 8 原生时间序列
import redis
import time

r = redis.Redis()

# 创建时间序列
r.execute_command(
    "TS.CREATE", "sensor:temperature",
    "RETENTION", 86400000,  # 保留24小时
    "LABELS", "location", "factory_A", "unit", "celsius"
)

# 写入数据点
for i in range(1000):
    ts = int(time.time() * 1000) + i * 1000
    value = 20 + (i % 10) * 0.5
    r.execute_command("TS.ADD", "sensor:temperature", ts, value)

# 查询最近1小时的平均值
result = r.execute_command(
    "TS.RANGE", "sensor:temperature",
    "-", "+",
    "AGGREGATION", "avg", 60000  # 1分钟聚合
)

# 时间序列 + 向量搜索:异常模式检测
# 1. 提取时间序列特征向量
# 2. 在历史异常模式库中搜索相似模式
# 3. 返回最相似的异常事件

Valkey 没有原生时间序列支持,需要通过外部模块或自定义数据结构实现。

4.3 概率数据结构对比

# Redis 8 原生概率数据结构
import redis

r = redis.Redis()

# Bloom Filter:快速判断元素是否可能存在
r.execute_command("BF.RESERVE", "spam_filter", 0.001, 1000000)
r.execute_command("BF.ADD", "spam_filter", "spam@example.com")
exists = r.execute_command("BF.EXISTS", "spam_filter", "spam@example.com")  # 1
exists = r.execute_command("BF.EXISTS", "spam_filter", "good@example.com")  # 0

# Cuckoo Filter:支持删除的布隆过滤器
r.execute_command("CF.RESERVE", "session_tracker", 1000000)
r.execute_command("CF.ADD", "session_tracker", "session:abc123")
r.execute_command("CF.DEL", "session_tracker", "session:abc123")  # 支持删除!

# Count-Min Sketch:近似计数
r.execute_command("CMS.INITBYDIM", "url_counter", 1000, 5)
r.execute_command("CMS.INCRBY", "url_counter", "https://example.com", 1)
count = r.execute_command("CMS.QUERY", "url_counter", "https://example.com")

# Top-K:高频元素追踪
r.execute_command("TOPK.RESERVE", "hot_keys", 10, 5000, 4, 0.8)
r.execute_command("TOPK.ADD", "hot_keys", "key1", "key1", "key1", "key2")
top = r.execute_command("TOPK.LIST", "hot_keys")  # 返回 Top-K 元素

# t-digest:分位数估算
r.execute_command("TDIGEST.CREATE", "latency_digest")
for latency in [10, 15, 20, 25, 30, 100, 200]:
    r.execute_command("TDIGEST.ADD", "latency_digest", latency)
p99 = r.execute_command("TDIGEST.QUANTILE", "latency_digest", 0.99)

Valkey 仅通过 Valkey Bloom 模块支持 Bloom Filter,不支持 Cuckoo Filter、Count-Min Sketch、Top-K、t-digest 等。


第五章:AI 能力差距——语义缓存与混合搜索

5.1 Redis LangCache:LLM 推理成本降低15倍

# Redis 8 语义缓存:相同语义的问题只调用一次 LLM
import redis
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')
r = redis.Redis()

# 创建语义缓存索引
r.execute_command(
    "FT.CREATE", "semantic_cache",
    "ON", "HASH",
    "PREFIX", "1", "cache:",
    "SCHEMA",
    "query", "TEXT",
    "embedding", "VECTOR", "HNSW", "6",
        "TYPE", "FLOAT32", "DIM", "384",
        "DISTANCE_METRIC", "COSINE",
    "response", "TEXT",
    "ttl", "NUMERIC"
)

def semantic_search(query, threshold=0.85):
    """语义搜索缓存"""
    # 生成查询向量
    query_vec = model.encode(query).tobytes()
    
    # 在缓存中搜索语义相似的查询
    results = r.execute_command(
        "FT.SEARCH", "semantic_cache",
        f"(@embedding:[KNN 1 @embedding $vec AS score]) "
        f"@ttl:[{int(time.time())} +inf]",
        "PARAMS", "2", "vec", query_vec,
        "SORTBY", "score", "ASC",
        "LIMIT", "0", "1",
        "DIALECT", "4"
    )
    
    if results and results[1]:
        score = float(results[1][1][b'score'])
        if score >= threshold:
            # 缓存命中!直接返回
            return results[1][1][b'response'].decode()
    
    # 缓存未命中,调用 LLM
    response = call_llm(query)
    
    # 存入缓存
    r.hset(
        f"cache:{hash(query)}",
        mapping={
            "query": query,
            "response": response,
            "embedding": model.encode(query).tobytes(),
            "ttl": int(time.time()) + 3600  # 1小时过期
        }
    )
    
    return response

# 使用示例
# 用户1: "什么是向量数据库?" → 调用 LLM → 缓存
# 用户2: "向量数据库是什么?" → 语义命中 → 直接返回(省钱!)
# 用户3: "向量数据库的原理?" → 部分语义匹配 → 可能命中

5.2 Redis 8.10 新特性:增强的 AI 工具链

# Redis 8.10: 增强的向量操作和 AI 集成
import redis

r = redis.Redis()

# 1. 向量集合的批量操作
pipe = r.pipeline(transaction=False)
for i in range(10000):
    vec = generate_embedding(f"document_{i}")
    pipe.execute_command("VADD", "docs", vec, f"doc:{i}")
    if (i + 1) % 1000 == 0:
        pipe.execute()
        pipe = r.pipeline(transaction=False)
pipe.execute()

# 2. 混合搜索:向量 + 全文 + 过滤
results = r.execute_command(
    "FT.SEARCH", "docs_idx",
    "(@content:机器学习) [KNN 10 @embedding $vec AS score] @category:[AI ML]",
    "PARAMS", "2", "vec", query_vec,
    "SORTBY", "score", "DESC",
    "LIMIT", "0", "10",
    "DIALECT", "4"
)

# 3. 实时流式处理:Redis Streams + AI
# 生产者:发送用户查询
r.xadd("ai_queries", {
    "query": "帮我分析这段代码",
    "user_id": "user_123",
    "timestamp": str(time.time())
})

# 消费者:AI 服务消费查询并返回结果
while True:
    messages = r.xreadgroup(
        "ai_group", "worker_1",
        {"ai_queries": ">"}, count=1
    )
    for stream, msgs in messages:
        for msg_id, data in msgs:
            response = process_with_ai(data[b'query'])
            r.xadd("ai_responses", {
                "query_id": msg_id.decode(),
                "response": response,
                "status": "completed"
            })
            r.xack("ai_queries", "ai_group", msg_id)

5.3 Valkey 的 AI 能力差距

# Valkey: 需要通过模块实现类似功能
# 但功能和性能都明显落后

# Valkey Search 模块的向量搜索
# 需要单独安装和配置
r.execute_command(
    "FT.CREATE", "docs_idx",
    "ON", "HASH",
    "SCHEMA",
    "content", "TEXT",
    "embedding", "VECTOR", "HNSW", "6",
        "TYPE", "FLOAT32", "DIM", "768",
        "DISTANCE_METRIC", "COSINE"
)

# 但没有混合搜索(FT.HYBRID)
# 没有语义缓存(LangCache)
# 没有原生时间序列
# 没有原生概率数据结构(除 Bloom)
# 没有向量集合(Vector Set)

# Valkey 的优势:BSD 许可 + 多厂商治理
# 适合不需要高级 AI 功能的场景

第六章:迁移实战——从 Redis 7.2 到 Redis 8 或 Valkey

6.1 迁移决策树

Redis 7.2 → 迁移决策
│
├── 你需要 JSON/Time Series/向量搜索/语义缓存?
│   ├── 是 → 迁移到 Redis 8
│   │   ├── 评估许可证合规性
│   │   ├── 选择 AGPLv3 或付费许可
│   │   └── 使用 redis-shake 工具平滑迁移
│   └── 否 → 迁移到 Valkey 9
│       ├── 许可证更宽松(BSD)
│       ├── 多厂商治理,无单点风险
│       ├── 兼容性完美(基于 7.2.4)
│       └── 多数据库集群支持(Redis 没有)
│
├── 你有自定义模块?
│   ├── 是 → 评估模块兼容性
│   │   ├── Redis 8: 核心模块已内置
│   │   └── Valkey: 需要适配 Valkey 模块 API
│   └── 否 → 两者都兼容
│
└── 你有云服务商绑定?
    ├── AWS ElastiCache → 等待 Valkey 支持
    ├── Azure Cache → 已支持 Valkey
    ├── GCP Memorystore → 已支持 Valkey
    └── 阿里云 Redis → 暂无 Valkey 支持

6.2 迁移代码示例

# Redis 7.2 → Redis 8 迁移脚本
import redis
import json
import time

class RedisMigrator:
    def __init__(self, source_host, source_port, target_host, target_port):
        self.source = redis.Redis(host=source_host, port=source_port)
        self.target = redis.Redis(host=target_host, port=target_port)
        self.batch_size = 1000
    
    def migrate_keys(self, pattern="*"):
        """迁移匹配模式的所有键"""
        cursor = 0
        migrated = 0
        
        while True:
            cursor, keys = self.source.scan(
                cursor=cursor, match=pattern, count=self.batch_size
            )
            
            if keys:
                pipe = self.target.pipeline(transaction=False)
                for key in keys:
                    key_type = self.source.type(key)
                    
                    if key_type == b'string':
                        value = self.source.get(key)
                        pipe.set(key, value)
                    
                    elif key_type == b'hash':
                        value = self.source.hgetall(key)
                        pipe.hset(key, mapping=value)
                    
                    elif key_type == b'list':
                        values = self.source.lrange(key, 0, -1)
                        pipe.rpush(key, *values)
                    
                    elif key_type == b'set':
                        members = self.source.smembers(key)
                        pipe.sadd(key, *members)
                    
                    elif key_type == b'zset':
                        members = self.source.zrange(
                            key, 0, -1, withscores=True
                        )
                        for member, score in members:
                            pipe.zadd(key, {member: score})
                
                pipe.execute()
                migrated += len(keys)
                print(f"已迁移 {migrated} 个键...")
            
            if cursor == 0:
                break
        
        return migrated
    
    def migrate_with_ttl(self, pattern="*"):
        """迁移键及其 TTL"""
        cursor = 0
        migrated = 0
        
        while True:
            cursor, keys = self.source.scan(
                cursor=cursor, match=pattern, count=self.batch_size
            )
            
            for key in keys:
                # 迁移数据
                key_type = self.source.type(key)
                ttl = self.source.ttl(key)
                
                if key_type == b'string':
                    value = self.source.get(key)
                    self.target.set(key, value)
                # ... 其他类型处理
                
                # 恢复 TTL
                if ttl > 0:
                    self.target.expire(key, ttl)
                elif ttl == -1:
                    pass  # 无过期时间
                elif ttl == -2:
                    continue  # 键已过期,跳过
                
                migrated += 1
            
            if cursor == 0:
                break
        
        return migrated

# 使用示例
migrator = RedisMigrator(
    source_host="redis-7.2.local",
    source_port=6379,
    target_host="redis-8.local",
    target_port=6379
)

count = migrator迁移脚本(适用于 Redis → Valkey)
import redis
import json

class ValkeyMigrator:
    def __init__(self, redis_host, redis_port, valkey_host, valkey_port):
        self.redis = redis.Redis(host=redis_host, port=redis_port)
        self.valkey = redis.Redis(host=valkey_host, port=valkey_port)
    
    def migrate_all(self):
        """迁移所有数据到 Valkey"""
        cursor = 0
        count = 0
        
        while True:
            cursor, keys = self.redis.scan(cursor=cursor, count=1000)
            
            pipe = self.valkey.pipeline(transaction=False)
            for key in keys:
                # 获取键类型
                key_type = self.redis.type(key).decode()
                
                if key_type == 'string':
                    value = self.redis.get(key)
                    pipe.set(key, value)
                
                elif key_type == 'hash':
                    hash_data = self.redis.hgetall(key)
                    pipe.hset(key, mapping=hash_data)
                
                elif key_type == 'list':
                    list_data = self.redis.lrange(key, 0, -1)
                    pipe.rpush(key, *list_data)
                
                elif key_type == 'set':
                    set_data = self.redis.smembers(key)
                    pipe.sadd(key, *set_data)
                
                elif key_type == 'zset':
                    zset_data = self.redis.zrange(key, 0, -1, withscores=True)
                    for member, score in zset_data:
                        pipe.zadd(key, {member: score})
                
                elif key_type == 'stream':
                    # Streams 需要特殊处理
                    entries = self.redis.xrange(key)
                    for entry_id, fields in entries:
                        pipe.xadd(key, fields, id=entry_id)
                
                # 迁移 TTL
                ttl = self.redis.ttl(key)
                if ttl > 0:
                    pipe.expire(key, ttl)
            
            pipe.execute()
            count += len(keys)
            
            if cursor == 0:
                break
        
        return count
    
    def verify_migration(self):
        """验证迁移完整性"""
        redis_keys = set()
        valkey_keys = set()
        
        cursor = 0
        while True:
            cursor, keys = self.redis.scan(cursor=cursor, count=1000)
            redis_keys.update(keys)
            if cursor == 0:
                break
        
        cursor = 0
        while True:
            cursor, keys = self.valkey.scan(cursor=cursor, count=1000)
            valkey_keys.update(keys)
            if cursor == 0:
                break
        
        missing = redis_keys - valkey_keys
        extra = valkey_keys - redis_keys
        
        return {
            "redis_key_count": len(redis_keys),
            "valkey_key_count": len(valkey_keys),
            "missing_in_valkey": len(missing),
            "extra_in_valkey": len(extra),
            "missing_keys": list(missing)[:10],  # 显示前10个
        }

# 执行迁移
migrator = ValkeyMigrator(
    redis_host="localhost", redis_port=6379,
    valkey_host="localhost", valkey_port=6380
)

print("开始迁移...")
count = migrator.migrate_all()
print(f"迁移完成: {count} 个键")

print("\n验证迁移...")
result = migrator.verify_migration()
print(f"Redis 键数: {result['redis_key_count']}")
print(f"Valkey 键数: {result['valkey_key_count']}")
print(f"缺失: {result['missing_in_valkey']}")

6.3 迁移后的验证

# 迁移验证脚本
#!/bin/bash

echo "=== 数据完整性验证 ==="

# 对比键数量
REDIS_KEYS=$(redis-cli -h redis-old DBSIZE | awk '{print $2}')
VALKEY_KEYS=$(redis-cli -h valkey-new DBSIZE | awk '{print $2}')
echo "Redis 键数: $REDIS_KEYS"
echo "Valkey 键数: $VALKEY_KEYS"

# 对比内存使用
REDIS_MEM=$(redis-cli -h redis-old INFO memory | grep used_memory_human | cut -d: -f2)
VALKEY_MEM=$(redis-cli -h valkey-new INFO memory | grep used_memory_human | cut -d: -f2)
echo "Redis 内存: $REDIS_MEM"
echo "Valkey 内存: $VALKEY_MEM"

# 抽样验证数据完整性
echo ""
echo "=== 抽样验证 ==="
for key in $(redis-cli -h redis-old RANDOMKEY 10 | head -10); do
    REDIS_VALUE=$(redis-cli -h redis-old GET "$key")
    VALKEY_VALUE=$(redis-cli -h valkey-new GET "$key")
    
    if [ "$REDIS_VALUE" = "$VALKEY_VALUE" ]; then
        echo "✓ $key: 数据一致"
    else
        echo "✗ $key: 数据不一致!"
        echo "  Redis: $REDIS_VALUE"
        echo "  Valkey: $VALKEY_VALUE"
    fi
done

# 性能对比
echo ""
echo "=== 性能对比 ==="
echo "Redis 8 SET 延迟:"
redis-benchmark -h redis-new -t set -n 100000 -c 50 -q | grep "SET"

echo "Valkey 9 SET 延迟:"
redis-benchmark -h valkey-new -t set -n 100000 -c 50 -q | grep "SET"

第七章:生产级部署架构

7.1 Redis 8 集群部署(带向量搜索)

# docker-compose.redis8.yml
version: '3.8'

services:
  redis-node-1:
    image: redis:8.0
    command: >
      redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6379:6379"
    volumes:
      - redis1-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

  redis-node-2:
    image: redis:8.0
    command: >
      redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6380:6379"
    volumes:
      - redis2-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

  redis-node-3:
    image: redis:8.0
    command: >
      redis-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6381:6379"
    volumes:
      - redis3-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

volumes:
  redis1-data:
  redis2-data:
  redis3-data:

7.2 Valkey 9 集群部署

# docker-compose.valkey9.yml
version: '3.8'

services:
  valkey-node-1:
    image: valkey/valkey:9.0
    command: >
      valkey-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6379:6379"
    volumes:
      - valkey1-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

  valkey-node-2:
    image: valkey/valkey:9.0
    command: >
      valkey-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6380:6379"
    volumes:
      - valkey2-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

  valkey-node-3:
    image: valkey/valkey:9.0
    command: >
      valkey-server
      --cluster-enabled yes
      --cluster-config-file nodes.conf
      --cluster-node-timeout 5000
      --appendonly yes
      --appendfsync everysec
      --maxmemory 8gb
      --maxmemory-policy allkeys-lru
    ports:
      - "6381:6379"
    volumes:
      - valkey3-data:/data
    deploy:
      resources:
        limits:
          memory: 10G
          cpus: '4'

  # Valkey 特有:多数据库支持
  # 在 Redis 集群中,SELECT 命令不可用
  # Valkey 9.0 支持集群模式下的多数据库
  # 通过不同的 db index 隔离数据

volumes:
  valkey1-data:
  valkey2-data:
  valkey3-data:

第八章:总结与展望

8.1 核心结论

Redis 8 vs Valkey 9 选型决策矩阵

                    Redis 8          Valkey 9
─────────────────────────────────────────────────
许可证              AGPLv3/付费       BSD 3-Clause
治理模式            单厂商控制        多厂商基金会
数据模型            多模型(8种新类型)  传统KV+模块扩展
向量搜索            原生Vector Set    模块(Valkey Search)
语义缓存            原生LangCache     不支持
混合搜索            原生FT.HYBRID     不支持
时间序列            原生              不支持
概率数据结构         5种原生           仅Bloom模块
JSON               原生(内存优化92%)  模块
多数据库集群        不支持            支持
原子槽迁移          支持              支持
RDMA支持           不支持            实验性
Rust集成           不支持            进行中
企业级支持          Redis Cloud       无
性能(吞吐)          5x vs 7.2        接近7.2水平

8.2 最终建议

选择 Redis 8 的场景:
├── AI/ML 应用:需要向量搜索、语义缓存、混合查询
├── 实时分析:需要时间序列、概率数据结构
├── 企业级应用:需要 99.999% SLA 和商业支持
├── 微服务架构:需要 JSON 原生支持和高效序列化
└── 能接受 AGPLv3 或付费许可

选择 Valkey 9 的场景:
├── 许可证敏感:需要真正的 BSD 开源
├── 云原生部署:需要多厂商治理和避免单点风险
├── 传统缓存:只需要高性能 KV 存储
├── 多租户:需要集群模式下的多数据库支持
├── 贡献社区:想参与项目开发和决策
└── 迁移成本低:从 Redis 7.2 无缝迁移

8.3 未来展望

2026年下半年展望
├── Redis 8.12+: 
│   ├── 向量集合 GA(非 beta)
│   ├── 语义缓存 2.0(支持多模态)
│   └── Redis Flex 混合存储
├── Valkey 9.1:
│   ├── Rust 核心路径完成
│   ├── RDMA GA
│   └── 更多搜索能力
└── 行业趋势:
    ├── 内存数据库成为 AI 基础设施核心
    ├── 向量搜索从专用数据库融入通用存储
    ├── 许可证争议推动更多项目选择基金会治理
    └── Redis 和 Valkey 将长期并存,各自服务不同需求

最终答案:如果你在做 AI 应用,选 Redis 8;如果你在意许可证和治理,选 Valkey 9。两者不是非此即彼——很多团队同时运行 Redis 8(AI 工作负载)和 Valkey 9(传统缓存),各取所长。


本文基于 Redis 8.10.0、Valkey 9.0、Redis 官方博客、Valkey 官方文档编写。所有性能数据均来自官方基准测试,实际结果可能因硬件和配置而异。

推荐文章

JavaScript设计模式:桥接模式
2024-11-18 19:03:40 +0800 CST
WebSQL数据库:HTML5的非标准伴侣
2024-11-18 22:44:20 +0800 CST
如何实现虚拟滚动
2024-11-18 20:50:47 +0800 CST
Python设计模式之工厂模式详解
2024-11-19 09:36:23 +0800 CST
底部导航栏
2024-11-19 01:12:32 +0800 CST
程序员茄子在线接单