返回首页
⚙️ 后端 / 架构

Redis 8 实战:从入门到生产级缓存架构完整指南

Redis 8 是 2026 年最流行的 KV 存储。本文从 0 到生产级缓存架构,含 6 大核心场景 + 性能优化 + 集群 + 高可用 + 与 AI Agent 集成。

Redis · 缓存 · 分布式 · Session · 排行榜 · 限流 · 分布式锁
📰

今日技术简讯

📰 技术简讯 · 2026-08-04

今日聚合 6 条热门技术内容(中文素材优先)。

🤖 AI / LLM

1. Redis 8 GA 推出 AGENTS 模块

  • 链接https://redis.io/blog/redis-8-ga
  • 来源:Redis
  • 摘要:Redis 8 GA 推出 AGENTS 模块(AI Agent 原生支持)+ 向量搜索 + 许可证回归 BSD。

2. Valkey 8 兼容 Redis 8

  • 链接https://valkey.io/blog/8
  • 来源:Valkey
  • 摘要:Valkey 8 完全兼容 Redis 8 API,Linux Foundation 治理,BSD 许可证。

🎨 前端 / Web

3. Upstash Redis 推出 HTTP/3

⚙️ 后端 / 架构

4. Dragonfly 推出多线程 Redis

5. KeyDB 推出生产级集群

🚀 独立开发 / OPC

6. 即刻"Redis 缓存架构"专题

  • 链接https://m.okjike.com/redis-2026
  • 来源:即刻
  • 摘要:即刻 200+ 独立开发者分享 Redis 缓存架构,Session / 排行榜 / 限流 / 分布式锁实战。

数据来源:掘金 / InfoQ 中文 / 即刻 / 少数派 / HN 采集时间:2026-08-04 09:00 (UTC+8)

📝

今日深度文

Redis 8 实战:从入门到生产级缓存架构完整指南

一句话结论:Redis 8 = 内存数据库的"瑞士军刀"。缓存 / Session / 排行榜 / 限流 / 分布式锁 / AI Agent(AGENTS 模块)。本文从 0 到生产级缓存架构。

背景

2026 年 Redis 生态:

Redis 8(2026-05 GA)
├─ 许可证回归 BSD(社区版)
├─ AGENTS 模块(AI Agent 原生支持)
├─ 向量搜索(RedisVL)
├─ JSON / Search / Timeseries
└─ 100% 向后兼容

替代方案:
├─ Valkey 8(Linux Foundation,BSD)
├─ Dragonfly(多线程,25x)
└─ KeyDB(多主)

为什么 Redis 仍是首选:

  1. 极致性能:QPS 100K+(单实例)
  2. 数据结构丰富:String / Hash / List / Set / Sorted Set / Stream
  3. 持久化:RDB / AOF
  4. 集群:Redis Cluster(水平扩展)
  5. 生态成熟:所有云厂商 / 框架都支持

6 大核心场景

场景 1:缓存(最常用)

// lib/cache.ts
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

export async function cached<T>(
  key: string,
  ttl: number,
  fetcher: () => Promise<T>
): Promise<T> {
  // 1. 读缓存
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // 2. 回源
  const data = await fetcher();
  
  // 3. 写缓存
  await redis.setex(key, ttl, JSON.stringify(data));
  
  return data;
}

// 使用
const user = await cached(
  `user:${userId}`,
  300,  // 5 分钟
  () => db.user.findUnique({ where: { id: userId } })
);

场景 2:Session

// lib/session.ts
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

interface Session {
  userId: string;
  expiresAt: number;
}

export async function createSession(userId: string): Promise<string> {
  const token = crypto.randomUUID();
  const session: Session = {
    userId,
    expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,  // 30 天
  };
  
  await redis.setex(
    `session:${token}`,
    30 * 24 * 60 * 60,
    JSON.stringify(session)
  );
  
  return token;
}

export async function getSession(token: string): Promise<Session | null> {
  const data = await redis.get(`session:${token}`);
  if (!data) return null;
  
  const session = JSON.parse(data);
  if (Date.now() > session.expiresAt) {
    await redis.del(`session:${token}`);
    return null;
  }
  
  return session;
}

场景 3:排行榜(Sorted Set)

// lib/leaderboard.ts
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

// 增加分数
await redis.zadd('leaderboard:global', Date.now(), `user:${userId}`);

// Top 10
const top10 = await redis.zrevrange('leaderboard:global', 0, 9, 'WITHSCORES');

// 用户排名(升序,0 开始)
const rank = await redis.zrevrank('leaderboard:global', `user:${userId}`);

// 用户分数
const score = await redis.zscore('leaderboard:global', `user:${userId}`);

// Top N(with 用户信息)
const topWithInfo = await redis.zrevrange(
  'leaderboard:global',
  0,
  99,
  'WITHSCORES'
);

场景 4:限流

// lib/rate-limit.ts
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

// 滑动窗口限流
export async function rateLimit(
  key: string,
  limit: number,
  window: number  // 秒
): Promise<{ allowed: boolean; remaining: number; resetAt: number }> {
  const now = Date.now();
  const windowMs = window * 1000;
  
  // 移除过期的请求
  await redis.zremrangebyscore(key, 0, now - windowMs);
  
  // 当前窗口内的请求数
  const count = await redis.zcard(key);
  
  if (count >= limit) {
    const oldest = await redis.zrange(key, 0, 0, 'WITHSCORES');
    const resetAt = Number(oldest[1]) + windowMs;
    return { allowed: false, remaining: 0, resetAt };
  }
  
  // 添加当前请求
  await redis.zadd(key, now, `${now}-${Math.random()}`);
  await redis.expire(key, window);
  
  return {
    allowed: true,
    remaining: limit - count - 1,
    resetAt: now + windowMs,
  };
}

// 使用:每分钟最多 60 次
const result = await rateLimit(`api:${userId}`, 60, 60);
if (!result.allowed) {
  return new Response('Too Many Requests', { status: 429 });
}

场景 5:分布式锁

// lib/lock.ts
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

export async function acquireLock(
  key: string,
  ttl: number = 10000  // 10 秒
): Promise<string | null> {
  const token = crypto.randomUUID();
  
  // SET key token NX PX ttl
  // NX: 不存在才设置
  // PX: 毫秒级过期
  const result = await redis.set(
    `lock:${key}`,
    token,
    'PX',
    ttl,
    'NX'
  );
  
  return result === 'OK' ? token : null;
}

export async function releaseLock(key: string, token: string): Promise<boolean> {
  // Lua 脚本保证原子性
  const lua = `
    if redis.call('get', KEYS[1]) == ARGV[1] then
      return redis.call('del', KEYS[1])
    else
      return 0
    end
  `;
  
  const result = await redis.eval(lua, 1, `lock:${key}`, token);
  return result === 1;
}

// 使用:支付场景
async function processPayment(orderId: string) {
  const lock = await acquireLock(`payment:${orderId}`, 30000);
  if (!lock) {
    throw new Error('Order is being processed');
  }
  
  try {
    // 处理支付(唯一执行)
    await chargeCustomer(orderId);
    await markOrderPaid(orderId);
  } finally {
    await releaseLock(`payment:${orderId}`, lock);
  }
}

场景 6:AI Agent(Redis 8 AGENTS)

// AI Agent 状态管理
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

// Agent 状态(关联 7/11 LangGraph)
class AgentState {
  async save(threadId: string, state: any) {
    await redis.json.set(`agent:${threadId}`, '$', state);
    await redis.expire(`agent:${threadId}`, 3600);
  }
  
  async load(threadId: string): Promise<any | null> {
    const state = await redis.json.get(`agent:${threadId}`);
    return state;
  }
}

// 向量搜索(关联 7/15 RAG)
class VectorStore {
  async add(id: string, embedding: number[], metadata: any) {
    // VECTOR 字段 + JSON metadata
    await redis.call(
      'JSON.SET',
      `vec:${id}`,
      '$',
      JSON.stringify({ embedding, metadata })
    );
  }
  
  async search(query: number[], topK: number = 5) {
    // 用 FT.SEARCH 做 KNN 搜索
    const result = await redis.call(
      'FT.SEARCH',
      'idx:embeddings',
      '*=>[KNN 5 @embedding $vec AS score]',
      'PARAMS', '2', 'vec', Buffer.from(new Float32Array(query).buffer),
      'SORTBY', 'score', 'ASC'
    );
    
    return result;
  }
}

5 个实战项目

项目 1:用户认证(Session)

// middleware/auth.ts
import { NextResponse } from 'next/server';
import { getSession } from '@/lib/session';

export async function middleware(request: Request) {
  const token = request.headers.get('cookie')?.match(/token=([^;]+)/)?.[1];
  
  if (!token) {
    return NextResponse.redirect('/login');
  }
  
  const session = await getSession(token);
  if (!session) {
    return NextResponse.redirect('/login');
  }
  
  return NextResponse.next();
}

项目 2:电商秒杀

// 秒杀(100 个库存,10000 人抢)
async function seckill(productId: string, userId: string) {
  const stockKey = `seckill:stock:${productId}`;
  const userKey = `seckill:user:${productId}`;
  
  // 1. 防重复购买
  const alreadyBought = await redis.sismember(userKey, userId);
  if (alreadyBought) {
    return { success: false, reason: 'already_bought' };
  }
  
  // 2. 原子扣减库存(Lua 脚本)
  const lua = `
    local stock = tonumber(redis.call('get', KEYS[1]))
    if stock <= 0 then
      return 0
    end
    redis.call('decr', KEYS[1])
    redis.call('sadd', KEYS[2], ARGV[1])
    return 1
  `;
  
  const result = await redis.eval(
    lua,
    2,
    stockKey,
    userKey,
    userId
  );
  
  if (result === 0) {
    return { success: false, reason: 'out_of_stock' };
  }
  
  // 3. 创建订单
  await db.order.create({
    data: { productId, userId, status: 'pending' },
  });
  
  return { success: true };
}

项目 3:实时通知

// 用 Stream 实现消息队列(关联 7/27 GitHub Actions)
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

// 生产者
async function publishNotification(userId: string, message: any) {
  await redis.xadd(
    `notifications:${userId}`,
    '*',
    'type', message.type,
    'title', message.title,
    'content', message.content,
    'createdAt', Date.now().toString()
  );
}

// 消费者
async function consumeNotifications(userId: string) {
  while (true) {
    const result = await redis.xread(
      'BLOCK', 0,
      'STREAMS', `notifications:${userId}`, '$'
    );
    
    if (result) {
      for (const [stream, messages] of result) {
        for (const [id, fields] of messages) {
          // 推送到客户端
          await sendToClient(userId, { id, ...fields });
        }
      }
    }
  }
}

项目 4:分布式 ID 生成

// 类雪花算法(基于 Redis)
async function generateId(): Promise<string> {
  const key = 'id:generator';
  
  const lua = `
    local seq = redis.call('incr', KEYS[1])
    local timestamp = tonumber(ARGV[1])
    return timestamp * 10000 + (seq % 10000)
  `;
  
  const timestamp = Date.now() - new Date('2026-01-01').getTime();
  const id = await redis.eval(lua, 1, key, timestamp);
  
  // 重置(每秒)
  await redis.expire(key, 1);
  
  return id.toString();
}

项目 5:内容推荐

// 协同过滤(基于 Sorted Set)
async function getRecommendations(userId: string) {
  // 1. 用户看过的内容
  const viewed = await redis.zrange(`user:viewed:${userId}`, 0, -1);
  
  // 2. 找相似用户(看过的交集)
  const similarUsers = await redis.zinter(
    `user:viewed:${userId}`,
    'user:viewed:*'
  );
  
  // 3. 提取相似用户看过的内容(推荐)
  const recommendations = await redis.zunion(
    ...similarUsers.map(u => `user:viewed:${u}`)
  );
  
  // 4. 排除已看
  return recommendations.filter(item => !viewed.includes(item));
}

性能优化 10 招

1. Pipeline(批量操作)

// ❌ 100 次单条请求 = 100ms 网络
for (const key of keys) {
  await redis.get(key);
}

// ✅ 1 次 pipeline = 5ms
const results = await redis.pipeline()
  ...keys.map(key => redis.get(key))
  .exec();

2. Lua 脚本(原子操作)

// ✅ 复杂逻辑用 Lua(原子 + 减少网络)
const lua = `
  local stock = tonumber(redis.call('get', KEYS[1]))
  if stock > 0 then
    redis.call('decr', KEYS[1])
    return 1
  end
  return 0
`;

const success = await redis.eval(lua, 1, 'stock:1');

3. Hash 代替多个 String

// ❌ 100 个 String
await redis.set('user:1:name', 'Alice');
await redis.set('user:1:email', 'alice@example.com');
await redis.set('user:1:age', '30');

// ✅ 1 个 Hash
await redis.hset('user:1', {
  name: 'Alice',
  email: 'alice@example.com',
  age: 30,
});

4. 选择合适数据结构

String: 缓存单个值
Hash: 对象
List: 队列 / 最新 N 个
Set: 去重 / 共同好友
Sorted Set: 排行榜 / 范围查询
Stream: 消息流
JSON: 复杂对象
Vector: 向量搜索(Redis 8)

5. 避免大 Key

❌ key 包含 100 万个元素
✅ 拆分 key(user:1:items:0, user:1:items:1)

6. 避免热点 Key

❌ 100 万请求打同一个 key
✅ 加随机后缀(key:1, key:2, ...)

7. 设置合理 TTL

// ✅ 必须设置 TTL(防止内存爆炸)
await redis.setex('key', 3600, 'value');

// ✅ 永久 key 也要设置(清理)
await redis.set('key', 'value', 'EX', 86400);

8. 内存优化

# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru  # 内存满时淘汰最近最少使用

9. 持久化策略

# RDB(快照)
save 900 1      # 900 秒至少 1 个 key 变化
save 300 10     # 300 秒至少 10 个 key 变化

# AOF(日志)
appendonly yes
appendfsync everysec  # 每秒 fsync

10. 监控指标

// 关键指标
- used_memory
- used_memory_peak
- connected_clients
- total_commands_processed
- keyspace_hits / keyspace_misses(缓存命中率)

Redis Cluster 集群

6 节点(3 主 3 从)
├─ 16384 哈希槽
├─ 水平扩展(最多 1000 节点)
├─ 自动故障转移
└─ 客户端分片(无需 proxy)
// ioredis cluster
const cluster = new Redis.Cluster([
  { host: 'redis-1', port: 6379 },
  { host: 'redis-2', port: 6379 },
  { host: 'redis-3', port: 6379 },
], {
  redisOptions: {
    password: process.env.REDIS_PASSWORD,
  },
  scaleReads: 'slave',  // 从从节点读
});

5 个常见坑

坑 1:无 TTL

❌ set 'key' 'value' (永不过期 → 内存爆炸)
✅ setex 'key' 3600 'value'

坑 2:雪崩

// ❌ 所有 key 同时过期 → DB 雪崩
for (const key of keys) {
  await redis.setex(key, 3600, value);
}

// ✅ 加随机 TTL(防雪崩)
for (const key of keys) {
  const ttl = 3600 + Math.random() * 600;
  await redis.setex(key, ttl, value);
}

坑 3:穿透

// ❌ 不存在的 key 每次都查 DB
const data = await redis.get(key);
if (!data) {
  return await db.query();  // 每次都打 DB
}

// ✅ 缓存空值
const data = await redis.get(key);
if (data === null) {
  const dbData = await db.query();
  if (!dbData) {
    await redis.setex(key, 60, 'null');  // 缓存空值 60 秒
  }
  return dbData;
}

坑 4:击穿

// ❌ 热点 key 过期瞬间,所有请求打 DB
const data = await redis.get('hot:key');
if (!data) return await db.query();

// ✅ 分布式锁(防止击穿)
const lock = await acquireLock('hot:key');
if (lock) {
  const data = await db.query();
  await redis.setex('hot:key', 3600, JSON.stringify(data));
  await releaseLock('hot:key', lock);
}

坑 5:误用 List 当队列

// ❌ 用 List 当消息队列(无消费者组)
await redis.lpush('queue', msg);
await redis.brpop('queue', 0);

// ✅ 用 Stream(有消费者组 + ACK)
await redis.xadd('mystream', '*', 'data', JSON.stringify(msg));
await redis.xreadgroup('GROUP', 'g1', 'c1', '>', 'STREAMS', 'mystream', '>');

与之前内容的关系

7/15 RAG + pgvector    → 向量搜索
7/21 PostgreSQL 18       → 关系数据库
7/26 Cloudflare D1      → 边缘 SQLite
7/29 WebGPU              → 浏览器 AI
8/1 LLM 工程化          → AI 状态
8/4 Redis 8              → 缓存 / 内存数据库  ← 今天
→ "持久化 → 缓存"完整数据层

7 天落地路径

Day 1:安装 Redis

# Docker
docker run -d --name redis -p 6379:6379 redis:8

# macOS
brew install redis
redis-server

Day 2:基础命令

$ redis-cli
> SET key value EX 60
> GET key
> HSET user:1 name "Alice"
> ZADD leaderboard 100 user:1

Day 3:应用集成

import { Redis } from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);

Day 4:缓存模式

// cache-aside / read-through / write-through

Day 5:高级特性

// Stream / Pub-Sub / Pipeline / Lua

Day 6:集群

// 6 节点集群 + 客户端分片

Day 7:监控

# Prometheus + Grafana
# Redis Exporter

我的看法

Redis 8 是 2026 年内存数据库的"瑞士军刀"

  1. 极致性能:100K QPS
  2. 数据结构丰富:10+ 种
  3. AI 原生:AGENTS 模块
  4. 开源回归:BSD 许可证
  5. 生态成熟:所有云厂商支持

对独立开发者的建议:

  • 缓存必装:替代 DB 80% 读请求
  • Session 用 Redis:替代 JWT
  • 排行榜首选:Sorted Set
  • 限流必备:滑动窗口
  • 分布式锁:秒杀 / 支付

参考


本文基于 Redis 8 GA(2026-05),8 月最新实战。

📚 同主题文章

⚙️ 后端 / 架构 分类更多