Megosztás:


Vezetőválasztási minta

Azure Blob Storage

Koordinálja az elosztott alkalmazásokban együttműködő példányok gyűjteménye által végrehajtott műveleteket úgy, hogy egy példányt választ ki vezetőként, amely a többi felügyeletéért felelős. Ez segíthet annak biztosításában, hogy a példányok ne ütközzanak egymással, ne okozzanak versengést a megosztott erőforrásokért, vagy véletlenül zavarják a más példányok által végzett munkát.

Környezet és probléma

Egy tipikus felhőalkalmazásban számos feladat összehangoltan működik. Ezek a tevékenységek lehetnek olyan példányok, amelyek ugyanazt a kódot futtatják, és ugyanahhoz az erőforráshoz való hozzáférést igénylik, vagy párhuzamosan dolgoznak együtt egy összetett számítás egyes részeinek végrehajtásához.

Előfordulhat, hogy a feladatpéldányok általában külön futnak, de szükség lehet az egyes példányok műveleteinek koordinálására is, hogy ne ütközhessenek, ne okozzanak versengést a megosztott erőforrásokért, vagy véletlenül zavarják a más feladatpéldányok által végzett munkát.

Például:

  • A horizontális skálázást megvalósító felhőalapú rendszerekben ugyanazon feladat több példánya is futhat egyszerre, és mindegyik példány egy másik felhasználót szolgál ki. Ha ezek a példányok megosztott erőforrásba írnak, koordinálni kell a műveleteiket, hogy az egyes példányok ne tudják felülírni a mások által végrehajtott módosításokat.
  • Ha a feladatok egy összetett számítás egyes elemeit párhuzamosan hajtják végre, az eredményeket összesíteni kell, amikor mind befejeződnek.

A feladatpéldányok mind társpéldányok, ezért nincs olyan természetes vezető, aki koordinátorként vagy aggregátorként működhet.

Megoldás

Egyetlen feladatpéldányt kell kijelölni vezetőként, és ennek a példánynak koordinálnia kell a többi alárendelt feladatpéldány műveleteit. Ha az összes feladatpéldány ugyanazt a kódot futtatja, mindegyik képes vezetőként viselkedni. Ezért a választási folyamatot körültekintően kell kezelni annak érdekében, hogy megakadályozzuk, hogy két vagy több példány egyidejűleg átvegye a vezető pozíciót.

A rendszernek robusztus mechanizmust kell biztosítania a vezető kiválasztásához. Ennek a módszernek olyan eseményekkel kell megbirkóznia, mint a hálózatkimaradások vagy a folyamathibák. Számos megoldásban az alárendelt feladatpéldányok valamilyen szívverési módszerrel vagy lekérdezéssel figyelik a vezetőt. Ha a kijelölt vezető váratlanul leáll, vagy egy hálózati hiba miatt a vezető elérhetetlenné válik az alárendelt feladatpéldányok számára, új vezetőt kell választaniuk.

Több stratégia is létezik arra, hogy vezetőt választson ki egy elosztott környezetben lévő feladatok közül, beleértve a következőket:

  • Verseny egy megosztott, elosztott mutex megszerzésére. Az első feladatpéldány, amely megszerezi a mutexet, lesz a vezető. A rendszernek azonban biztosítania kell, hogy ha a vezető leáll, vagy le lesz választva a rendszer többi részétől, a mutex felszabadításra kerül, hogy lehetővé tegye egy másik feladat vezetővé válását. Ezt a stratégiát az alábbi példában mutatjuk be.
  • Az egyik gyakori vezető választási algoritmus implementálása, például a Bully Algoritmus, a Raft Consensus Algoritmus vagy a Chang és Roberts algoritmus. Ezek az algoritmusok feltételezik, hogy a választás minden jelöltje egyedi azonosítóval rendelkezik, és megbízhatóan tud kommunikálni a többi jelölttel.

Problémák és szempontok

A minta implementálásának eldöntésekor vegye figyelembe a következő szempontokat:

  • A vezető kiválasztásának folyamatának rugalmasnak kell lennie az átmeneti és állandó hibákra.
  • Lehetségesnek kell lennie annak észlelésére, hogy a vezető sikertelen volt vagy más módon elérhetetlenné vált (például kommunikációs hiba miatt). A rendszertől függ, hogy milyen gyors észlelésre van szükség. Előfordulhat, hogy egyes rendszerek rövid ideig vezető nélkül is képesek működni, ami alatt átmeneti hiba javítható. Más esetekben szükség lehet arra, hogy azonnal észlelje a vezetőhibát, és új választást indítson el.
  • A horizontális automatikus skálázást megvalósító rendszerben a vezető leállhat, ha a rendszer visszaskáláz és leállítja a számítási erőforrások egy részét.
  • Megosztott vagy elosztott mutex használata függőséget vezet be a mutexet biztosító külső szolgáltatásra. A szolgáltatás egyetlen meghibásodási pontot jelent. Ha bármilyen okból elérhetetlenné válik, a rendszer nem tud vezetőt választani.
  • Az egyetlen dedikált folyamat vezetőként való használata egyértelmű megközelítés. Ha azonban a folyamat meghiúsul, a folyamat újraindítása jelentős késéssel járhat. Az eredményül kapott késés hatással lehet más folyamatok teljesítményére és válaszidejára, ha arra várnak, hogy a vezető koordináljon egy műveletet.
  • Az egyik vezető választási algoritmus manuális implementálása biztosítja a legnagyobb rugalmasságot a kód finomhangolásához és optimalizálásához.
  • Kerülje, hogy a vezető szűk keresztmetszetté váljon a rendszerben. A vezető célja, hogy koordinálja az alárendelt feladatok munkáját, és nem feltétlenül kell részt vennie ebben a munkában – bár ezt meg kell tudnia tenni, ha a feladatot nem választják meg vezetőként.

Mikor érdemes használni ezt a mintát?

Ezt a mintát akkor használja, ha egy elosztott alkalmazás feladatainak, például egy felhőalapú megoldásnak gondos koordinációra van szüksége, és nincs természetes vezető.

Ez a minta nem feltétlenül hasznos, ha:

  • Van egy természetes vezető vagy dedikált folyamat, amely mindig vezetőként működhet. Előfordulhat például, hogy a feladatpéldányokat koordináló egytonos folyamat implementálható. Ha ez a folyamat meghiúsul vagy nem megfelelő állapotúvá válik, a rendszer leállíthatja és újraindíthatja azt.
  • A feladatok közötti koordináció egy egyszerűbb módszer használatával valósítható meg. Ha például több feladatpéldánynak egyszerűen összehangolt hozzáférésre van szüksége egy megosztott erőforráshoz, jobb megoldás, ha optimista vagy pesszimista zárolást használ a hozzáférés szabályozásához.
  • Egy külső megoldás, például az Apache Zookeeper hatékonyabb megoldás lehet.

Munkaterhelés tervezése

Az építészeknek értékelniük kell, hogyan használható a vezetőválasztási minta a számítási feladat kialakításában az Azure Well-Architected-keretrendszer pilléreiben foglalt célok és alapelvek kezelésére. Például:

Pillér Hogyan támogatja ez a minta a pillércélokat?
A megbízhatósági tervezési döntések segítenek a számítási feladatnak ellenállóvá válni a hibás működéssel szemben, és biztosítani, hogy a hiba bekövetkezése után teljesen működőképes állapotba kerüljön. Ez a minta a munka megbízható átirányításával mérsékli a csomóponthibák hatását. A feladatátvételt konszenzusos algoritmusokkal is megvalósítja, ha egy vezető hibásan működik.

- RE:05 Redundancia
- RE:07 Öngyógyítás

Mint minden tervezési döntésnél, fontolja meg az ezzel a mintával bevezethető többi pillér céljaival szembeni kompromisszumokat.

példa

A GitHub vezető választási mintája bemutatja, hogyan használható bérlet egy Azure Storage-blobon egy megosztott, elosztott mutex implementálásához. Ez a mutex használható vezető választására a rendelkezésre álló munkapéldányok egy csoportja között. Az a példány, amelyik először megszerzi a bérletet, vezetővé válik, és addig marad vezető, amíg le nem mond a bérletről, vagy nem tudja megújítani azt. Más feldolgozópéldányok továbbra is figyelhetik a blobbérletet, ha a vezető már nem érhető el.

A blobbérlet egy blob kizárólagos írási zárolása. Egy blob bármikor csak egy bérlet tárgyát képezheti. A munkafolyamat-példány foglalást kérhet egy adott blobra, és megkapja a foglalást, ha egyetlen másik munkafolyamat-példány sem rendelkezik foglalással ugyanarra a blobra. Ellenkező esetben a kérés kivételt fog eredményezni.

Ha szeretné elkerülni, hogy egy hibás vezetőpéldány határozatlan ideig megtartsa a bérletet, adjon meg egy élettartamot a bérlethez. Ha ez lejár, a bérlet elérhetővé válik. Bár egy példány rendelkezik a bérlettel, kérheti, hogy a bérletet megújítsák, és így egy további időszakra is megkapja azt. A vezető példány folyamatosan megismételheti ezt a folyamatot, ha meg akarja tartani a bérleti szerződést. A blobok bérletéről további információt a Blob bérlete (REST API) című témakörben talál.

Az BlobDistributedMutex alábbi C#-példában szereplő osztály tartalmazza a(z) RunTaskWhenMutexAcquired metódust, amely lehetővé teszi, hogy egy feldolgozópéldány megpróbáljon bérleti jogot szerezni egy adott blobra. A blob részleteit (a nevet, a tárolót és a tárfiókot) az objektum létrehozásakor a rendszer átadja a BlobSettings konstruktornak BlobDistributedMutex (ez az objektum egy egyszerű szerkezet, amely szerepel a mintakódban). A konstruktor elfogad egy Task is, amely a munkás példány által futtatandó kódra hivatkozik, ha sikeresen megszerzi a bérleti jogot a blob birtoklása esetén és vezetővé választják. A bérlet beszerzésének alacsony szintű részleteit kezelő kód egy külön, nevesített BlobLeaseManagersegédosztályban van implementálva.

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);
  }
  ...

Az RunTaskWhenMutexAcquired előző kódminta metódusa meghívja a RunTaskWhenBlobLeaseAcquired következő kódmintában látható metódust a bérlet tényleges beszerzéséhez. A RunTaskWhenBlobLeaseAcquired metódus aszinkron módon fut. Ha a bérleti jog megszerzése sikeresen megtörtént, a munkavégző példányt választották vezetőnek. A taskToRunWhenLeaseAcquired delegált célja a többi feldolgozópéldányt koordináló munka végrehajtása. Ha a bérlet nem szereződött be, egy másik feldolgozópéldányt választottak meg vezetőként, és az aktuális feldolgozópéldány alárendelt marad. Vegye figyelembe, hogy a TryAcquireLeaseOrWait metódus egy segédmetódus, amely az BlobLeaseManager objektumot használja a bérlet beszerzéséhez.

  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);
          ...
        }
      }
    }
    ...
  }

A vezető által indított feladat aszinkron módon is fut. Amíg ez a feladat fut, a RunTaskWhenBlobLeaseAcquired következő kódmintában látható metódus rendszeresen megpróbálja megújítani a bérletet. Ez segít biztosítani, hogy a munkavállalói példány maradjon az irányító. A mintamegoldásban a megújítási kérelmek közötti késés kisebb, mint a bérlet időtartamára megadott idő, hogy megakadályozza egy másik feldolgozópéldány vezetővé választását. Ha a megújítás bármilyen okból meghiúsul, a vezetőspecifikus feladat megszakad.

Ha a lízinget nem sikerül megújítani, vagy a feladatot megszakítják (például a dolgozói példány leállítása miatt), a lízinget felszabadítják. Ezen a ponton ez vagy egy másik munkavégző példány megválasztható vezetőként. Az alábbi kódkivonat a folyamat ezen részét mutatja be.

  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);
        }
      }
    }
  }
  ...
}

A KeepRenewingLease metódus egy másik segédmetódus, amely az BlobLeaseManager objektumot használja a bérlet megújításához. A CancelAllWhenAnyCompletes metódus megszakítja az első két paraméterként megadott feladatokat. Az alábbi ábra azt szemlélteti, hogy az BlobDistributedMutex osztály segítségével kiválaszthat egy vezetőt, és futtathat egy műveleteket koordináló feladatot.

Az 1. ábra a BlobDistributedMutex osztály funkcióit szemlélteti

Az alábbi példakód bemutatja, hogyan használhatja az BlobDistributedMutex osztályt egy feldolgozópéldányon belül. Ez a kód megszerez egy bérletet az Azure Blob Storage egyik tárolójában található MyLeaderCoordinatorTask nevű blobra, és meghatározza, hogy a MyLeaderCoordinatorTask metódusban meghatározott kód fusson, ha a feldolgozópéldányt vezetőnek választják.

// 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)
{
  ...
}

Jegyezze fel a mintamegoldásra vonatkozó alábbi pontokat:

  • A blob egy lehetséges egyetlen meghibásodási pont. Ha a blobszolgáltatás nem érhető el, vagy hozzáférhetetlen, a vezető nem tudja megújítani a bérletet, és más feldolgozó példány sem tudja megszerezni a bérletet. Ebben az esetben egyetlen munkáspéldány sem fog tudni vezetőként működni. A blobszolgáltatás azonban rugalmasnak lett tervezve, ezért a blobszolgáltatás teljes meghibásodása rendkívül valószínűtlennek tekinthető.
  • Ha a vezető által végzett feladat elakad, a vezető továbbra is megújíthatja a bérleti szerződést, megakadályozva ezzel, hogy bármely más feldolgozópéldány megszerezhesse a bérletet és átvehesse a vezetői pozíciót a feladatok koordinálása érdekében. A valós világban a vezető állapotát gyakran ellenőrizni kell.
  • A választási folyamat nem determinisztikus. Nem tehetünk pontos megállapítást arra vonatkozóan, hogy melyik dolgozói példány fogja megszerezni a blob bérletét és válik vezetővé.
  • A blob bérlet célobjektumaként használt objektumot semmilyen más célra nem szabad használni. Ha egy feldolgozópéldány ebben a blobban próbál adatokat tárolni, ezek az adatok csak akkor lesznek elérhetők, ha a feldolgozópéldány a vezető, és a blobbérletet tárolja.

Következő lépések

A minta megvalósításakor az alábbi útmutatás is releváns lehet: