分布式鎖的實現以及在定時器中的應用

2021-09-24 19:07:47 字數 2175 閱讀 9111

分布式鎖是為了保證分布式各系統對於資源的強佔,獨佔。分布式鎖的設計與多執行緒鎖設計一樣,都是通過乙個訊號量,對它進行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...