nginx-lua缓存机制

一. 简述:

缓存是一个大型系统中非常重要的一个组成部分。在硬件层面,大部分的计算机硬件都会用缓存来提高速度,比如CPU会有多级缓存、RAID卡也有读写缓存。在软件层面,我们用的数据库就是一个缓存设计非常好的例子,在SQL语句的优化、索引设计、磁盘读写的各个地方,都有缓存。一个生产环境的缓存系统,需要根据自己的业务场景和系统瓶颈,来找出最好的方案,这是一门平衡的艺术。

通常情况下,缓存有两个原则:

  1. 尽量靠近用户:如能用本地缓存的就不要发送HTTP请求,能用CDN缓存的就不要打到web服务器,能用nginx缓存的就不要用数据库的缓存。
  2. 尽量使用本进程和本机:因为跨了进程和机器甚至机房,缓存的网络开销就会变大,在高并发的时候会非常明显。

二. 关于nginx lua缓存:

在nginx的lua模块中,通常情况下,可采用两种缓存方式;

  1. 跨worker共享:lua_shared_dict

在使用前,需要在配置文件中进行声明:

复制代码
#/etc/nginx/nginx.conf
lua_shared_dict my_cache 20m;

调用代码片段:

复制代码
function get_from_cache(key)
    local cache_ngx = ngx.shared.my_cache
    local value = cache_ngx:get(key)
    return value
end

function set_to_cache(key, value, exptime)
    if not exptime then
        exptime = 0
    end

    local cache_ngx = ngx.shared.my_cache
    local succ, err, forcible = cache_ngx:set(key, value, exptime)
    return succ
end

--这里面用的就是ngx shared dict cache。如同它的名字一样,这个cache是nginx所有worker之间共享的,内部使用的LRU算法来判断缓存是否在内存占满时被清除。

2)worker独享:lua LRU cache

代码片段:

复制代码
local _M = {}

-- alternatively: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"

-- we need to initialize the cache on the lua module level so that
-- it can be shared by all the requests served by each nginx worker process:
local c = lrucache.new(200)  -- allow up to 200 items in the cache
if not c then
    return error("failed to create the cache: " .. (err or "unknown"))
end

function _M.go()
    c:set("dog", 32)
    c:set("cat", 56)
    ngx.say("dog: ", c:get("dog"))
    ngx.say("cat: ", c:get("cat"))

    c:set("dog", { age = 10 }, 0.1)  -- expire in 0.1 sec
    c:delete("dog")
end

return _M

-- 这个cache是worker级别的,不会在nginx wokers之间共享。并且,它是预先分配好key的数量,而shared dcit需要自己用key和value的大小和数量,来估算需要把内存设置为多少。

两者差异:

  1. shared.dict 使用的是共享内存(相对占用较少),每次操作都是全局锁,如果高并发环境,不同worker之间容易引起竞争。所以单个shared.dict的体积不能过大。lrucache是worker内使用的,由于nginx是单进程方式存在,所以永远不会触发锁,效率上有优势,并且没有shared.dict的体积限制,内存上也更弹性,但不同worker之间数据不同享,同一缓存数据可能被冗余存储。

  2. lua lru cache提供的API比较少,现在只有get、set和delete,而ngx shared dict还可以add、replace、incr、get_stale(在key过期时也可以返回之前的值)、get_keys(获取所有key,虽然不推荐)。

相关推荐
mengzhi啊8 小时前
缓存类CacheDataManager把临时数据存入json。做成插件·
qt·缓存·json
小lu飞12 小时前
DeepSeek Flash 降价的技术账本:缓存友好型定价如何改写推理成本结构
缓存
hweiyu0014 小时前
Redis命令:APPEND
redis·缓存
敲代码的嘎仔14 小时前
从集群锁失效到异步领券:我用分布式锁 + Redisson + MQ 把领券接口 RT 从 200ms 压到 15ms
java·数据库·redis·分布式·缓存·ai·wpf
MetaLite18 小时前
Spring Cache只留注解-MetaLite如何二开缓存运行时
java·spring·缓存
wdfk_prog19 小时前
lely-canopen-rtt:为什么推荐在 RT-Thread 上使用 Lely CANopen 构建主站
java·运维·缓存·docker·容器
莫得感情 o19 小时前
Redis 12 · 缓存一致性:数据库与缓存双写怎么不乱
redis·缓存
李兆龙的博客21 小时前
问津集 #24:LiquidCache——面向过滤的缓存编码与计算下推
缓存
爱上网的小舟21 小时前
着色器缓存大小设置多少合适?N卡A卡缓存路径与清理方法
缓存·着色器
草莓熊Lotso1 天前
【Redis 初阶】C++ 客户端实战:从 RESP 协议到 redis-plus-plus 工程化用法
linux·开发语言·网络·数据库·c++·redis·缓存