通過協(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í)行。例如:
由于任務(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í)現(xiàn)這個(gè)模式時(shí),請考慮以下幾點(diǎn):
使用此模式時(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)人。
這種模式可能不適合:
在列入可用于本指南中的示例代碼中 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):
更多建議: