在查詢商品時,優先查詢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