(十三)——領(lǐng)導(dǎo)人選舉模式

2018-02-24 15:44 更新

云計(jì)算設(shè)計(jì)模式(十三)——領(lǐng)導(dǎo)人選舉模式

通過協(xié)調(diào)合作,在分布式應(yīng)用程序的任務(wù)實(shí)例集合執(zhí)行的操作,選舉一個(gè)實(shí)例作為承擔(dān)管理的其他實(shí)例責(zé)任的領(lǐng)導(dǎo)者。這個(gè)模式可以有助于確保任務(wù)實(shí)例不互相沖突,導(dǎo)致爭用共享資源,或與其他的任務(wù)實(shí)例正在執(zhí)行的工作無意中干擾。

背景和問題

一個(gè)典型的云應(yīng)用包括行動(dòng)協(xié)調(diào)的方式很多任務(wù)。這些任務(wù)都可以是實(shí)例運(yùn)行相同的代碼和需要訪問相同的資源,或者它們可能是可并行工作,以執(zhí)行復(fù)雜計(jì)算的各個(gè)部分。

任務(wù)實(shí)例可能為多的時(shí)間自主運(yùn)行,但它也可能是必要的,以協(xié)調(diào)各實(shí)例的操作,以確保它們不發(fā)生沖突,導(dǎo)致爭用共享資源,或無意中妨礙工作,其他的任務(wù)實(shí)例正在執(zhí)行。例如:

  • 在基于云的系統(tǒng),該系統(tǒng)實(shí)現(xiàn)了橫向擴(kuò)展,同一個(gè)任務(wù)的多個(gè)實(shí)例可以與每個(gè)實(shí)例服務(wù)于不同的用戶同時(shí)運(yùn)行。如果這些實(shí)例寫入到共享資源,也可能是必要的,以協(xié)調(diào)它們的操作,以防止每個(gè)實(shí)例從盲目地覆蓋由他人進(jìn)行的更改。
  • 如果任務(wù)正在執(zhí)行復(fù)雜的計(jì)算以并行的單個(gè)元素,其結(jié)果將需要被聚合時(shí),他們都完成了。

由于任務(wù)實(shí)例都是同行,沒有天生的領(lǐng)導(dǎo)者,能夠充當(dāng)協(xié)調(diào)員或聚合器。

解決方案

單個(gè)任務(wù)實(shí)例應(yīng)選充當(dāng)領(lǐng)導(dǎo)者,這種情況下應(yīng)協(xié)調(diào)其他從屬任務(wù)實(shí)例的操作。如果所有的任務(wù)實(shí)例都運(yùn)行相同的代碼,他們可能都能夠充當(dāng)領(lǐng)導(dǎo)者。因此,選舉過程必須謹(jǐn)慎管理,以防止兩個(gè)或多個(gè)實(shí)例接管領(lǐng)導(dǎo)者的角色在同一時(shí)間。

該系統(tǒng)必須選擇的領(lǐng)導(dǎo)者提供了一個(gè)堅(jiān)固的機(jī)構(gòu)。這種機(jī)制必須能夠應(yīng)付諸如網(wǎng)絡(luò)中斷或進(jìn)程故障事件。在許多解決方案中,下屬的工作情況監(jiān)控的領(lǐng)導(dǎo)者,通過某種類型的心跳機(jī)制,或通過輪詢。如果指定的領(lǐng)導(dǎo)者意外終止或網(wǎng)絡(luò)故障使得領(lǐng)導(dǎo)者不通下屬的工作情況,有必要為他們選出了新的領(lǐng)導(dǎo)人。

有可用于選舉的領(lǐng)導(dǎo)者之間的一組任務(wù)在分布式環(huán)境中,包括幾個(gè)策略:

  • 與排名最低的實(shí)例或進(jìn)程ID選擇任務(wù)實(shí)例。
  • 競速獲得一個(gè)共享的分布式互斥。第一個(gè)任務(wù)實(shí)例獲取該互斥鎖處于領(lǐng)先地位。然而,系統(tǒng)必須保證,如果領(lǐng)導(dǎo)者終止或變得與系統(tǒng)的其余部分?jǐn)嚅_,該互斥被釋放,以允許另一個(gè)任務(wù)實(shí)例成為領(lǐng)導(dǎo)者。
  • 實(shí)施的共同領(lǐng)導(dǎo)人選舉算法,如惡霸算法或環(huán)算法之一。這些算法是相對簡單的,但也有一些更復(fù)雜的技術(shù)提供。這些算法假定每個(gè)候選參選具有唯一的 ID,并且,它們可以用可靠的方式在其他候選人進(jìn)行通信。

問題和注意事項(xiàng)

在決定如何實(shí)現(xiàn)這個(gè)模式時(shí),請考慮以下幾點(diǎn):

  • 選出一個(gè)領(lǐng)導(dǎo)者的過程應(yīng)該是彈性的瞬時(shí)和永久失效。
  • 必須能夠檢測到當(dāng)領(lǐng)導(dǎo)失敗,或變成不可用(可能是由于通訊故障)。在這是需要這種檢測的速度將取決于系統(tǒng)。有些系統(tǒng)可能能夠發(fā)揮作用了一會(huì)兒沒有一個(gè)領(lǐng)導(dǎo)者,在此期間造成的領(lǐng)導(dǎo)人變得不可用瞬時(shí)故障可能已被排除。在其他情況下,可能有必要立即檢測領(lǐng)袖失敗并引發(fā)新的選舉。
  • 在實(shí)現(xiàn)自動(dòng)縮放水平的系統(tǒng)中,如果系統(tǒng)鱗背面和關(guān)閉一些計(jì)算資源的領(lǐng)導(dǎo)者可能被終止。
  • 使用一個(gè)共享的分布式互斥引入外部服務(wù),提供了互斥鎖的可用性依賴。該服務(wù)可以構(gòu)成一個(gè)單點(diǎn)故障。如果此服務(wù)應(yīng)該以任何理由變得不可用時(shí),系統(tǒng)將無法選出一個(gè)領(lǐng)導(dǎo)者。
  • 使用一個(gè)專用進(jìn)程的領(lǐng)導(dǎo)者是一個(gè)比較簡單的方法。然而,如果該過程失敗,可能有顯著延遲而被重新啟動(dòng),并且將得到的延遲可能影響其他進(jìn)程的性能和響應(yīng)時(shí)間,如果他們正在等待領(lǐng)導(dǎo)人來協(xié)調(diào)的動(dòng)作。
  • 實(shí)施的領(lǐng)導(dǎo)人選舉算法之一手動(dòng)為調(diào)整和優(yōu)化代碼的最大靈活性。

何時(shí)使用這個(gè)模式

使用此模式時(shí),在分布式應(yīng)用程序的任務(wù),比如云托管解決方案,需要認(rèn)真協(xié)調(diào),也沒有天生的領(lǐng)導(dǎo)者。

注意:避免使領(lǐng)導(dǎo)者在系統(tǒng)中的瓶頸。領(lǐng)導(dǎo)者的目的是協(xié)調(diào)的附屬任務(wù)完成的工作,它不一定有機(jī)會(huì)參加這項(xiàng)工作本身,盡管它應(yīng)該是有能力這樣做,如果任務(wù)沒有當(dāng)選領(lǐng)導(dǎo)人。

這種模式可能不適合:

  • 如果有一個(gè)天生的領(lǐng)導(dǎo)者或?qū)S玫倪^程,可以隨時(shí)充當(dāng)領(lǐng)導(dǎo)者。例如,有可能實(shí)現(xiàn)一個(gè)單進(jìn)程,其協(xié)調(diào)該任務(wù)的實(shí)例。如果這個(gè)過程失敗或變得不健康,系統(tǒng)可以將其關(guān)閉并重新啟動(dòng)它。
  • 如果任務(wù)之間的協(xié)調(diào),可以很容易地通過使用更輕便的機(jī)構(gòu)來實(shí)現(xiàn)的。例如,如果幾個(gè)任務(wù)實(shí)例僅僅需要對共享資源的訪問協(xié)調(diào),一個(gè)最好的解決辦法可能是使用樂觀或悲觀鎖來控制訪問該資源。
  • 如果一個(gè)第三方的解決方案是比較合適的。例如,微軟的 Azure HDInsight 服務(wù)(基于 Apache Hadoop 的)使用所提供的 ApacheZookeeper 協(xié)調(diào)的 map / reduce 的匯總?cè)蝿?wù)和匯總數(shù)據(jù)的服務(wù)。它也可以安裝并在Azure的虛擬機(jī)配置動(dòng)物園管理員,并將其集成到自己的解決方案,或使用可從微軟開放技術(shù)的動(dòng)物園管理員預(yù)置的虛擬機(jī)映像。欲了解更多信息,請參閱 Apache 的動(dòng)物園管理員在微軟的 Azure 在微軟開放技術(shù)的網(wǎng)站。

例子

在列入可用于本指南中的示例代碼中 LeaderElection 解決方案 DistributedMutex 項(xiàng)目展示了如何使用租賃在 Azure 存儲(chǔ) BLOB 提供了一種機(jī)制,實(shí)現(xiàn)共享的分布式互斥。此互斥鎖可以用來選擇在 Azure 云服務(wù)的領(lǐng)導(dǎo)者之間的一組角色的實(shí)例。第一個(gè)角色實(shí)例獲得租約當(dāng)選的領(lǐng)導(dǎo)人,并保持領(lǐng)先直至其租賃或直到它無法續(xù)租。其他角色實(shí)例可以繼續(xù)監(jiān)視在領(lǐng)導(dǎo)不再可用的情況下將 BLOB 租賃。

注意

一個(gè) BLOB 租賃是在一個(gè) blob 的排他寫鎖。單個(gè) BLOB 可以是一整租的在任何一個(gè)時(shí)間點(diǎn)的問題。角色實(shí)例可以請求租約在指定的斑點(diǎn),而且將被授予租約,如果沒有其他租賃在同一個(gè)斑點(diǎn),是由這個(gè)或任何其他作用,比如舉行,否則將拋出一個(gè)異常。

為了減少一個(gè)故障角色實(shí)例保留無限期租用的可能性,指定了一輩子的租約。當(dāng)此期滿后,租賃變?yōu)榭捎谩H欢?,?dāng)一個(gè)角色實(shí)例持有的租賃也可以請求租約到期,并且將被授予租約的時(shí)間再延長。角色實(shí)例可以不斷重復(fù)這一過程,如果它希望保留租約。

有關(guān)如何租用一個(gè) blob 的詳細(xì)信息,請參閱租賃斑點(diǎn)(REST API)在 MSDN 上。

public class BlobDistributedMutex  
{  
  ...  
  private readonly BlobSettings blobSettings;  
  private readonly Func<CancellationToken, Task> taskToRunWhenLeaseAcquired;  
  ...  
?
  public BlobDistributedMutex(BlobSettings blobSettings,   
           Func<CancellationToken, Task> taskToRunWhenLeaseAquired)  
  {  
    this.blobSettings = blobSettings;  
    this.taskToRunWhenLeaseAquired = taskToRunWhenLeaseAquired;  
  }  
?
  public async Task RunTaskWhenMutexAcquired(CancellationToken token)  
  {  
    var leaseManager = new BlobLeaseManager(blobSettings);  
    await this.RunTaskWhenBlobLeaseAcquired(leaseManager, token);      
  }   
  ...

代碼示例中的 RunTaskWhenMutexAquired 上述方法調(diào)用以下代碼示例來實(shí)際獲得的租賃所示的 RunTaskWhenBlobLeaseAcquired 方法。該 RunTaskWhenBlobLeaseAcquired 方法異步運(yùn)行。如果租賃的成功獲取,角色實(shí)例已經(jīng)當(dāng)選的領(lǐng)導(dǎo)者。該 taskToRunWhenLeaseAcquired 委托的目的是為了執(zhí)行協(xié)調(diào)其它角色實(shí)例的工作。如果未取得租賃,另一個(gè)角色實(shí)例已當(dāng)選為領(lǐng)導(dǎo)人和當(dāng)前角色實(shí)例仍然是一個(gè)下屬。注意,TryAcquireLeaseOrWait 方法是使用 BlobLeaseManager 對象獲取租賃一個(gè)輔助方法。

...  
 private async Task RunTaskWhenBlobLeaseAcquired(  
   BlobLeaseManager leaseManager, CancellationToken token)  
 {  
   while (!token.IsCancellationRequested)  
   {  
     // Try to acquire the blob lease.   
     // Otherwise wait for a short time before trying again.  
     string leaseId = await this.TryAquireLeaseOrWait(leaseManager, token);  
?
     if (!string.IsNullOrEmpty(leaseId))  
     {  
       // Create a new linked cancellation token source so that if either the   
       // original token is cancelled or the lease cannot be renewed, the  
       // leader task can be cancelled.  
       using (var leaseCts =   
         CancellationTokenSource.CreateLinkedTokenSource(new[] { token }))  
       {  
         // Run the leader task.  
         var leaderTask = this.taskToRunWhenLeaseAquired.Invoke(leaseCts.Token);            
         ...  
       }  
     }  
   }  
 }  
 ...

由領(lǐng)導(dǎo)開始的任務(wù)還異步執(zhí)行。雖然這個(gè)任務(wù)正在運(yùn)行,下面的代碼示例所示的 RunTaskWhenBlobLeaseAquired方法周期性地嘗試?yán)m(xù)訂租約。這個(gè)動(dòng)作有助于確保該角色實(shí)例保持領(lǐng)先。在簡單解決方案中,續(xù)訂請求之間的延遲小于對租賃期限,以防止另一角色實(shí)例當(dāng)選的領(lǐng)導(dǎo)人指定的時(shí)間。如果更新失敗,以任何理由,任務(wù)被取消。如果租用未能被更新或任務(wù)被取消(可能為角色實(shí)例關(guān)停的結(jié)果),租賃被釋放。在這一點(diǎn)上,這個(gè)或另一個(gè)角色實(shí)例可能被選為領(lǐng)導(dǎo)者。下面的代碼提取物顯示出此過程的一部分。

...  
  private async Task RunTaskWhenBlobLeaseAcquired(  
    BlobLeaseManager leaseManager, CancellationToken token)  
  {  
    while (...)  
    {  
      ...  
      if (...)  
      {  
        ...  
        using (var leaseCts = ...)  
        {  
          ...  
          // Keep renewing the lease in regular intervals.   
          // If the lease cannot be renewed, then the task completes.  
          var renewLeaseTask =   
            this.KeepRenewingLease(leaseManager, leaseId, leaseCts.Token);  
?
          // When any task completes (either the leader task itself or when it could  
          // not renew the lease) then cancel the other task.  
          await CancelAllWhenAnyCompletes(leaderTask, renewLeaseTask, leaseCts);  
        }  
      }  
    }  
  }  
  ...  
}

該 KeepRenewingLease 方法是使用 BlobLeaseManager 對象續(xù)租另一個(gè) helper 方法。該 CancelAllWhenAnyCompletes 方法取消指定為前兩個(gè)參數(shù)的任務(wù)。

圖 1 示出了 BlobDistributedMutex 類的功能。

圖1 - 使用 BlobDistributedMutex 類選出一個(gè)領(lǐng)導(dǎo)者和運(yùn)行協(xié)調(diào)操作的任務(wù)

下面的代碼示例顯示了如何使用 BlobDistributedMutex 類的輔助角色。此代碼獲取租賃了一個(gè)名為 MyLeaderCoordinatorTask 在開發(fā)的倉儲(chǔ)租賃容器中的 blob,并指定在 MyLeaderCoordinatorTask 方法定義的代碼應(yīng)該運(yùn)行,如果角色實(shí)例當(dāng)選的領(lǐng)導(dǎo)人。

var settings = new BlobSettings(CloudStorageAccount.DevelopmentStorageAccount,   
  "leases", "MyLeaderCoordinatorTask");  
var cts = new CancellationTokenSource();  
var mutex = new BlobDistributedMutex(settings, MyLeaderCoordinatorTask);  
mutex.RunTaskWhenMutexAcquired(this.cts.Token);  
...  
?
// Method that runs if the role instance is elected the leader  
private static async Task MyLeaderCoordinatorTask(CancellationToken token)  
{  
  ...  
}

請注意有關(guān)樣品溶液中的以下幾點(diǎn):

  • BLOB 是一個(gè)潛在的單點(diǎn)故障。如果 Blob 服務(wù)不可用,或的 blob 是人跡罕至,領(lǐng)導(dǎo)者將無法續(xù)租,并沒有其他的作用,比如將能夠獲得租約。在這種情況下,沒有作用,例如將能夠充當(dāng)領(lǐng)導(dǎo)者。然而,blob 服務(wù)被設(shè)計(jì)為彈性的,所述 blob 的服務(wù),以便徹底失敗被認(rèn)為是極不可能的。
  • 如果被領(lǐng)導(dǎo)者攤位正在執(zhí)行的任務(wù),領(lǐng)導(dǎo)者可能會(huì)繼續(xù)續(xù)租,防止任何其他角色實(shí)例從獲得租約,并接管了領(lǐng)導(dǎo)作用,以協(xié)調(diào)任務(wù)。在現(xiàn)實(shí)世界中,領(lǐng)導(dǎo)者的健康應(yīng)該頻繁地進(jìn)行檢查。
  • 在選舉過程具有不確定性。你不能做任何假設(shè)哪個(gè)角色實(shí)例將得到的blob租約,成為領(lǐng)導(dǎo)者。
  • 不應(yīng)使用任何其他目的用作的 blob 租賃的目標(biāo)的 blob。如果一個(gè)角色實(shí)例嘗試將數(shù)據(jù)存儲(chǔ)在該的 blob,該數(shù)據(jù)將不能被訪問,除非該角色實(shí)例是領(lǐng)導(dǎo)者和持有的 blob租約。
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)