Aracılığıyla paylaş


Lider Seçimi düzeni

Azure Blob Depolama

Dağıtılmış bir uygulamadaki işbirliği örnekleri koleksiyonu tarafından gerçekleştirilen eylemleri koordine etmek için, bir örneği diğerlerini yönetme sorumluluğunu üstlenen lider olarak seçin. Bu, örneklerin birbiriyle çakışmamasını, paylaşılan kaynaklar için çekişmeye neden olmasını veya diğer örneklerin gerçekleştirdiği çalışmayı yanlışlıkla engellemesini sağlamaya yardımcı olabilir.

Bağlam ve sorun

Tipik bir bulut uygulamasının eşgüdümlü bir şekilde hareket eden birçok görevi vardır. Bu görevlerin tümü aynı kodu çalıştıran ve aynı kaynaklara erişim gerektiren örnekler olabilir veya karmaşık bir hesaplamanın tek tek bölümlerini gerçekleştirmek için paralel olarak birlikte çalışıyor olabilirler.

Görev örnekleri çoğu zaman ayrı çalışabilir, ancak çakışmadığından, paylaşılan kaynaklar için çekişmeye neden olmadığından veya diğer görev örneklerinin gerçekleştirdiği çalışmayı yanlışlıkla müdahale etmediğinden emin olmak için her örneğin eylemlerini koordine etmek de gerekebilir.

Örneğin:

  • Yatay ölçeklendirme uygulayan bulut tabanlı bir sistemde, her örnek farklı bir kullanıcıya hizmet ederken aynı görevin birden çok örneği aynı anda çalışıyor olabilir. Bu örnekler paylaşılan bir kaynağa yazıyorsa, her örneğin başkaları tarafından yapılan değişikliklerin üzerine yazılmasını önlemek için eylemlerini koordine etmek gerekir.
  • Görevler karmaşık bir hesaplamanın tek tek öğelerini paralel olarak gerçekleştiriyorsa, hepsi tamamlandığında sonuçların toplanması gerekir.

Görev örneklerinin tümü eştir, dolayısıyla koordinatör veya toplayıcı olarak görev yapabilecek doğal bir öncü yoktur.

Çözüm

Öncü olarak davranacak tek bir görev örneği seçilmelidir ve bu örnek diğer alt görev örneklerinin eylemlerini koordine etmelidir. Tüm görev örnekleri aynı kodu çalıştırıyorsa, her biri öncü olarak hareket edebilmektedir. Bu nedenle, iki veya daha fazla örneğin aynı anda lider konumunu devralmasını önlemek için seçim süreci dikkatli bir şekilde yönetilmelidir.

Sistem, öncü seçmek için sağlam bir mekanizma sağlamalıdır. Bu yöntemin ağ kesintileri veya işlem hataları gibi olaylarla başa çıkması gerekir. Birçok çözümde, alt görev örnekleri bir tür sinyal yöntemi aracılığıyla veya yoklama yoluyla öncüsü izler. Belirlenen öncü beklenmedik bir şekilde sonlandırılırsa veya bir ağ hatası öncüsü alt görev örnekleri için kullanılamaz hale getirirse, yeni bir öncü seçmeleri gerekir.

Dağıtılmış bir ortamdaki bir dizi görev arasında öncü seçmek için aşağıdakiler dahil olmak üzere birden çok strateji vardır:

  • Paylaşılan, dağıtılmış bir mutex elde etmek için yarışıyor. Mutex'i alan ilk görev örneği öncüdür. Ancak sistem, öncü sonlandırılırsa veya sistemin geri kalanıyla bağlantısı kesilirse başka bir görev örneğinin öncü olmasına izin vermek için mutex'in serbest bırakıldığından emin olmalıdır. Bu strateji aşağıda verilen örnekte gösterilmiştir.
  • Zorba Algoritması, Raft Konsensüs Algoritması veya Halka Algoritması gibi ortak lider seçim algoritmalarından birini uygulama. Bu algoritmalar, seçimdeki her adayın benzersiz bir kimliği olduğunu ve diğer adaylarla güvenilir bir şekilde iletişim kurabileceğini varsayar.

Sorunlar ve dikkat edilmesi gerekenler

Bu düzeni nasıl uygulayacaklarına karar verirken aşağıdaki noktaları göz önünde bulundurun:

  • Öncü seçme süreci, geçici ve kalıcı hatalara dayanıklı olmalıdır.
  • Öncü başarısız olduğunda veya başka bir şekilde kullanılamaz duruma geldiğinde (örneğin, bir iletişim hatası nedeniyle) algılamak mümkün olmalıdır. Algılamanın ne kadar hızlı gerektiği sisteme bağlıdır. Bazı sistemler, geçici bir hatanın düzeltilebileceği bir öncü olmadan kısa bir süre çalışabilir. Diğer durumlarda, lider başarısızlığını hemen tespit etmek ve yeni bir seçim tetiklemek gerekebilir.
  • Yatay otomatik ölçeklendirme uygulayan bir sistemde, sistem yeniden ölçeklendirilir ve bazı bilgi işlem kaynaklarını kapatırsa öncü sonlandırılabilir.
  • Paylaşılan, dağıtılmış bir mutex kullanmak, mutex'i sağlayan dış hizmete bağımlılık sağlar. Hizmet tek bir hata noktası oluşturur. Herhangi bir nedenle kullanılamaz duruma gelirse sistem bir lider seçemez.
  • Öncü olarak tek bir ayrılmış işlem kullanmak basit bir yaklaşımdır. Ancak, işlem başarısız olursa yeniden başlatılırken önemli bir gecikme olabilir. Elde edilen gecikme süresi, öncü tarafından bir işlemi koordine etmek için bekleyen diğer işlemlerin performans ve yanıt sürelerini etkileyebilir.
  • Öncü seçim algoritmalarından birinin el ile uygulanması, kodu ayarlamak ve iyileştirmek için en büyük esnekliği sağlar.
  • Lideri sistemde bir performans sorunu haline getirmekten kaçının. Liderin amacı, alt görevlerin çalışmasını koordine etmektir ve bu işin kendisine katılması gerekmez; ancak görev lider olarak seçilmediyse bunu yapabilmesi gerekir.

Bu desen ne zaman kullanılır?

Bulutta barındırılan bir çözüm gibi dağıtılmış bir uygulamadaki görevler dikkatli bir koordinasyona ihtiyaç duyduğunda ve doğal bir öncü olmadığında bu düzeni kullanın.

Bu desen aşağıdakiler için yararlı olmayabilir:

  • Her zaman öncü olarak davranabilen doğal bir öncü veya özel bir süreç vardır. Örneğin, görev örneklerini koordine eden tekil bir işlem uygulamak mümkün olabilir. Bu işlem başarısız olursa veya iyi durumda değilse, sistem kapatabilir ve yeniden başlatabilir.
  • Görevler arasındaki koordinasyon daha basit bir yöntem kullanılarak sağlanabilir. Örneğin, birkaç görev örneğinin paylaşılan bir kaynağa eşgüdümlü erişime ihtiyacı varsa, erişimi denetlemek için iyimser veya kötümser kilitleme kullanmak daha iyi bir çözümdür.
  • Apache Zookeeper gibi bir üçüncü taraf çözümü daha verimli bir çözüm olabilir.

İş yükü tasarımı

Bir mimar, Azure Well-Architected Framework yapılarında ele alınan hedefleri ve ilkeleri ele almak için lider seçimi düzeninin iş yükünün tasarımında nasıl kullanılabileceğini değerlendirmelidir. Örneğin:

Sütun Bu desen sütun hedeflerini nasıl destekler?
Güvenilirlik tasarımı kararları, iş yükünüzün arızaya karşı dayanıklı olmasına ve bir hata oluştuktan sonra tamamen çalışır duruma gelmesini sağlamaya yardımcı olur. Bu desen, işi güvenilir bir şekilde yeniden yönlendirerek düğüm arızalarının etkisini azaltır. Ayrıca lider arızalandığında konsensüs algoritmaları aracılığıyla yük devretme uygular.

- RE:05 Yedeklilik
- RE:07 Kendi kendini iyileştirme

Herhangi bir tasarım kararında olduğu gibi, bu desenle ortaya konulabilecek diğer sütunların hedeflerine karşı herhangi bir dengeyi göz önünde bulundurun.

Örnek

GitHub'da Öncü Seçimi örneği, paylaşılan, dağıtılmış bir mutex uygulamak için bir mekanizma sağlamak üzere Azure Depolama blobu üzerinde kiralamanın nasıl kullanılacağını gösterir. Bu mutex, kullanılabilir çalışan örnekleri grubu arasında bir öncü seçmek için kullanılabilir. Kirayı almak için ilk örnek öncü seçilir ve kirayı serbest bırakana veya kirayı yenileyemediği sürece öncü olarak kalır. Öncü artık kullanılabilir olmaması durumunda diğer çalışan örnekleri blob kiralamasını izlemeye devam edebilir.

Blob kiralama, blob üzerinde özel yazma kilididir. Tek bir blob, herhangi bir zamanda yalnızca bir kiranın konusu olabilir. Bir çalışan örneği belirtilen blob üzerinde kiralama isteyebilir ve aynı blob üzerinde başka bir çalışan örneğinin kiralaması yoksa kira verilir. Aksi takdirde istek bir özel durum oluşturur.

Hatalı bir öncü örneğin kirayı süresiz olarak tutmasını önlemek için kiralama için bir ömür belirtin. Bu süre dolduğunda kira kullanılabilir duruma gelir. Ancak, bir örnek kirayı barındırsa da, kiranın yenilenmesini isteyebilir ve daha fazla süre için kira verilir. Öncü örnek, kiralamayı korumak istiyorsa bu işlemi sürekli olarak yineleyebilir. Blob kiralama hakkında daha fazla bilgi için bkz. Kira Blobu (REST API).

BlobDistributedMutex Aşağıdaki C# örneğindeki sınıfı, bir çalışan örneğinin belirtilen blob üzerinden kira almayı denemesini sağlayan yöntemi içerirRunTaskWhenMutexAcquired. Blobun ayrıntıları (ad, kapsayıcı ve depolama hesabı), nesne oluşturulduğunda bir BlobSettings nesnedeki BlobDistributedMutex oluşturucuya geçirilir (bu nesne, örnek koda dahil edilen basit bir yapıdır). Oluşturucu ayrıca blob üzerinden kirayı başarıyla alır ve öncü seçilirse çalışan örneğinin çalıştırması gereken koda başvuran bir Task kabul eder. Kiralamayı edinmenin alt düzey ayrıntılarını işleyen kodun adlı BlobLeaseManagerayrı bir yardımcı sınıfında uygulandığını unutmayın.

public class BlobDistributedMutex
{
  ...
  private readonly BlobSettings blobSettings;
  private readonly Func<CancellationToken, Task> taskToRunWhenLeaseAcquired;
  ...

  public BlobDistributedMutex(BlobSettings blobSettings,
           Func<CancellationToken, Task> taskToRunWhenLeaseAcquired, ... )
  {
    this.blobSettings = blobSettings;
    this.taskToRunWhenLeaseAcquired = taskToRunWhenLeaseAcquired;
    ...
  }

  public async Task RunTaskWhenMutexAcquired(CancellationToken token)
  {
    var leaseManager = new BlobLeaseManager(blobSettings);
    await this.RunTaskWhenBlobLeaseAcquired(leaseManager, token);
  }
  ...

RunTaskWhenMutexAcquired Yukarıdaki kod örneğindeki yöntemi, kirayı RunTaskWhenBlobLeaseAcquired almak için aşağıdaki kod örneğinde gösterilen yöntemi çağırır. RunTaskWhenBlobLeaseAcquired yöntemi zaman uyumsuz olarak çalışır. Kira başarıyla alınırsa, çalışan örneği öncü seçilmiştir. Temsilcinin taskToRunWhenLeaseAcquired amacı, diğer çalışan örneklerini koordine eden çalışmayı gerçekleştirmektir. Kira alınmazsa, öncü olarak başka bir çalışan örneği seçilmiştir ve geçerli çalışan örneği bir alt örnek olarak kalır. yönteminin TryAcquireLeaseOrWait kirayı almak için nesnesini kullanan BlobLeaseManager bir yardımcı yöntem olduğunu unutmayın.

  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.TryAcquireLeaseOrWait(leaseManager, token);

      if (!string.IsNullOrEmpty(leaseId))
      {
        // Create a new linked cancellation token source so that if either the
        // original token is canceled or the lease can't be renewed, the
        // leader task can be canceled.
        using (var leaseCts =
          CancellationTokenSource.CreateLinkedTokenSource(new[] { token }))
        {
          // Run the leader task.
          var leaderTask = this.taskToRunWhenLeaseAcquired.Invoke(leaseCts.Token);
          ...
        }
      }
    }
    ...
  }

Öncü tarafından başlatılan görev de zaman uyumsuz olarak çalışır. Bu görev çalışırken, RunTaskWhenBlobLeaseAcquired aşağıdaki kod örneğinde gösterilen yöntem düzenli aralıklarla kiralamayı yenilemeyi dener. Bu, çalışan örneğinin öncü olmaya devam etmesini sağlamaya yardımcı olur. Örnek çözümde, başka bir çalışan örneğinin öncü seçilmesini önlemek için yenileme istekleri arasındaki gecikme, kiralama süresi boyunca belirtilen süreden daha kısadır. Yenileme herhangi bir nedenle başarısız olursa öncüye özgü görev iptal edilir.

Kira yenilenemezse veya görev iptal edilirse (çalışan örneğinin kapatılmasının bir sonucu olarak), kira serbest bırakılır. Bu noktada, öncü olarak bu veya başka bir çalışan örneği seçilebilir. Aşağıdaki kod ayıklama işlemi bu bölümünü gösterir.

  private async Task RunTaskWhenBlobLeaseAcquired(
    BlobLeaseManager leaseManager, CancellationToken token)
  {
    while (...)
    {
      ...
      if (...)
      {
        ...
        using (var leaseCts = ...)
        {
          ...
          // Keep renewing the lease in regular intervals.
          // If the lease can't 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
          // couldn't renew the lease) then cancel the other task.
          await CancelAllWhenAnyCompletes(leaderTask, renewLeaseTask, leaseCts);
        }
      }
    }
  }
  ...
}

KeepRenewingLease yöntemi, kirayı BlobLeaseManager yenilemek için nesnesini kullanan başka bir yardımcı yöntemdir. yöntemi, CancelAllWhenAnyCompletes ilk iki parametre olarak belirtilen görevleri iptal eder. Aşağıdaki diyagramda, bir öncü seçmek ve işlemleri koordine eden bir görev çalıştırmak için sınıfının kullanılması BlobDistributedMutex gösterilmektedir.

Şekil 1'de BlobDistributedMutex sınıfının işlevleri gösterilmektedir

Aşağıdaki kod örneği, bir çalışan örneği içinde sınıfının nasıl kullanılacağını BlobDistributedMutex gösterir. Bu kod, kiranın Azure Blob Depolama kapsayıcısında adlı MyLeaderCoordinatorTask bir blob üzerinden kira alır ve çalışan örneği öncü seçilirse yönteminde MyLeaderCoordinatorTask tanımlanan kodun çalıştırılması gerektiğini belirtir.

// Create a BlobSettings object with the connection string or managed identity and the name of the blob to use for the lease
BlobSettings blobSettings = new BlobSettings(storageConnStr, "leases", "MyLeaderCoordinatorTask");

// Create a new BlobDistributedMutex object with the BlobSettings object and a task to run when the lease is acquired
var distributedMutex = new BlobDistributedMutex(
    blobSettings, MyLeaderCoordinatorTask);

// Wait for completion of the DistributedMutex and the UI task before exiting
await distributedMutex.RunTaskWhenMutexAcquired(cancellationToken);

...

// Method that runs if the worker instance is elected the leader
private static async Task MyLeaderCoordinatorTask(CancellationToken token)
{
  ...
}

Örnek çözümle ilgili aşağıdaki noktaları not edin:

  • Blob olası bir hata noktasıdır. Blob hizmeti kullanılamaz duruma gelirse veya erişilemezse, öncü kirayı yenileyemez ve başka bir çalışan örneği kiralamayı alamaz. Bu durumda, hiçbir çalışan örneği öncü olarak davranamaz. Ancak blob hizmeti dayanıklı olacak şekilde tasarlanmıştır, bu nedenle blob hizmetinin tam hatasının son derece düşük bir olasılık olduğu kabul edilir.
  • Öncü tarafından gerçekleştirilen görev durursa, öncü kirayı yenilemeye devam edebilir ve diğer çalışan örneklerinin kirayı almasını engelleyebilir ve görevleri koordine etmek için öncü konumu devralabilir. Gerçek dünyada, liderin durumu sık aralıklarla kontrol edilmelidir.
  • Seçim süreci belirleyici değil. Blob kirasını hangi çalışan örneğinin edineceği ve öncü olacağı konusunda hiçbir varsayımda bulunamazsınız.
  • Blob kirasının hedefi olarak kullanılan blob başka bir amaçla kullanılmamalıdır. Bir çalışan örneği bu blobda veri depolamayı denerse, çalışan örneği öncü olmadığı ve blob kirasını tutmadığı sürece bu verilere erişilemez.

Sonraki Adımlar

Bu desen uygulanırken aşağıdaki yönergeler de uygun olabilir: