【RuoYi-Eggjs】:缓存,让你的应用飞起来
前言
在 Web 应用开发中,缓存是提升性能的关键手段。无论是减少数据库查询、加快 API 响应,还是降低服务器负载,缓存都扮演着重要角色。[ruoyi-eggjs-cache](https://github.com/undsky/ruoyi-eggjs-cache) 就是一个为 Egg.js 量身定制的缓存插件,基于强大的 cache-manager 生态,提供了开箱即用的缓存能力。
核心特性
🎯 三种存储方式,按需选择
插件支持三种缓存存储方式,每种都有其独特的使用场景:
1. 内存缓存(Memory)
- 优势:速度最快,毫秒级响应
- 劣势:应用重启后丢失,占用内存
- 适用场景:频繁访问的小数据、临时数据
2. 文件系统缓存(FS)
- 优势:持久化存储,不占用应用内存
- 劣势:读写速度相对较慢
- 适用场景:大数据缓存、需要持久化的数据
3. Redis 缓存(推荐)
- 优势:速度快、持久化、支持分布式
- 劣势:需要额外的 Redis 服务
- 适用场景:生产环境、集群部署、多实例共享数据
🔧 统一的 API,简单易用
插件提供了四个核心方法,覆盖所有缓存操作场景:
// 1. set - 设置缓存
await app.cache.default.set('key', 'value', 300); // 缓存 5 分钟
// 2. get - 获取缓存
const value = await app.cache.default.get('key');
// 3. del - 删除缓存
await app.cache.default.del('key');
// 4. wrap - 缓存包装器(最常用)
const result = await app.cache.default.wrap('key', async () => {
return await fetchData(); // 仅在缓存不存在时执行
});
其中 wrap 方法是最实用的——它会自动判断缓存是否存在,存在则直接返回,不存在则执行回调函数并缓存结果。
快速上手
安装
npm i ruoyi-eggjs-cache --save
配置
1. 启用插件
// config/plugin.js
exports.cache = {
enable: true,
package: "ruoyi-eggjs-cache",
};
2. 基础配置(内存缓存)
// config/config.default.js
const path = require('path');
config.cache = {
default: 'memory', // 默认使用内存缓存
ttl: 600, // 缓存 10 分钟
fs: {
path: path.join(appInfo.baseDir, 'cache'),
subdirs: false,
zip: false,
},
redis: null,
};
3. Redis 配置(推荐生产环境)
// config/config.prod.js
config.cache = {
default: 'redis',
ttl: 600,
redis: {
host: '127.0.0.1',
port: 6379,
password: '',
db: 0,
},
};
实战场景
场景 1:数据库查询缓存
数据库查询是最常见的性能瓶颈,使用缓存可以显著提升响应速度:
// app/service/user.js
class UserService extends Service {
async getUserById(userId) {
const { app } = this;
// 使用 wrap 自动管理缓存
return await app.cache.default.wrap(`user:${userId}`, async () => {
return await app.mysql.select('SELECT * FROM users WHERE id = ?', [userId]);
});
}
async updateUser(user) {
const { app } = this;
// 更新数据库
await app.mysql.update('UPDATE users SET name = ? WHERE id = ?', [user.name, user.id]);
// 删除缓存,确保下次获取最新数据
await app.cache.default.del(`user:${user.id}`);
}
}
关键点:
- 查询时使用
wrap自动缓存 - 更新/删除时手动清除缓存
场景 2:API 响应缓存
对于查询频繁但变化不大的列表接口,缓存可以大幅降低服务器负载:
// app/controller/article.js
class ArticleController extends Controller {
async list() {
const { ctx, app } = this;
const params = ctx.request.body;
// 根据查询参数生成唯一的缓存 key
const cacheKey = `article:list:${JSON.stringify(params)}`;
const articles = await app.cache.default.wrap(cacheKey, async () => {
return await ctx.service.article.getList(params);
}, { ttl: 60 }); // 列表缓存 1 分钟
ctx.body = { code: 200, data: articles };
}
}
场景 3:配置数据缓存
系统配置数据变化频率极低,非常适合长时间缓存:
// app/service/config.js
class ConfigService extends Service {
async getConfigByKey(configKey) {
const { app } = this;
return await app.cache.default.wrap(`config:${configKey}`, async () => {
return await app.mysql.select('SELECT * FROM sys_config WHERE config_key = ?', [configKey]);
}, { ttl: 3600 }); // 缓存 1 小时
}
async updateConfig(config) {
const { app } = this;
await app.mysql.update('UPDATE sys_config SET config_value = ? WHERE config_key = ?',
[config.configValue, config.configKey]);
// 清除配置缓存
await app.cache.default.del(`config:${config.configKey}`);
}
}
场景 4:不同存储方式的组合使用
针对不同的数据特点,选择最合适的缓存方式:
// app/service/data.js
class DataService extends Service {
// 高频访问的小数据 → 内存缓存
async getHotData() {
return await this.app.cache.memory.wrap('hot:data', async () => {
return await this.fetchHotData();
});
}
// 体积大的数据 → 文件系统缓存
async getBigData() {
return await this.app.cache.fs.wrap('big:data', async () => {
return await this.fetchBigData();
}, { ttl: 1800 });
}
// 多实例共享数据 → Redis 缓存
async getSharedData() {
return await this.app.cache.redis.wrap('shared:data', async () => {
return await this.fetchSharedData();
}, { ttl: 600 });
}
}
缓存策略最佳实践
1. 合理设计缓存 Key
好的 Key 命名能让缓存管理更清晰:
// ✅ 推荐:使用有意义的前缀和参数
`user:${userId}`
`article:list:${category}:${page}`
`config:${configKey}`
// ❌ 不推荐:无意义的 Key
`u123`
`data`
2. 根据数据特点设置 TTL
// 频繁变化的数据 - 短 TTL
await app.cache.default.wrap('stock:price', async () => {
return await fetchStockPrice();
}, { ttl: 60 }); // 1 分钟
// 相对稳定的数据 - 中 TTL
await app.cache.default.wrap('user:info', async () => {
return await fetchUserInfo();
}, { ttl: 600 }); // 10 分钟
// 几乎不变的数据 - 长 TTL
await app.cache.default.wrap('system:config', async () => {
return await fetchSystemConfig();
}, { ttl: 3600 }); // 1 小时
3. 避免缓存雪崩
缓存雪崩是指大量缓存同时过期,导致瞬间的数据库压力激增。解决方法是给 TTL 加上随机值:
// 在基础 TTL 上增加随机时间
const ttl = 300 + Math.floor(Math.random() * 60); // 300-360 秒
await app.cache.default.set('key', 'value', ttl);
4. 及时清除过期缓存
在数据变更(增删改)时,记得清除相关缓存:
// 更新后清除单条缓存
await app.cache.default.del(`user:${userId}`);
// 删除多条缓存
await app.cache.default.del([`user:${userId}`, `user:list`]);
// 清空所有缓存(慎用)
await app.cache.default.reset();
性能优化建议
-
选择合适的缓存方式
- 开发/测试:Memory
- 生产单机:FS 或 Redis
- 生产集群:Redis
-
合理设置 TTL
- 避免设置过长导致数据不一致
- 避免设置过短失去缓存意义
-
缓存粒度控制
- 细粒度:单条数据缓存(如
user:123) - 粗粒度:列表缓存(如
user:list) - 根据业务场景选择
- 细粒度:单条数据缓存(如
-
监控缓存命中率
- 定期检查缓存使用情况
- 优化低命中率的缓存策略
总结
ruoyi-eggjs-cache 是一个轻量且强大的 Egg.js 缓存插件,它的优势在于:
- 多种存储:Memory、FS、Redis 三种方式,适应不同场景
- API 简洁:统一的接口,学习成本低
- 开箱即用:默认配置即可使用,无需复杂配置
- 智能降级:Redis 不可用时自动降级,保障稳定性
- 开发友好:开发环境自动短 TTL,调试无烦恼
无论是初创项目还是大型应用,合理使用缓存都能带来显著的性能提升。如果你正在使用 Egg.js,不妨试试这个插件,让你的应用飞起来!
- 插件地址:ruoyi-eggjs-cache
- 项目地址:RuoYi-Eggjs
- 开发文档:RuoYi-Eggjs 文档
6万+

被折叠的 条评论
为什么被折叠?



