Redis模式Skill redis-patterns

该技能是关于使用 Upstash Redis 实现各种后端开发模式的完整指南,包括缓存、限流、会话存储、实时通信和排行榜等核心功能。关键词:Redis 缓存,速率限制,会话管理,发布订阅,排行榜,后端开发,数据库优化,API 防护,实时数据,缓存策略。

后端开发 0 次安装 0 次浏览 更新于 3/2/2026

名称: redis-patterns 描述: Upstash Redis 缓存和限流模式。

Upstash Redis 模式

设置

// lib/redis.ts
import { Redis } from '@upstash/redis';

export const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

基础缓存

// 带TTL的缓存
async function getCachedUser(id: string): Promise<User | null> {
  const cacheKey = `user:${id}`;

  // 先尝试从缓存读取
  const cached = await redis.get<User>(cacheKey);
  if (cached) return cached;

  // 从数据库获取
  const user = await db.query.users.findFirst({
    where: eq(users.id, id),
  });

  if (user) {
    // 缓存5分钟
    await redis.setex(cacheKey, 300, user);
  }

  return user;
}

缓存失效

// 更新时失效缓存
async function updateUser(id: string, data: UpdateUserInput): Promise<User> {
  const user = await db.update(users)
    .set(data)
    .where(eq(users.id, id))
    .returning();

  // 失效缓存
  await redis.del(`user:${id}`);

  // 同时失效列表缓存
  await redis.del('users:list');

  return user[0];
}

速率限制

import { Ratelimit } from '@upstash/ratelimit';

const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(10, '10 s'), // 10秒内10次请求
  analytics: true,
});

// 在API路由或中间件中
export async function POST(request: Request) {
  const ip = request.headers.get('x-forwarded-for') ?? 'anonymous';
  const { success, limit, reset, remaining } = await ratelimit.limit(ip);

  if (!success) {
    return new Response('请求过多', {
      status: 429,
      headers: {
        'X-RateLimit-Limit': limit.toString(),
        'X-RateLimit-Remaining': remaining.toString(),
        'X-RateLimit-Reset': reset.toString(),
      },
    });
  }

  // 处理请求...
}

会话存储

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

async function createSession(userId: string): Promise<string> {
  const sessionId = crypto.randomUUID();
  const session: Session = {
    userId,
    expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7天
  };

  await redis.setex(`session:${sessionId}`, 7 * 24 * 60 * 60, session);
  return sessionId;
}

async function getSession(sessionId: string): Promise<Session | null> {
  return await redis.get<Session>(`session:${sessionId}`);
}

async function deleteSession(sessionId: string): Promise<void> {
  await redis.del(`session:${sessionId}`);
}

实时发布/订阅

// 发布者
async function publishEvent(channel: string, data: unknown): Promise<void> {
  await redis.publish(channel, JSON.stringify(data));
}

// 使用示例
await publishEvent('user:updates', { userId: '123', action: 'updated' });

排行榜

// 添加分数
await redis.zadd('leaderboard', { score: 100, member: 'user:123' });

// 获取前10名
const topUsers = await redis.zrevrange('leaderboard', 0, 9, { withScores: true });

// 获取用户排名
const rank = await redis.zrevrank('leaderboard', 'user:123');

缓存模式

// 缓存旁路模式
async function getData<T>(
  key: string,
  fetcher: () => Promise<T>,
  ttl: number = 300
): Promise<T> {
  const cached = await redis.get<T>(key);
  if (cached) return cached;

  const data = await fetcher();
  await redis.setex(key, ttl, data);
  return data;
}

// 使用示例
const user = await getData(
  `user:${id}`,
  () => db.query.users.findFirst({ where: eq(users.id, id) }),
  300
);