1. 程式人生 > >關於分散式鎖的一種實現思路

關於分散式鎖的一種實現思路

需求語言描述:多個節點競爭同一資源,且只能有一個節點競爭成功;

場景描述:

  最近在做一個數據同步程式,因為es出色的查詢效能以及為了減輕與底層資料庫的互動,將底層資料庫如sqlserver中的資料同步到es。

  在做了定時任務的統一排程和配置之後,由於是多人協同開發,所以各自本地都可能啟動一個例項,那麼就相當於多個例項。但是同一個同步程式(定時任務)在指定時間內我們只想排程(觸發)一次,而多個例項同時觸發,由於也沒有做es的鎖的控制,所以發現es會寫入重複的資料。舉個栗子,比如一個名為 “jobBondGuarantor”的定時任務,cron表示式設定的4個小時排程一次,那麼12點的時候,在沒有人修改排程表示式的時候,所有本地例項都會觸發定時任務,這樣就會造成es寫入資料重複(A例項先寫,B例項後寫),同理,16點,20點,8點等等,都有這樣的問題。

解決:

  1.Redis分佈鎖,本人這次沒采用這個,所以自行百度哈;

  2.利用資料庫的排他鎖,加上冪等解決。

 

解釋:

資料庫設計

更新sql(冪等):

  資料庫更新時的排他鎖,就是當有一個執行緒(程序)更新這條資料時,那麼其他執行緒就不能更新這條資料了,這個鎖一般都是行級鎖,其他執行緒一般會等待獲取鎖,等拿到鎖之後執行相應的更新,如果超時則會取消,這個不絕對,和你用的持久層框架有關,你也可以自己寫持久層互動。

  那麼為什麼要用冪等呢,比如A執行緒先搶到鎖,更新了,將 IS_SYNC更新為1了,返回影響行數1行,這個沒問題,B執行緒在等待A執行緒更新完資料釋放鎖之後,獲取到鎖,執行更新,如果不用冪等,只是update edr_cloud_sync_job set is_sync =1 where job_name = ..., 那麼B執行緒更新返回影響行數也是1,我們無法區分AB執行緒到底是誰更新了is_sync=1,而用冪等,那麼B執行緒則會查不出資料,因為is_sync已經被A執行緒更新為1了,所以加上is_sync=0時,B執行緒更新返回影響行數為0。那麼就可以區分到底誰更改了is_sync=1,即有唯一一個執行緒更改資料成功,那麼由他執行此次的任務即可。

  一般而言,市面上資料庫預設更新時排他鎖,而且為行級鎖,如果是表級鎖也不是很適合用這個方法(一般也沒人會把更新做成表級鎖,即使需要,也另外設表),具體的還需要各位親測。