分布式鎖是為了保證分布式各系統對於資源的強佔,獨佔。分布式鎖的設計與多執行緒鎖設計一樣,都是通過乙個訊號量,對它進行cas(compare and set)原子操作來實現樂觀鎖,或通過乙個獨佔鎖實現悲觀鎖,悲觀鎖不推薦。
樂觀鎖的核心是通過訊號量代表資源,通過cas的操作去標誌改訊號被占用。cas成功,代表資源沒有被占用,執行任務;cas失敗,代表資源被占用或處理過,不執行改資源。
失敗後迴圈cas的操作就叫做無鎖自旋
。juc原始碼中,鎖的實現,就是通過safe進行無鎖自旋。
分布式鎖的應用 - 定時任務
分布式鎖在定時任務時會被使用到。分布式服務上,每個服務都有定時任務,如何保證定時任務執行的資源只執行一次,可以用分布式鎖來鎖住資源實現。也可以使用hash資源定位服務來實現。
定時任務分布式鎖按鎖的粒度,有兩種思路實現。一種是定時任務加鎖,即乙個定時任務,只可在乙個服務上執行;另一種是定時任務的每個資源加鎖,即定時任務在所有服務上都執行,但是每個資源自會在乙個服務節點執行。
定時任務,定時任務加鎖
給定時任務加上乙個訊號量,定時任務執行時,cas一下,如果訊號加上去,就代表沒有其他節點執行定時任務,就執行;如果cas失敗,就代表已經執行了,就不要再執行這次任務了。
下面一種通過資料庫來實現 ,我們加上乙個定時任務表,欄位有執行時間,version欄位,每個定時任務對應表中的一條記錄,通過update ... where version = and update_date=
做cas操作。分布式系統cas操作失敗,代表該定時任務已被其他節點執行,它就不用執行了。
create
table
`job_mutex`
(`id`
int(10)
unsigned
notnull
auto_increment
,`job_type`
tinyint(3
)not
null
,`update_time`
datetime
default
null
,`version`
int(12)
default
'0',
primary
key(
`id`))
engine
=innodb
auto_increment=6
default
charset
=utf8mb4 collate
=utf8mb4_bin
querytaskjobscheduwait
(jobtype)
;//update job_mutex set version=#, update_time=# where version=# and to_days(update_time) = to_days(#)
//定時任務一天執行一次
ifupdateversontoday
(taskjobschedu, taskjobschedu.
getversion()
+1,new
date()
))
噹噹的開源專案elastic-job就有如此實現定時任務,按每個任務加鎖
如果想將分布式鎖的粒度放在每個資源上,即定時任務在每個節點服務上都執行,但是它們執行的資源不會重複。這個可以通過雙寫來解決。執行前先通過cas寫資源到乙個中間狀態,執行成功結束後,將資源寫到完成狀態。加上乙個過期設定,如中間狀態15分鐘後,就認為資源執行失敗,回滾重新執行。
這裡是一種通過redis和db雙寫來實現資源的,這裡通過redistemplate的setisabsent來做原子操作,db中資源那張表,加個字段表示是否執行定時任務。
如果執行任務失敗,它就不會寫到db,在redis中的key超時後的定時任務會再次執行這個任務。
list
tasks =
getnotexecutetaskindb()
;for
(task task: tasks)
}
悲觀鎖亦可實現,但不推薦,悲觀鎖使用資料庫可以用select for update
來獨佔資源。 Redis分布式鎖實現以及避免死鎖
分布式鎖 當多個程序不在同乙個系統中,用分布式鎖控制多個程序對資源的訪問 import com.demo.common.redissonmanager import org.redisson.api.rlock component slf4j public class closeordertask ...
利用redis分布式鎖的功能來實現定時器的分布式
以前為部門內部開發過乙個定時器程式,這個定時器很簡單,就是配置quartz,來實現定時呼叫配置的url功能。最近為了防止定時器所在的伺服器由於特殊原因掛掉,需要對定時器做多機部署。那麼如果按照原來的方式進行部署,就會遇到在一定的間隔時間內,可能出現多次重複呼叫的問題。為了解決這個問題,我就借助了re...
go 定時器 程序記憶體資訊 redis分布式鎖
通過newtimer和newticker分別實現定時器 package main import fmt time func main fmt.println time.now utc starting.timer time.newtimer time.second 2 定時2s ticker tim...