一、为什么需要关注缓存配置?
想象一下你正在运营一个日活百万的电商平台,每次用户查询商品详情都要从数据库读取数据,数据库就像被无数人同时按门铃的快递小哥,迟早会崩溃。这时候缓存就像小区门口的快递柜,能临时存放热门商品数据。但快递柜如果太小(缓存容量不足)或者包裹过期不清理(缓存时间过长),要么新包裹塞不进去,要么用户拿到过期的商品信息——这就是我们今天要解决的OpenResty缓存配置难题。
二、OpenResty缓存基础套餐
OpenResty提供两大缓存神器:
- 共享字典(ngx.shared.DICT) - 类似小区公共储物柜,所有租户共享空间
- lua-resty-lrucache - 就像每家每户的私人储物箱,独立管理
2.1 共享字典容量设置
在nginx.conf里配置共享内存,就像给小区采购储物柜:
http {
lua_shared_dict my_cache 200m;
server {
listen 80;
location / {
content_by_lua_block {
local cache = ngx.shared.my_cache
-- 存入缓存(有效期60秒)
cache:set("iphone15", "{price:6999}", 60)
-- 读取缓存
ngx.say(cache:get("iphone15"))
}
}
}
}
容量陷阱:实际可用空间约为配置值的95%(预留空间给元数据)
2.2 LRU缓存容量控制
当需要精细化控制时,lua-resty-lrucache更适合:
local lrucache = require "resty.lrucache"
-- 创建最多存储1000个元素的缓存池
local cache, err = lrucache.new(1000)
if not cache then
ngx.log(ngx.ERR, "创建缓存失败: ", err)
return
end
-- 设置缓存(带30秒有效期)
cache:set("user_123", "{name:'老王'}", 30)
-- 获取时自动检查过期
local user = cache:get("user_123")
三、过期时间的花式玩法
3.1 被动过期(懒人模式)
local function get_product(id)
local product = cache:get(id)
if not product then
-- 缓存穿透保护
product = query_db(id)
cache:set(id, product, 60) -- 设置60秒保鲜期
end
return product
end
适合场景:商品详情页等低频变更数据
3.2 主动过期(强迫症模式)
local function update_product(id, new_data)
-- 先更新数据库
db_update(id, new_data)
-- 立即让旧缓存失效
cache:delete(id)
-- 或者设置0秒立即过期
cache:set(id, new_data, 0)
end
适合场景:秒杀库存等需要实时性的数据
四、实战中的组合拳
案例:API限速防护
location /api {
access_by_lua_block {
local limit = 100 -- 每分钟100次
local client_ip = ngx.var.remote_addr
-- 使用共享字典计数
local counter = ngx.shared.api_limit
local current = counter:get(client_ip) or 0
if current >= limit then
ngx.exit(429)
end
-- 原子操作递增(设置60秒过期自动清理)
counter:incr(client_ip, 1, 0, 60)
}
}
这个配置实现:每个IP每分钟最多100次请求,计数器60秒自动清零
五、技术选型指南
方案 | 优点 | 缺点 |
---|---|---|
共享字典 | 跨Worker共享数据 | 容量需预先分配 |
LRU缓存 | 内存控制精准 | 单Worker独立存储 |
Redis集群 | 分布式存储 | 增加网络延迟 |
六、避坑备忘录
- 雪崩预防:批量设置缓存时,给过期时间加随机数(如60±5秒)
- 穿透防护:对空结果设置较短有效期(建议5-10秒)
- 内存监控:定期检查shared dict使用率
local free_bytes = ngx.shared.my_cache:free_space() ngx.log(ngx.INFO, "剩余内存:", free_bytes)
七、性能参数对照表
操作类型 | QPS(单Worker) |
---|---|
共享字典读 | 200,000+ |
LRU缓存读 | 500,000+ |
带过期时间写入 | 150,000+ |
八、终极总结
缓存配置就像给程序做饮食管理——缓存太小容易"营养不良"(缓存命中率低),缓存过大导致"肥胖症"(内存溢出)。通过合理搭配共享内存与LRU缓存,配合主动/被动过期策略,就像给程序制定了科学的健身计划。记住三个黄金法则:监控内存水位、避免集中过期、关键数据主动更新。