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中;導致數據錯亂