首頁  >  文章  >  資料庫  >  基於Redis分散式鎖的任務調度怎麼實現

基於Redis分散式鎖的任務調度怎麼實現

WBOY
WBOY轉載
2023-05-28 13:37:30627瀏覽

在分散式大量資料收集過程中,信源的管理尤其重要。為了確保同一任務在同一時間只能被一個採集器處理,必須確保任務調度的獨特性。通常我們在進行分散式資料收集時,一般情況下都會有一個調度模組,其主要的職責就是負責採集任務的分發,同時確保任務的唯一性。

由於是分散式,涉及多台伺服器(多機),每台伺服器又涉及到多個採集器(多進程),每個採集器又有可能涉及多執行緒,所以,任務調度模組中的鎖定機制顯得特別重要。根據應用的實作架構不同,鎖的實作方式通常可以分為以下幾種型別

  • #如果處理程序是單行程多執行緒的,在python下,就可以使用threading 模組的Lock 物件來限制對共享變數的同步訪問,實現線程安全。

  • 單機多進程的情況,在 python 下,可以使用 multiprocessing 的 Lock 物件來處理。

  • 多機多進程部署的情況,就得依賴一個第三方元件(儲存鎖定物件)來實現一個分散式的同步鎖了。

由於調度模組是多機多進程多執行緒的處理機制,所以符合第三種方式。

分散式鎖定實作方式

目前主流的分散式鎖定實作方式有以下幾種:

  • 基於資料庫來實現,如mysql

  • 基於快取來實現,如redis

  • 基於zookeeper 來實作

#每種實作方式各有千秋,綜合考量,Redis是最適合的選擇。主要原因是:

  • redis 是基於記憶體來操作,存取速度比資料庫快,在高並發下,加鎖之後的效能不會下降太多

  • redis 可以設定鍵值的生存時間(TTL)

  • #redis 的使用方式簡單,整體實作開銷小

#但是,使用redis 實作的分散鎖定還需要具備以下幾個條件:

  1. 同一個時刻只能有一個執行緒佔有鎖,其他執行緒必須等待直到鎖被釋放

  2. 鎖定的操作必須滿足原子性

  3. 不會發生死鎖,例如已取得鎖定的執行緒在釋放鎖定之前突然異常退出,導致其他執行緒會一直在循環等待鎖被釋放

  4. #鎖定的新增和釋放必須由同一個執行緒來設定

#我們使用redis 來實作一個分散式同步鎖,來確保資料的一致性,需滿足一下特點:

  • 滿足互斥性,同一個時刻只能有一個線程可以獲取鎖

  • 利用redis 的ttl 來確保不會出現死鎖,但同時也會帶來由於鎖過期引發的多執行緒同時佔有鎖的問題,需要我們合理設定鎖的過期時間來避免

  • 利用鎖的唯一性來確保不會出現誤刪鎖的情況


我在實際操作過程中,把調度模組從整個採集系統中拆離了出來,基於Java客戶端Jredis(JRedis是一個高效能的Java客戶端,用來連接到Redis分散式雜湊鍵-值資料庫。一個獨立的服務,使用Spring Boot實現了同步和非同步功能。以便其他各個採集器,透過HTTP方式請求所要處理的採集任務。其處理過程大致如下:

  • 採集器透過HTTP方式,向調度中心發送任務請求;

  • ##調度中心判斷鎖定是否存在,如果存在則直接傳回空集合;

  • 如果不存在鎖,則對請求加鎖,然後根據信源規則取得對應的採集任務;

  • 返回獲取到的任務(如果沒有待處理任務,則返回空),然後刪除鎖。

調度模組的程式碼實現,大致如下所示:

public static List fetchTask(String lockK ; result = new ArrayList();

     try {

         String dicNameLock = "Dispatcher_Task_Lock";// 任務排程鎖定;#! redisHashUtils.keyIsExit(dicNameLock, lockKeyValue)) {// 判斷鎖定是否存在

         // 新增鎖定(把任務唯一性識別寫入記錄);

# ,

            DateUtil.getYMDHMS());

         // 處理任務邏輯

        則................................................ ..................

          // 移除鎖定(任務唯一性識別);

          hsdi.remove(redisHashUtils, dicNameLock, KeyKeyKeyValue);

##很抱歉,您沒有提供需要重寫的原話,無法進行重寫else {

            //上存在

      暫時回到空白集合....");

很抱歉,您沒有提供需要重寫的原話,無法進行重寫

     } catch (

     Exception e) {e.printStackTrace();

     }

#return result;

##}

##在實際的作業過程中,在進行鎖定新增時,必須為鎖定加上

過期時間,否則出現某些不可知的異常時,可能會導致鎖定無法釋放,擷取器一直無法取得到擷取任務的情況。

以上是基於Redis分散式鎖的任務調度怎麼實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除