一,為什么要使用redis作本地緩存?
1,使用緩存通常會有三層
當使用openresty作為web服務器時,我們更看重是的它可以通過lua編程的擴展能力,就openresty而言,它可以實現的功能非常多,
提高響應速度是web服務中非常重要的功能,
使用緩存通常會有三層:
本地緩存:存在於本地機器上,直接通過nginx訪問,避免網絡io;
redis cluster:存儲更多的供lua訪問的數據,也是通過nginx訪問直接返回,相比前一層緩存,增加了網絡io,但仍然避免了對業務系統的訪問;
業務緩存:供運行在tomcat/php-fpm/go http中內的業務代碼訪問。
可以比較得到本地緩存是響應速度最快的,通常可以在10ms內對請求進行響應。
我們看到的很多經過優化的BAT等大廠的站點都能在極短時間內響應請求,就是經過了層層優化的結果。
2,這里會提供一個例子:使用redis做商品詳情頁的cache:
流程:當用戶訪問時,
先從redis中獲取cache內容,
如果redis中不存在此value,則會改為訪問后端業務系統獲取cache
說明:在生產環境中,為方便更新,通常會采用redis的主從架構,
每台業務nginx上所配備的redis的數據能得到實時更新
說明:劉宏締的架構森林是一個專注架構的博客,地址:https://www.cnblogs.com/architectforest
對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/
說明:作者:劉宏締 郵箱: 371125307@qq.com
二,nginx的配置文件:
upstream backenditem { server 127.0.0.1:8000; } server { listen 8000; server_name 8000.test.com; location / { default_type 'text/html'; content_by_lua_block {ngx.say("hello world,this is path backend from 8000:uri:"..ngx.var.request_uri)} } } server { listen 82; server_name test.com; location ~ /backenditem/(.*) { rewrite /backenditem(/.*) $1 break; proxy_next_upstream error timeout; proxy_pass http://backenditem; } location /item { default_type text/html; content_by_lua_file /data/luacache/webroot/item_redis_cache.lua; } location / { default_type 'text/html'; content_by_lua_block {ngx.say("default path:uri:"..ngx.var.request_uri)} } }
說明:1,端口8000的server是一個demo,生產環境中,它應該是使用tomcat/php-fpm/django之類的業務系統
2,location ~ /backenditem/(.*) :負責upstream到后端業務系統,
注意這里要做一次 rewrite /backenditem(/.*) $1 break; ,作用是去掉用來標識要跳轉到后端的backenditem字串
3,content_by_lua_file 此處用絕對路徑指定了lua代碼的程序文件
三,lua程序文件: item_redis_cache.lua
--指定要訪問的lua包所在的路徑 package.path = package.path..";/data/luacache/webroot/config/?.lua;/data/luacache/webroot/lib/?.lua" local config = require "config_constant" local readhttp = require "read_http" local returnjson = require "return_json" --redis連接池工廠 local redis_factory = require('redis_factory')(config.redisConfig) --獲取redis的連接實例 local ok, redis_a = redis_factory:spawn('redis_a') --用於接收前端數據的對象 local args=nil --獲取前端的請求方式 並獲取傳遞的參數 local request_method = ngx.var.request_method --判斷是get請求還是post請求並分別拿出相應的數據 if "GET" == request_method then args = ngx.req.get_uri_args() elseif "POST" == request_method then ngx.req.read_body() args = ngx.req.get_post_args() --兼容請求使用post請求,但是傳參以get方式傳造成的無法獲取到數據的bug if (args == nil or args.data == null) then args = ngx.req.get_uri_args() end end --ngx.log(ngx.ERR,"args.key:",args.key) if args.itemid == nil or args.itemid=="" then local json = returnjson.getjson("1",'key not exist or key is empty',"") --ngx.log(ngx.ERR,"json:",json) ngx.say(json) else --獲取前端傳遞的itemid local itemid = args.itemid --在redis中獲取itemid對應的值 local va = redis_a:get(itemid) if va == ngx.null or va == nil then --ngx.log(ngx.ERR, "redis not found content, back to http, itemid : ", itemid) local url="/backenditem/item" va = readhttp.read(url,itemid) ngx.print(returnjson.getjson(0,itemid,va)) else --響應前端 ngx.say(returnjson.getjson(0,itemid,va)) end end
四,lua訪問redis的配置文件: config_constant.lua
config = {} config.redisConfig = { redis_a = { -- your connection name --ip host = '127.0.0.1', --端口 port = 6379, --密碼 pass = '', --超時時間,如果是測試環境debug的話,這個值可以給長一點;如果是正式環境,可以設置為200 timeout = 120000, --redis的庫 database = 0, }, } return config
五,lua程序文件:read_http.lua:用來從后端業務系統得到response
local read_http = {} function read_http.read(url,id) local resp = ngx.location.capture(url, { method = ngx.HTTP_GET, args = {id = id} }) if not resp then ngx.log(ngx.ERR, "request error :", err) return end if resp.status ~= 200 then ngx.log(ngx.ERR, "request error, status :", resp.status) return end return resp.body end return read_http
六,lua程序:return_json.lua :返回json字串
local return_json = {} function return_json.getjson(status,msg,data) local json = '{"status":"'..status..'","msg":"'..msg..'","data":"'..data..'"}' return json end return return_json
七,此項目的github地址:
https://github.com/liuhongdi/luacache
八,測試效果:
1,當有商品存在於redis中的返回 :如圖
2,當商品不存在於redis中的返回: 如圖
3,當參數錯誤時的返回 :如圖
九,文中涉及到的各平台的版本查看:
[root@localhost luacache]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core)
[root@localhost luacache]# /usr/local/openresty/bin/openresty -V nginx version: openresty/1.15.8.2 built by gcc 8.2.1 20180905 (Red Hat 8.2.1-3) (GCC) built with OpenSSL 1.1.0k 28 May 2019 TLS SNI support enabled
[root@localhost luacache]# /usr/local/soft/redis5/bin/redis-server --version Redis server v=5.0.7 sha=00000000:0 malloc=libc bits=64 build=8e31d2ed9a4c9593