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中;導致數據錯亂
轉載于:https://www.cnblogs.com/reblue520/p/11434278.html
總結
以上是生活随笔為你收集整理的openresty开发系列26--openresty中使用redis模块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openresty开发系列25--ope
- 下一篇: openresty开发系列27--ope