Redis 缓存集成方案
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 项目中安装 ioredis
或 redis
客户端库:
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
下一篇:数据库连接池配置优化