在查询商品时,优先查询OpenResty的本地缓存,需求:
1.修改item.lua中的read_data函数,优先查询本地缓存,未命中时再查询Redis、Tomcat
2.查询Redis或Tomcat成功后,将数据写入本地缓存,并设置有效期
3.商品基本信息,有效期30分钟
4.库存信息,有效期1分钟
1、nginx.conf
#user nobody;
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
access_log "D:/dev/openresty-1.19.9.1/logs/item.log";
error_log "D:/dev/openresty-1.19.9.1/logs/item.error" info;
#加载lua 模块
lua_package_path "D:/dev/openresty-1.19.9.1/lualib/?.lua;;";
#加载c模块
lua_package_cpath "D:/dev/openresty-1.19.9.1/lualib/?.so;;";
# 添加共享字典,也就是本地缓存,名称叫做:item_cache,大小150m
lua_shared_dict item_cache 150m;
server {
listen 80;
server_name localhost;
location /item {
proxy_pass http://192.168.8.70:8081;
proxy_redirect off;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_connect_timeout 3000;
}
location ~ /item/(\d+) {
# 响应类型,这里返回json
default_type application/json;
# 响应数据由 lua/item.lua这个文件来决定
content_by_lua_file lua/item.lua;
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
2、item.lua脚本
-- 引入自定义工具模块 local common = require("common") local read_http=common.read_http local read_redis=common.read_redis -- 导入cjson库 local cjson = require("cjson") --获取本地缓存对象 local item_cache=ngx.shared.item_cache -- 封装函数,先查询redis,再查询http local function read_data1(key, expire, path, params) ngx.log(ngx.INFO, "path=", path) -- 查询本地缓存 local val = item_cache:get(key) if not val then ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询redis,key:", key) -- 查询redis val = read_redis("127.0.0.1", 6379, key) ngx.log(ngx.INFO, "查询Redis数据, val = ", val) -- 判断redis是否命中 if not val then ngx.log(ngx.INFO, "Redis查询失败,尝试查询http") ngx.log(ngx.INFO, path, params) -- Redis查询失败,查询http val = read_http(path, params) end end ngx.log(ngx.INFO, "val=", val) -- 查询成功,把数据写入本地缓存,单位秒 -- item_cache:set(key, val, expire) -- 返回结果 return val end --获取路径参数 local id=ngx.var[1] -- 根据id查询商品 local paths = "/item/"..id local itemJSON=read_data1("item:id:"..id,60,paths,nil) --根据id查询商品库存 paths = "/item/stock/"..id local itemStockJSON=read_data1("item:stock:id:"..id,paths,nil) -- JSON转换为lua的table local item = cjson.decode(itemJSON) local itemStock = cjson.decode(itemStockJSON) -- 组合数据 item.stock = itemStock.stock -- 商品库存 item.sold = itemStock.sold -- 商品销量 -- 把item系列化JSON,并返回结果 ngx.say(item.name)
3、common.lua工具类
--引入redis模块 local redis = require("resty.redis") --初始化Redis对象 local red = redis:new() --设置Redis超时时间 red:set_timeouts(5000,5000,5000) -- 释放Redis连接API -- 关闭redis连接的工具方法,其实是放入连接池 local function close_redis(red) local pool_max_idle_time = 10000 -- 连接的空闲时间,单位是毫秒 local pool_size = 100 --连接池大小 local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) if not ok then ngx.log(ngx.ERR, "放入redis连接池失败: ", err) end end -- 读取Redis数据的API -- 查询redis的方法 ip和port是redis地址,key是查询的key local function read_redis(ip, port, key) -- 获取一个连接 local ok, err = red:connect(ip, port) -- ok, err = red:auth("123456") -- redis设置的密码 if not ok then ngx.log(ngx.ERR, "连接redis失败 : ", err) return nil end -- 查询redis local resp, err = red:get(key) -- 查询失败处理 if not resp then resp = nil ngx.log(ngx.ERR, "查询Redis失败: ", err, ", key = " , key) end --得到的数据为空处理 if resp == ngx.null then resp = nil ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key) end close_redis(red) return resp end -- 封装函数,发送http请求,并解析响应 local function read_http(path, params) ngx.log(ngx.INFO, "http请求进来了path:", path,",params:", params) local resp = ngx.location.capture(path,{ method = ngx.HTTP_GET, args = params, }) ngx.log(ngx.INFO, "http请求返回结果,resp.status:", resp.status, ",resp.body:", resp.body) if not resp then -- 记录错误信息,返回404 ngx.log(ngx.ERR, "http not found, path: ", path , ", args: ", args) ngx.exit(404) end return resp.body end -- 将方法导出 local _M = { read_http = read_http, read_redis = read_redis } return _M