通過協(xié)調合作,在分布式應用程序的任務實例集合執(zhí)行的操作,選舉一個實例作為承擔管理的其他實例責任的領導者。這個模式可以有助于確保任務實例不互相沖突,導致爭用共享資源,或與其他的任務實例正在執(zhí)行的工作無意中干擾。
一個典型的云應用包括行動協(xié)調的方式很多任務。這些任務都可以是實例運行相同的代碼和需要訪問相同的資源,或者它們可能是可并行工作,以執(zhí)行復雜計算的各個部分。
任務實例可能為多的時間自主運行,但它也可能是必要的,以協(xié)調各實例的操作,以確保它們不發(fā)生沖突,導致爭用共享資源,或無意中妨礙工作,其他的任務實例正在執(zhí)行。例如:
由于任務實例都是同行,沒有天生的領導者,能夠充當協(xié)調員或聚合器。
單個任務實例應選充當領導者,這種情況下應協(xié)調其他從屬任務實例的操作。如果所有的任務實例都運行相同的代碼,他們可能都能夠充當領導者。因此,選舉過程必須謹慎管理,以防止兩個或多個實例接管領導者的角色在同一時間。
該系統(tǒng)必須選擇的領導者提供了一個堅固的機構。這種機制必須能夠應付諸如網絡中斷或進程故障事件。在許多解決方案中,下屬的工作情況監(jiān)控的領導者,通過某種類型的心跳機制,或通過輪詢。如果指定的領導者意外終止或網絡故障使得領導者不通下屬的工作情況,有必要為他們選出了新的領導人。
有可用于選舉的領導者之間的一組任務在分布式環(huán)境中,包括幾個策略:
在決定如何實現(xiàn)這個模式時,請考慮以下幾點:
使用此模式時,在分布式應用程序的任務,比如云托管解決方案,需要認真協(xié)調,也沒有天生的領導者。
注意:避免使領導者在系統(tǒng)中的瓶頸。領導者的目的是協(xié)調的附屬任務完成的工作,它不一定有機會參加這項工作本身,盡管它應該是有能力這樣做,如果任務沒有當選領導人。
這種模式可能不適合:
在列入可用于本指南中的示例代碼中 LeaderElection 解決方案 DistributedMutex 項目展示了如何使用租賃在 Azure 存儲 BLOB 提供了一種機制,實現(xiàn)共享的分布式互斥。此互斥鎖可以用來選擇在 Azure 云服務的領導者之間的一組角色的實例。第一個角色實例獲得租約當選的領導人,并保持領先直至其租賃或直到它無法續(xù)租。其他角色實例可以繼續(xù)監(jiān)視在領導不再可用的情況下將 BLOB 租賃。
一個 BLOB 租賃是在一個 blob 的排他寫鎖。單個 BLOB 可以是一整租的在任何一個時間點的問題。角色實例可以請求租約在指定的斑點,而且將被授予租約,如果沒有其他租賃在同一個斑點,是由這個或任何其他作用,比如舉行,否則將拋出一個異常。
為了減少一個故障角色實例保留無限期租用的可能性,指定了一輩子的租約。當此期滿后,租賃變?yōu)榭捎?。然而,當一個角色實例持有的租賃也可以請求租約到期,并且將被授予租約的時間再延長。角色實例可以不斷重復這一過程,如果它希望保留租約。
有關如何租用一個 blob 的詳細信息,請參閱租賃斑點(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 上述方法調用以下代碼示例來實際獲得的租賃所示的 RunTaskWhenBlobLeaseAcquired 方法。該 RunTaskWhenBlobLeaseAcquired 方法異步運行。如果租賃的成功獲取,角色實例已經當選的領導者。該 taskToRunWhenLeaseAcquired 委托的目的是為了執(zhí)行協(xié)調其它角色實例的工作。如果未取得租賃,另一個角色實例已當選為領導人和當前角色實例仍然是一個下屬。注意,TryAcquireLeaseOrWait 方法是使用 BlobLeaseManager 對象獲取租賃一個輔助方法。
...
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);
...
}
}
}
}
...
由領導開始的任務還異步執(zhí)行。雖然這個任務正在運行,下面的代碼示例所示的 RunTaskWhenBlobLeaseAquired方法周期性地嘗試續(xù)訂租約。這個動作有助于確保該角色實例保持領先。在簡單解決方案中,續(xù)訂請求之間的延遲小于對租賃期限,以防止另一角色實例當選的領導人指定的時間。如果更新失敗,以任何理由,任務被取消。如果租用未能被更新或任務被取消(可能為角色實例關停的結果),租賃被釋放。在這一點上,這個或另一個角色實例可能被選為領導者。下面的代碼提取物顯示出此過程的一部分。
...
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ù)租另一個 helper 方法。該 CancelAllWhenAnyCompletes 方法取消指定為前兩個參數的任務。
圖 1 示出了 BlobDistributedMutex 類的功能。
圖1 - 使用 BlobDistributedMutex 類選出一個領導者和運行協(xié)調操作的任務
下面的代碼示例顯示了如何使用 BlobDistributedMutex 類的輔助角色。此代碼獲取租賃了一個名為 MyLeaderCoordinatorTask 在開發(fā)的倉儲租賃容器中的 blob,并指定在 MyLeaderCoordinatorTask 方法定義的代碼應該運行,如果角色實例當選的領導人。
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)
{
...
}
請注意有關樣品溶液中的以下幾點:
更多建議: