1.需求背景
在一些寫接口的場景下,由於一些網絡因素導致用戶的表單重復提交,就會在相鄰很短的時間內,發出多個數據一樣的請求。后台接口的冪等性保證一般都是先檢查數據的狀態,然后決定是否進行執行寫入操作,最后更新狀態。那么在這個很短的時間內,數據可能還沒來及寫入,多個請求同時進入了狀態判斷的邏輯,此時就可能繞過檢查,執行多次重復的寫入。
在此給出的解決方案是,使用redis分布式鎖,控制用戶的請求串行處理:客戶端的請求進入時,基於用戶的維度進行搶鎖,搶到了就可以往下執行邏輯,搶不到鎖的請求直接被拒絕。
2.redis分布式鎖的使用
2.1.使用下面的命令獲取鎖:
SET resource_name my_random_value EX 100 NX
當 resource_name 不存在的時候設置,將值設置為 my_random_value 同時指定 100秒過期時間,my_random_value 必須在鎖定請求中絕對唯一,用於后面的解鎖釋放。
2.2.使用Lua腳本解鎖:
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
這段Lua腳本執行的時候將 resource_name 作為 KEYS[1],將 my_random_value 作為 ARGV[1] 的值傳進去,只有當 my_random_value 的值恰好是之前存的值,才刪除它。
3. Redlock算法的高級鎖
Redlock算法 的介紹可以看Redis官網,關於這個算法的安全性問題,發生過一場 爭論 ,在此不展開分析。
就我目前的業務中是直接使用雲廠商 集群版的redis,客戶端的連接上只有一個實例,業務開發時等效於單機版來使用,雲廠商負責后面的主從支持。那么使用單redis節點的鎖方案就足夠了,簡單且效率高;用不了,也沒法用 Redlock算法的高級鎖方案。其實,最后是一個問題,有沒有必要去使用 Redlock這個過重的實現?還是看個人負責的業務場景吧,就我目前的業務需求是用不上的,也許后續會有更嚴苛的業務場景,到那時再會。