openresty開發系列26--openresty中使用redis模塊


openresty開發系列26--openresty中使用redis模塊

在一些高並發的場景中,我們常常會用到緩存技術,現在我們常用的分布式緩存redis是最知名的,

操作redis,我們需要引入redis模塊 require "resty.redis";

我們現在做個可以操作redis進行賦值,讀值的案例

一)連接redis服務器

---定義 redis關閉連接的方法
local function close_redis(red)  
    if not red then  
        return  
    end  
    local ok, err = red:close()  
    if not ok then  
        ngx.say("close redis error : ", err)  
    end  
end  

local redis = require "resty.redis"  --引入redis模塊
local red = redis:new()  --創建一個對象,注意是用冒號調用的
--設置超時(毫秒)  
red:set_timeout(1000)
--建立連接  
local ip = "10.11.0.215"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
    ngx.say("connect to redis error : ", err)  
    return close_redis(red)  
end  
--調用API設置key  
ok, err = red:set("msg", "hello world")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  
--調用API獲取key值  
local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end

ngx.say("msg : ", resp)
close_redis(red)  

請求結果   msg : hello world

--------------------------------
注意:得到的數據為空處理 ,redis返回的空 為null,所以不能用nil判斷,而要用ngx.null判斷
if resp == ngx.null then  
    resp = ''  --比如默認值  
end  


--------------連接授權的redis-----------------
在redis.conf配置文件 配置認證密碼
requirepass redis123

注意:windows 啟動redis時,配置redis.windows.conf;並且不能直接 雙擊redis-server.exe,
如果雙擊啟動,默認不會找此目錄下的配置文件;需要指定配置文件
解決方案:
1)cmd窗口中 運行 redis-server.exe redis.windows.conf
2)新建一個bat批處理文件  文件內容 redis-server.exe redis.windows.conf


連接報錯set msg error : NOAUTH Authentication required.因為認證出錯
在red:connect成功后,調用red:auth認證密碼

ok, err = red:auth("redis123")
if not ok then
    ngx.say("failed to auth: ", err)
    return close_redis(red)
end


二)redis連接池

redis的連接是tcp連接,建立TCP連接需要三次握手,而釋放TCP連接需要四次握手,而這些往返時延僅需要一次,
以后應該復用TCP連接,此時就可以考慮使用連接池,即連接池可以復用連接。
我們需要把close_redis函數改造一下

local function close_redis(red)  
    if not red then  
        return  
    end  
    --釋放連接(連接池實現)  
    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.say("set keepalive error : ", err)  
    end
end

即設置空閑連接超時時間防止連接一直占用不釋放;設置連接池大小來復用連接。
注意:
1、連接池是每Worker進程的,而不是每Server的;
2、當連接超過最大連接池大小時,會按照LRU算法回收空閑連接為新連接使用;
3、連接池中的空閑連接出現異常時會自動被移除;
4、連接池是通過ip和port標識的,即相同的ip和port會使用同一個連接池(即使是不同類型的客戶端);
5、連接池第一次set_keepalive時連接池大小就確定下了,不會再變更;

注意:我們如何知道,redis連接對象是從連接池中獲取的,還是新創建的連接呢??

使用 red:get_reused_times --->得到此連接被使用的次數

如果當前連接不是從內建連接池中獲取的,該方法總是返回 0 ,也就是說,該連接還沒有被使用過。

如果連接來自連接池,那么返回值永遠都是非零。所以這個方法可以用來確認當前連接是否來自池子。



連接優化

采用連接池,連接帶認證的redis

---定義 redis關閉連接的方法
local function close_redis(red)  
    if not red then  
        return  
    end  
    --釋放連接(連接池實現)  
    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.say("set keepalive error : ", err)  
    end  
end   

local redis = require "resty.redis"  --引入redis模塊
local red = redis:new()  --創建一個對象,注意是用冒號調用的
--設置超時(毫秒)  
red:set_timeout(1000)
--建立連接  
local ip = "10.11.0.215"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
    ngx.say("connect to redis error : ", err)  
    return close_redis(red)  
end  

local count, err = red:get_reused_times()
if 0 == count then ----新建連接,需要認證密碼
    ok, err = red:auth("redis123")
    if not ok then
        ngx.say("failed to auth: ", err)
        return
    end
elseif err then  ----從連接池中獲取連接,無需再次認證密碼
    ngx.say("failed to get reused times: ", err)
    return
end

--調用API設置key  
ok, err = red:set("msg", "hello world333333333")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  
--調用API獲取key值  
local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end

ngx.say("msg : ", resp)
close_redis(red)

=======================================

注意:連接池使用過程中,業務代碼有select方法,會導致數據錯亂

ok, err = red:select(1)  --->選擇db
if not ok then
    ngx.say("failed to select db: ", err)
    return
end

如:
A業務使用了db1,所以使用了 select(1);

B業務使用默認的db0,select(0)遺漏

但A,B業務共用了連接池,很有可能 B業務拿到的 A業務使用的連接,而此連接操作的數據庫db1;
而B業務中代碼沒有指定select數據庫,所以B業務操作數據到了db1中;導致數據錯亂


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM