OpenResty的快速自动化多级缓存
这个库可以作为 key/value存储来处理,但是可以缓存Lua类型和表,但是构建在lua_shared_dict,lua-resty-lrucache上 ,这种组合可以实现高性能和灵活的缓存。
功能:
使用TTL缓存和负缓存,
通过lua-resty-lock构建互斥体,以防止在缓存失败时将狗堆影响到数据库/后端,
内置worker通信,传播缓存失效,并允许worker更新他们的L1 (lua-resty-lrucache )缓存的更改(set()
,delete()
),
可以创建多个独立实例来保存各种类型的数据,同时依赖同一lua_shared_dict
L2缓存
缓存级别层次结构为:
lua_shared_dict
内存区域,只有L1未命中时才能访问此级别,并防止工作人员请求L3缓存,1)下载lua-resty-mlcache
git clone https://github.com/thibaultcha/lua-resty-mlcache.git
#将下载下来的lua-resty-mlcache/lib/resty文件下的文件拷到/usr/local/openresty/lualib/project/common/lualib/resty
2)nginx.conf文件
user root;
worker_processes 2;
daemon off;#避免nginx在后台运行
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 20480;#单个进程允许的客户端最大连接数
}
http {
include mime.types;
#default_type application/octet-stream;
lua_code_cache off; #关闭代码缓存上线后去掉
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
lua_package_path "/usr/local/openresty/lualib/project/common/lualib/?.lua;;/usr/local/openresty/lualib/project/common/resty-redis-cluster/lib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/project/common/resty-redis-cluster/src/?.so;;";
lua_shared_dict redis_cluster_slot_locks 100k;
lua_shared_dict redis_cluster_addr 20k;
lua_shared_dict my_lock 20k; #锁
lua_shared_dict my_cache 1M; #缓存
lua_shared_dict ipc_shared_dict 1M; #进程间通讯
init_worker_by_lua_file /usr/local/openresty/lualib/project/init.lua;
server {
listen 80;
location / {
root /var/www/html;
content_by_lua_file /usr/local/openresty/lualib/project/cache.lua;
index index.php index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ \.php/?.* {
root /var/www/html;#php-fpm容器中的路径,不是nginx路径
fastcgi_pass 127.0.0.1:9002;#对应容器的端口
fastcgi_index index.php;
#为php-fpm指定的根目录
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #加了这一项
#定义变量$path_info,存放pathinfo信息
set $path_info "";
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
#将文件地址赋值给变量 $real_script_name
set $real_script_name $1;
#将文件地址后的参数赋值给变量 $path_info
set $path_info $2;
}
#配置fastcgi的一些参数
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
include /usr/local/openresty/nginx/conf/fastcgi_params;
}
}
}
3)cache.lua文件
local mlcache = require "resty.mlcache"
local resty_lock = require ("resty.lock")
local key = ngx.re.match(ngx.var.request_uri,"/([0-9]+).html")
--1、L1缓存使用lua_resty_lrucache
local function fetch_shop(key)
local lock = resty_lock:new("my_lock",{exptime=10,timeout=1})
if not lock then
ngx.log(ngx.ERR,"创建失败")
return
end
local flag_lock,err = lock:lock(key)
if err then
ngx.log(ngx.ERR,"加锁失败")
end
--如果加锁失败,获取旧数据
if not flag_lock then
local res = cache:get_stale(key)
ngx.log(ngx.ERR,"获取锁失败:占用")
return res
end
--锁成功获取,可能已经有人将值放入到缓存当中了,再检查下
local res,err = cache:get(key)
if res then
lock:unlock()
return res
end
-- ngx.sleep(2)
-- 如果仍然没有再请求服务器
local req_data
local method = ngx.var.request.method
if method == "POST" then
req_data = {method=ngx.HTTP_POST,body=ngx.req.read_body()}
elseif method == "PUT" then
req_data = {method=ngx.HTTP_PUT,body=ngx.req.read_body()}
else
req_data = {method=ngx.HTTP_GET}
end
local uri
if not ngx.var.request.uri then
uri = ''
end
local res,err = ngx.location.capture(
"/index.php"..uri,
req_data
)
if res.status == 200 then
ngx.say(res.body)
end
--解锁
lock:unlock()
end
if type(key) == "table" then
--创建L1缓存
local cache,err = mlcache.new("cache_name","my_cache",{
lru_size = 500, -- 用于定义基础L1缓存(lua-resty-lrucache实例)的大小
--ttl = 3600, -- 指定缓存值的到期时间
ttl = 5, -- 指定缓存值的到期时间
-- neg_ttl = 30, -- 指定缓存的未命中的过期时间(当L3回调返回时nil)
neg_ttl = 6, -- 指定缓存的未命中的过期时间(当L3回调返回时nil)
ipc_shm = "ipc_shared_dict", --用于将L2的缓存设置到L1
})
--如果没有值记录错误日志
if not cache then
ngx.log(ngx.ERR,"创建失败",err)
end
ngx.say(key[1])
--如果有值,获取值
local res,err = cache:get(key[1],nil,fetch_shop,key[1])
ngx.say(res)
-- 在L2缓存中设置一个值,并将事件广播到其他工作进程,
if not res then
cache:set(key[1],nil,res)
end
end