高并发-Redis分布式锁setnx,setex连用
Lua在Redis中的使用方式
? redis中內嵌了Lua腳本的解釋器,并提供了執行Lua腳本的入口“eval”命令,
? 格式為 EVAL script numkeys key [key ...] arg [arg...] .
? 其中eval 為命令, script為執行的命令腳本, numkeys 為腳本中共涉及到的key的數量,后續接收若干個key的輸入和若干個arg的輸入.
? 整個腳本中使用KEYS[index],和ARGS[index]來獲取實際的輸入有點類似于SQL的占位符。另外一層原因由于Redis集群的固有模式導致EVAL在集群中涉及多個KEY的操作時要求所有的KEY都在同一個Hash Solt上,集群環境中調用EVAL Redis會對腳本先做一個的校驗。
KEYS[1] KEYS[2],是要操作的鍵,可以指定多個,在lua腳本中通過KEYS[1], KEYS[2]獲取?!咎貏e注意】這些鍵要現在redis中存在,不然就獲取不到對應的值。
ARGV[1] ARGV[2],參數在lua腳本中通過ARGV[1], ARGV[2]獲取。
redis 執行Lua的保證
? Redis中保證對一個Lua腳本執行的完整性,也就是說一個Lua腳本的執行只會有成功和失敗,且保證在Redis Server端同時只會有一個Lua腳本在運行,這樣就意味著Lua腳本中的操作是一個完整的原子操作,不會伴隨中間狀態和資源競爭,同時也意味著在Lua腳本中不適合進行一些耗時長的操作.由于有以上的保證,使用Redis來進行一些復雜的原子操作就在合適不過了,setNx方法的局限性也被Redis Lua進行了彌補.
? Redis對嵌入的Lua做了若干的限制,包保證腳本不對Redis 造成破壞.不提供訪問系統狀態的庫,禁止使用loadfile函數,禁止帶有隨機性質的命令或者帶有副作用的命令, 對隨機讀命令的結果進行排序,替換math原有的random方法,不允許定義函數,不允許聲明全局變量等等.
要注意的是Lua中 0 為 true。
在腳本中調用redis命令
在腳本中可以使用redis.call函數調用Redis命令
redis.call('set', 'foo', 'bar')
local value=redis.call('get', 'foo') --value的值為bar
redis.call函數的返回值就是Redis命令的執行結果
Redis命令的返回值有5種類型,redis.call函數會將這5種類型的回復轉換成對應的Lua的數據類型。
Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在時,為 key 設置指定的值。
Redis分布式鎖
分布鎖滿足兩個條件,一個是加有效時間的鎖,一個是高性能解鎖
采用redis命令setnx(set if not exist)、setex(set expire value)實現
【千萬記住】解鎖流程不能遺漏,否則導致任務執行一次就永不過期
分布式鎖setnx、setex的缺陷,在setnx和setex中間發生了服務down機
從Redis宕機講解分布式鎖執行的異常場景流程
從Server服務宕機講解分布式鎖執行的異常場景流程
在setnx和setex中間發生了服務down機 那么key將沒有超時時間 會一直存在,新的請求永遠進不來
解決方案:
由于setnx與setex是分步進行,那么我們將兩步合成一步,放在同一個原子中即可
怎么一次性執行過一條命令而不會出現問題,采用Lua腳本
Redis從2.6之后支持setnx、setex連用
Lua簡介
從 Redis 2.6.0 版本開始,通過內置的 Lua 解釋器,可以使用 EVAL 命令對 Lua 腳本進行求值。
* Redis 使用單個 Lua 解釋器去運行所有腳本,并且, Redis 也保證腳本會以原子性(atomic)的方式執行:當某個腳本正在運行的時候,不會有其他腳本或 Redis 命令被執行。這和使用 MULTI / EXEC 包圍的事務很類似。在其他別的客戶端看來,腳本的效果(effect)要么是不可見的(not visible),要么就是已完成的(already completed)。
在 Lua 腳本中,可以使用redis.call()來執行 Redis 命令
Lua腳本配置流程
1、在resource目錄下面新增一個后綴名為.lua結尾的文件
2、編寫lua腳本
local lockKey = KEYS[1]
local lockTime = KEYS[2]
local lockValue = KEYS[3]
-- setnx info
local result_1 = redis.call('SETNX', lockKey, lockValue)
if result_1 == 1
then
local result_2= redis.call('SETEX', lockKey,lockTime, lockValue)
return result_2
else
return 'faild'
end
3、傳入lua腳本的key和arg
4、調用redisTemplate.execute方法執行腳本
總結
以上是生活随笔為你收集整理的高并发-Redis分布式锁setnx,setex连用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云ecs配置辅助网卡绑定公网ip地址
- 下一篇: 中信银行信用卡怎么修改账单日?这些事项要