阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Redis 缓存集成方案

Redis 缓存集成方案

作者:陈川 阅读数:43929人阅读 分类: Node.js

Redis 缓存集成方案

Redis 是一个高性能的键值存储系统,常用于缓存、消息队列等场景。在 Koa2 中集成 Redis 可以显著提升应用的响应速度和并发能力。以下是一个完整的 Redis 缓存集成方案,包括安装、配置、基本操作和高级用法。

安装 Redis 和依赖

首先需要安装 Redis 服务器和 Node.js 的 Redis 客户端库。Redis 服务器可以通过官网下载安装,或者使用 Docker 快速启动:

# 使用 Docker 启动 Redis
docker run --name my-redis -p 6379:6379 -d redis

在 Koa2 项目中安装 ioredisredis 客户端库:

npm install ioredis
# 或者
npm install redis

基本配置

在 Koa2 中,通常会将 Redis 客户端实例挂载到 ctx 上下文中,方便全局调用。以下是一个基本的配置示例:

const Koa = require('koa');
const Redis = require('ioredis');

const app = new Koa();
const redis = new Redis({
  host: '127.0.0.1',
  port: 6379,
  password: 'yourpassword', // 如果有密码
  db: 0, // 选择数据库
});

// 将 Redis 实例挂载到上下文
app.context.redis = redis;

app.use(async (ctx) => {
  ctx.body = 'Hello Redis';
});

app.listen(3000);

缓存数据的基本操作

Redis 支持多种数据结构,以下是常见的操作示例:

字符串(String)

// 设置缓存
await ctx.redis.set('user:1', JSON.stringify({ name: 'Alice', age: 25 }));

// 获取缓存
const userData = await ctx.redis.get('user:1');
const user = JSON.parse(userData);
console.log(user); // { name: 'Alice', age: 25 }

// 设置过期时间(10秒)
await ctx.redis.set('temp:data', 'expires soon', 'EX', 10);

哈希(Hash)

// 设置哈希字段
await ctx.redis.hset('user:2', 'name', 'Bob');
await ctx.redis.hset('user:2', 'age', '30');

// 获取哈希字段
const userName = await ctx.redis.hget('user:2', 'name');
console.log(userName); // 'Bob'

// 获取所有字段
const user = await ctx.redis.hgetall('user:2');
console.log(user); // { name: 'Bob', age: '30' }

列表(List)

// 向列表添加元素
await ctx.redis.lpush('messages', 'msg1', 'msg2');

// 获取列表范围
const messages = await ctx.redis.lrange('messages', 0, -1);
console.log(messages); // ['msg2', 'msg1']

缓存策略

缓存穿透

缓存穿透是指查询一个不存在的数据,导致每次请求都打到数据库。可以通过布隆过滤器或缓存空值来解决:

app.use(async (ctx, next) => {
  const cacheKey = `user:${ctx.params.id}`;
  let user = await ctx.redis.get(cacheKey);

  if (user === null) {
    // 数据库查询
    user = await db.queryUser(ctx.params.id);
    if (!user) {
      // 缓存空值,设置较短的过期时间
      await ctx.redis.set(cacheKey, '', 'EX', 60);
    } else {
      await ctx.redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
    }
  }

  ctx.body = user || {};
});

缓存雪崩

缓存雪崩是指大量缓存同时失效,导致数据库压力骤增。可以通过设置不同的过期时间来避免:

// 设置随机过期时间
const randomTTL = Math.floor(Math.random() * 300) + 300; // 300-600秒
await ctx.redis.set('data:key', 'value', 'EX', randomTTL);

缓存击穿

缓存击穿是指热点数据失效时,大量请求直接打到数据库。可以通过互斥锁(Mutex)来解决:

async function getDataWithLock(key) {
  const value = await ctx.redis.get(key);
  if (value !== null) return value;

  const lockKey = `lock:${key}`;
  const locked = await ctx.redis.set(lockKey, '1', 'NX', 'EX', 10);
  if (locked) {
    try {
      const data = await fetchDataFromDB(); // 从数据库获取数据
      await ctx.redis.set(key, JSON.stringify(data), 'EX', 3600);
      return data;
    } finally {
      await ctx.redis.del(lockKey);
    }
  } else {
    // 等待并重试
    await new Promise(resolve => setTimeout(resolve, 100));
    return getDataWithLock(key);
  }
}

高级用法

发布/订阅模式

Redis 支持发布/订阅模式,可以用于实时消息通知:

// 订阅频道
const subscriber = new Redis();
subscriber.subscribe('news');

subscriber.on('message', (channel, message) => {
  console.log(`Received ${message} from ${channel}`);
});

// 发布消息
const publisher = new Redis();
publisher.publish('news', 'Hello world!');

Lua 脚本

Redis 支持执行 Lua 脚本,可以实现原子操作:

const script = `
  local key = KEYS[1]
  local limit = tonumber(ARGV[1])
  local current = tonumber(redis.call('GET', key) or 0)
  if current + 1 > limit then
    return 0
  else
    redis.call('INCR', key)
    return 1
  end
`;

// 执行限流脚本
const result = await ctx.redis.eval(script, 1, 'rate:limit:user1', 10);
console.log(result); // 1 或 0

管道(Pipeline)

管道可以一次性发送多个命令,减少网络开销:

const pipeline = ctx.redis.pipeline();
pipeline.set('key1', 'value1');
pipeline.set('key2', 'value2');
pipeline.expire('key1', 60);
const results = await pipeline.exec();
console.log(results);

性能优化

连接池

使用连接池可以避免频繁创建和销毁连接:

const Redis = require('ioredis');
const redis = new Redis({
  host: '127.0.0.1',
  port: 6379,
  password: 'yourpassword',
  db: 0,
  enableOfflineQueue: false, // 禁用离线队列
  maxRetriesPerRequest: 1, // 最大重试次数
  reconnectOnError: (err) => {
    // 自定义重连逻辑
    return err.message.includes('READONLY');
  },
});

集群模式

对于大规模应用,可以使用 Redis 集群:

const Redis = require('ioredis');
const cluster = new Redis.Cluster([
  { host: '127.0.0.1', port: 7000 },
  { host: '127.0.0.1', port: 7001 },
]);

app.context.redis = cluster;

监控与调试

慢查询日志

Redis 支持慢查询日志,可以通过以下命令开启:

# 设置慢查询阈值为 10 毫秒
redis-cli config set slowlog-log-slower-than 10000
# 保留最近 100 条慢查询
redis-cli config set slowlog-max-len 100
# 查看慢查询日志
redis-cli slowlog get

性能测试

使用 redis-benchmark 工具测试 Redis 性能:

redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌