天天看點

Lua+OpenResty+nginx+redis+canal實作緩存政策

一、OpenResty介紹

OpenResty(又稱:ngx_openresty) 是一個基于 nginx的可伸縮的 Web 平台,由中國人章亦春發起,提供了很多高品質的第三方子產品。

OpenResty 是一個強大的 Web 應用伺服器,Web 開發人員可以使用 Lua 腳本語言調動 Nginx 支援的各種 C 以及 Lua 子產品,更主要的是在性能方面,OpenResty可以 快速構造出足以勝任 10K 以上并發連接配接響應的超高性能 Web 應用系統。

360,UPYUN,阿裡雲,新浪,騰訊網,去哪兒網,酷狗音樂等都是 OpenResty 的深度使用者。

OpenResty 簡單了解成 就相當于封裝了nginx,并且內建了LUA腳本,開發人員隻需要簡單的其提供了子產品就可以實作相關的邏輯,而不再像之前,還需要在nginx中自己編寫lua的腳本,再進行調用了。

安裝openresty

linux安裝openresty:

1.添加倉庫執行指令

Lua+OpenResty+nginx+redis+canal實作緩存政策

安裝nginx

預設已經安裝好了nginx,在目錄:/usr/local/openresty/nginx 下。

修改/usr/local/openresty/nginx/conf/nginx.conf,将配置檔案使用的根設定為root,目的就是将來要使用lua腳本的時候 ,直接可以加載在root下的lua腳本。

Lua+OpenResty+nginx+redis+canal實作緩存政策

二、廣告緩存的載入與讀取

需求分析

需要在頁面上顯示廣告的資訊。

解決方法 Lua+Nginx配置

(1)實作思路-查詢資料放入redis中

實作思路:

定義請求:用于查詢資料庫中的資料更新到redis中。

a.連接配接mysql ,按照廣告分類ID讀取廣告清單,轉換為json字元串。

b.連接配接redis,将廣告清單json字元串存入redis 。

定義請求:

Lua+OpenResty+nginx+redis+canal實作緩存政策
請求位址: http://192.168.xxx.xxx/update_content?id=1 建立/root/lua目錄,在該目錄下建立update_content.lua: 目的就是連接配接mysql 查詢資料 并存儲到redis中。
Lua+OpenResty+nginx+redis+canal實作緩存政策
修改/usr/local/openresty/nginx/conf/nginx.conf檔案: 添加頭資訊,和 location資訊
Lua+OpenResty+nginx+redis+canal實作緩存政策
定義lua緩存命名空間,修改nginx.conf,添加如下代碼即可:
Lua+OpenResty+nginx+redis+canal實作緩存政策
請求

可以實作緩存的添加

(2)實作思路-從redis中擷取資料

定義請求,使用者根據廣告分類的ID 擷取廣告的清單。通過lua腳本直接從redis中擷取資料即可。

請求:/read_content

參數:id

傳回值:json

在/root/lua目錄下建立read_content.lua:

Lua+OpenResty+nginx+redis+canal實作緩存政策
在/usr/local/openresty/nginx/conf/nginx.conf中配置如下:
Lua+OpenResty+nginx+redis+canal實作緩存政策

(3)加入openresty本地緩存

如上的方式沒有問題,但是如果請求都到redis,redis壓力也很大,是以我們一般采用多級緩存的方式來減少下遊系統的服務壓力。參考基本思路圖的實作。

先查詢openresty本地緩存 如果 沒有

再查詢redis中的資料,如果沒有

再查詢mysql中的資料,但凡有資料 則傳回即可。

修改read_content.lua檔案,代碼如下:

ngx.header.content_type="application/json;charset=utf8"
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
--擷取本地緩存
local cache_ngx = ngx.shared.dis_cache;
--根據ID 擷取本地緩存資料
local contentCache = cache_ngx:get('content_cache_'..id);
​
if contentCache == "" or contentCache == nil then
    local redis = require("resty.redis");
    local red = redis:new()
    red:set_timeout(2000)
    red:connect("192.168.211.132", 6379)
    local rescontent=red:get("content_"..id);
​
    if ngx.null == rescontent then
        local cjson = require("cjson");
        local mysql = require("resty.mysql");
        local db = mysql:new();
        db:set_timeout(2000)
        local props = {
            host = "192.168.211.132",
            port = 3306,
            database = "xxx_content",
            user = "root",
            password = "123456"
        }
        local res = db:connect(props);
        local select_sql = "select url,pic from tb_content where status ='1' and category_id="..id.." order by sort_order";
        res = db:query(select_sql);
        local responsejson = cjson.encode(res);
        red:set("content_"..id,responsejson);
        ngx.say(responsejson);
        db:close()
    else
        cache_ngx:set('content_cache_'..id, rescontent, 10*60);
        ngx.say(rescontent)
    end
    red:close()
else
    ngx.say(contentCache)
end
      

測試位址:

http://192.168.211.132/update_content?id=1

此時會将分類ID=1的所有廣告查詢出來,并存入到Redis緩存。

http://192.168.xxx.xxx/read_content?id=1

此時會擷取分類ID=1的所有廣告資訊。