一、为什么需要关注缓存配置?

想象一下你正在运营一个日活百万的电商平台,每次用户查询商品详情都要从数据库读取数据,数据库就像被无数人同时按门铃的快递小哥,迟早会崩溃。这时候缓存就像小区门口的快递柜,能临时存放热门商品数据。但快递柜如果太小(缓存容量不足)或者包裹过期不清理(缓存时间过长),要么新包裹塞不进去,要么用户拿到过期的商品信息——这就是我们今天要解决的OpenResty缓存配置难题。


二、OpenResty缓存基础套餐

OpenResty提供两大缓存神器:

  1. 共享字典(ngx.shared.DICT) - 类似小区公共储物柜,所有租户共享空间
  2. 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集群 分布式存储 增加网络延迟

六、避坑备忘录

  1. 雪崩预防:批量设置缓存时,给过期时间加随机数(如60±5秒)
  2. 穿透防护:对空结果设置较短有效期(建议5-10秒)
  3. 内存监控:定期检查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缓存,配合主动/被动过期策略,就像给程序制定了科学的健身计划。记住三个黄金法则:监控内存水位、避免集中过期、关键数据主动更新。