Csövek és szűrők mintája

Azure Blob Storage
Azure Functions
Azure Queue Storage

Egy összetett feldolgozást végrehajtó feladatot lebonthat különálló, újrahasznosítható elemek sorává. Ez javíthatja a teljesítményt, a méretezhetőséget és az újrafelhasználhatóságot azáltal, hogy lehetővé teszi a feldolgozást végző tevékenységelemek egymástól függetlenül történő üzembe helyezését és skálázását.

Kontextus és probléma

Az alkalmazások különböző feladatokat hajthatnak végre, amelyek összetettsége az általa feldolgozott információktól függően változhat. Az alkalmazások implementálásának egyszerű, de rugalmatlan megközelítése, ha ezt a feldolgozást monolitikus modulban hajtja végre. Ez a megközelítés azonban valószínűleg csökkenti a kód újrabontásának, optimalizálásának vagy újrafelhasználásának lehetőségét, ha az alkalmazás más részein is szükség van ugyanannak a feldolgozásnak a részeire.

Az alábbi ábra az adatok monolitikus megközelítéssel történő feldolgozásával kapcsolatos problémákat mutatja be. Az alkalmazások két forrásból fogadnak és dolgoznak fel adatokat. Az egyes forrásból származó adatokat egy külön modul dolgozza fel, amely feladatokat hajt végre az adatok átalakításához, mielőtt átadná az eredményt az alkalmazás üzleti logikájának.

Diagram that shows a solution implemented with monolithic modules.

A monolitikus modulok által végrehajtott feladatok némelyike funkcionálisan hasonló, de a modulokat külön tervezték. A feladatokat megvalósító kód szorosan kapcsolódik egy modulhoz. A fejlesztés során nem vették figyelembe az újrafelhasználhatóságot és a méretezhetőséget.

Az egyes modulok által végrehajtott feldolgozási feladatok, illetve az egyes tevékenységek üzembehelyezési követelményei azonban változhatnak az üzleti követelmények frissítésekor. Egyes feladatok nagy számítási igényű tevékenységek lehetnek, amelyek kihasználhatják a hatékony hardveren való futtatás előnyeit. Előfordulhat, hogy más feladatok nem igényelnek ilyen drága erőforrásokat. Emellett további feldolgozásra is szükség lehet a jövőben, vagy az a sorrend, amelyben a feldolgozás által végrehajtott feladatok változhatnak. Olyan megoldásra van szükség, amely kezeli ezeket a problémákat, és növeli a kód újrafelhasználásának lehetőségeit.

Megoldás

Az egyes streamekhez szükséges feldolgozást bontsa fel különálló összetevőkre (vagy szűrőkre), amelyek mindegyike egyetlen feladatot hajt végre. Az egyes összetevők által kapott és küldött adatok szabványos formátumának eléréséhez a szűrők kombinálhatók a folyamatban. Ezzel elkerülheti a kód duplikálását, és megkönnyíti az összetevők eltávolítását vagy cseréjét, illetve további összetevők integrálását, ha a feldolgozási követelmények megváltoznak. Ez az ábra egy csövekkel és szűrőkkel implementált megoldást mutat be:

Diagram that shows a solution that's implemented with pipes and filters.

Az egyetlen kérés feldolgozásához szükséges idő a folyamat leglassabb szűrőinek sebességétől függ. Egy vagy több szűrő szűk keresztmetszetet jelenthet, különösen akkor, ha egy adott adatforrásból származó streamben nagy számú kérés jelenik meg. A folyamatstruktúra egyik fő előnye, hogy lehetővé teszi a lassú szűrők párhuzamos példányainak futtatását, így a rendszer eloszthatja a terhelést, és javíthatja az átviteli sebességet.

A folyamatokat alkotó szűrők különböző gépeken futtathatók, így egymástól függetlenül skálázhatók, és kihasználhatják a számos felhőkörnyezet által biztosított rugalmasságot. A számításigényes szűrők nagy teljesítményű hardvereken futtathatók, míg más kevésbé igényes szűrők kevésbé költséges hardvereken üzemeltethetők. A szűrőknek nem is kell ugyanabban az adatközpontban vagy földrajzi helyen lenniük, így a folyamat minden eleme olyan környezetben fusson, amely közel van a szükséges erőforrásokhoz. Ez az ábra az 1. forrásból származó adatok folyamatára alkalmazott példát mutatja be:

Diagram that shows an example applied to the pipeline for the data from Source 1.

Ha egy szűrő bemenete és kimenete streamként van strukturálva, az egyes szűrők feldolgozása párhuzamosan is elvégezhető. A folyamat első szűrője elindíthatja a munkáját, és kimenetelheti az eredményeit, amelyeket közvetlenül a következő szűrőnek ad át a sorozatban, mielőtt az első szűrő befejezi a munkáját.

Ennek a modellnek egy másik előnye a rugalmasság, amelyet képes biztosítani. Ha egy szűrő meghibásodik, vagy a gép, amelyen fut, már nem érhető el, a folyamat átütemezheti a szűrő által végzett munkát, és átirányíthatja az összetevő egy másik példányára. Egyetlen szűrő meghibásodása nem feltétlenül eredményezi a teljes folyamat meghibásodását.

Az elosztott tranzakciók implementálásának alternatív módszere a Csövek és szűrők minta és a Kompenzáló tranzakció minta együttes használata. Az elosztott tranzakciókat külön, kompenzálható tevékenységekre bonthatja, amelyek mindegyike implementálható egy szűrővel, amely a kompenzáló tranzakció mintáját is implementálja. A folyamatok szűrőit olyan különálló üzemeltetett feladatokként implementálhatja, amelyek az általuk kezelt adatok közelében futnak.

Problémák és megfontolandó szempontok

Vegye figyelembe a következő szempontokat, amikor úgy dönt, hogy hogyan valósítja meg ezt a mintát:

  • Összetettség. A minta által biztosított megnövelt rugalmasság összetettséget is eredményezhet, különösen akkor, ha a folyamat szűrői különböző kiszolgálókon vannak elosztva.

  • Megbízhatóság. Olyan infrastruktúrát használjon, amely biztosítja, hogy ne legyen adatvesztés a folyamat szűrői közötti adatátvitel során.

  • Idempotencia. Ha egy folyamat szűrője egy üzenet fogadása után meghiúsul, és a munka a szűrő egy másik példányára van ütemezve, a munka egy része már befejeződött. Ha a munka frissíti a globális állapot valamely aspektusát (például az adatbázisban tárolt adatokat), egyetlen frissítés megismételhető. Hasonló probléma akkor fordulhat elő, ha egy szűrő meghiúsul, miután közzétette az eredményeit a folyamat következő szűrőjében, de mielőtt jelezné, hogy sikeresen befejezte a munkáját. Ezekben az esetekben lehetséges, hogy ugyanazt a feladatot a szűrő egy másik példánya is elvégzi, így ugyanazok az eredmények kétszer lesznek közzétéve. Ez a forgatókönyv azt eredményezheti, hogy a folyamat további szűrői kétszer dolgoznak fel ugyanazokat az adatokat. Ezért a folyamat szűrőit idempotensnek kell tervezni. További információ: Idempotency Patterns on Jonathan Oliver's blog.

  • Ismétlődő üzenetek. Ha egy folyamat szűrője meghiúsul, miután üzenetet tesz közzé a folyamat következő szakaszára, előfordulhat, hogy a szűrő egy másik példánya fut, és ugyanannak az üzenetnek egy példányát közzéteszi a folyamatnak. Ez a forgatókönyv azt eredményezheti, hogy ugyanannak az üzenetnek két példánya lesz átadva a következő szűrőnek. A probléma elkerülése érdekében a folyamatnak észlelnie kell és meg kell szüntetnie az ismétlődő üzeneteket.

    Feljegyzés

    Ha üzenetsorok (például Azure Service Bus-üzenetsorok) használatával valósítja meg a folyamatot, az üzenetsor-kezelési infrastruktúra automatikusan ismétlődő üzenetészlelést és -eltávolítást biztosíthat.

  • Kontextus és állapot. A folyamatokban a szűrők gyakorlatilag elkülönítve futnak, és nem tudják feltételezni azok aktiválásuk módját. Ezért minden szűrőnek elegendő kontextust kell biztosítani a munkájához. Ez a környezet jelentős mennyiségű állapotinformációt tartalmazhat.

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

Használja ezt a mintát, ha:

  • Az alkalmazások számára szükséges feldolgozási folyamat egyszerűen lebontható független lépések sorozatára.

  • Az alkalmazások által végrehajtott feldolgozási lépések különböző skálázhatósági követelményekkel rendelkeznek.

    Feljegyzés

    Csoportosíthatja azokat a szűrőket, amelyeknek ugyanabban a folyamatban együtt kell skálázniuk. További információkért lásd a számításierőforrás-konszolidálási mintát.

  • Rugalmasságot igényel ahhoz, hogy lehetővé tegye az alkalmazás által végrehajtott feldolgozási lépések átrendezését, vagy lehetővé tegye a lépések hozzáadását és eltávolítását.

  • A rendszer számára előnyös lehet, ha az egyes lépésekhez tartozó feldolgozási folyamatok különböző kiszolgálókra vannak elosztva.

  • Olyan megbízható megoldásra van szüksége, amely minimálisra csökkenti az adatok feldolgozása során fellépő hibák hatásait egy lépésben.

Nem érdemes ezt a mintát használni, ha:

  • Az alkalmazás által végrehajtott feldolgozási lépések nem függetlenek, vagy egy tranzakció részeként együtt kell végrehajtani őket.

  • A lépéshez szükséges környezeti vagy állapotinformációk mennyisége miatt ez a megközelítés nem hatékony. Előfordulhat, hogy meg tudja őrizni az állapotinformációkat egy adatbázisban, de ne használja ezt a stratégiát, ha az adatbázis többletterhelése túlzott versengést okoz.

Példa

Az üzenetsorok sorozatával biztosíthatja a folyamat implementálásához szükséges infrastruktúrát. A kezdeti üzenetsorok feldolgozatlan üzeneteket kapnak, amelyek a csövek és a szűrők mintájának implementálásának kezdeteivé válnak. A szűrőfeladatként implementált összetevő figyeli az üzenetsor üzeneteit, végrehajtja a munkáját, majd új vagy átalakított üzenetet küld a következő üzenetsorba a sorrendben. Egy másik szűrőfeladat figyelheti az üzenetsoron lévő üzeneteket, feldolgozhatja őket, közzéteheti az eredményeket egy másik üzenetsorba, és így tovább, amíg az utolsó lépés, amely befejezi a csövek és a szűrők folyamatát. Ez az ábra egy üzenetsorokat használó folyamatot szemléltet:

Diagram showing a pipeline that uses message queues.

Ezzel a mintával egy képfeldolgozó folyamat implementálható. Ha a számítási feladat lemezképet készít, a rendszerkép nagyrészt független és átrendezhető szűrők sorozatán haladhat át az olyan műveletek végrehajtásához, mint például:

  • con sátormód ration
  • átméretezés
  • Vízjel
  • tájolás
  • Metaadatok exif eltávolítása
  • Tartalomkézbesítési hálózat (CDN) kiadványa

Ebben a példában a szűrők egyénileg üzembe helyezett Azure Functionsként vagy akár egyetlen Azure-függvényalkalmazásként is implementálhatók, amelyek az egyes szűrőket izolált üzemelő példányként tartalmazzák. Az Azure-függvény eseményindítóinak, bemeneti kötéseinek és kimeneti kötéseinek használata leegyszerűsítheti a szűrőkódot, és automatikusan együttműködhet egy üzenetsoralapú csővel a rendszerkép jogcím-ellenőrzése segítségével a feldolgozáshoz.

Diagram showing an image processing pipeline that uses Azure Queue Storage between a series of Azure Functions.

Íme egy példa arra, hogy egy Azure-függvényként implementált szűrő hogyan aktiválódik egy Queue Storage-csőből egy jogcímellenőrzéssel a képre, és hogyan nézhet ki egy új jogcím-ellenőrzés írása egy másik Queue Storage-csőbe. Az implementációt a rövidség kedvéért pszeudokódra cserélték. Ehhez hasonló kód a GitHubon elérhető Csövek és szűrők minta bemutatójában található.

// This is the "Resize" filter. It handles claim checks from input pipe, performs the
// resize work, and places a claim check in the next pipe for anther filter to handle.
[Function(nameof(ResizeFilter))]
[QueueOutput("pipe-fjur", Connection = "pipe")]  // Destination pipe claim check
public async Task<string> RunAsync(
  [QueueTrigger("pipe-xfty", Connection = "pipe")] string imageFilePath,  // Source pipe claim check
  [BlobInput("{QueueTrigger}", Connection = "pipe")] BlockBlobClient imageBlob)  // Image to process
{
  _logger.LogInformation("Processing image {uri} for resizing.", imageBlob.Uri);

  // Idempotency checks
  // ...

  // Download image based on claim check in queue message body
  // ...
  
  // Resize the image
  // ...

  // Write resized image back to storage
  // ...

  // Create claim check for image and place in the next pipe
  // ...
  
  _logger.LogInformation("Image resizing done or not needed. Adding image {filePath} into the next pipe.", imageFilePath);
  return imageFilePath;
}

Következő lépések

A minta megvalósításakor a következő erőforrások lehetnek hasznosak:

A minta megvalósításakor az alábbi minták is relevánsak lehetnek:

  • Jogcím-ellenőrzési minta. Előfordulhat, hogy egy üzenetsort használó folyamat nem a szűrőkön keresztül küldött tényleges elemet tárolja, hanem a feldolgozandó adatokra mutató mutatót. A példa egy jogcím-ellenőrzést használ az Azure Queue Storage-ban az Azure Blob Storage-ban tárolt képekhez.
  • Versengő felhasználókat ismertető minta. A folyamatok adott szűrők több példányát is tartalmazhatják. Ez a módszer lassú szűrők párhuzamos példányainak futtatásához hasznos. Lehetővé teszi a rendszer számára a terhelés elterjesztését és az átviteli sebesség javítását. A szűrő minden példánya versenge a többi példánnyal való bemenetért, de a szűrő két példánya nem tudja feldolgozni ugyanazokat az adatokat. Ez a cikk a megközelítést ismerteti.
  • Számításierőforrás-konszolidálási minta. Lehetséges, hogy olyan szűrőket csoportosítunk, amelyeknek egyetlen folyamatba kell skálázniuk. Ez a cikk további információt nyújt a stratégia előnyeiről és kompromisszumairól.
  • Kompenzáló tranzakció mintája. A szűrőt megfordítható műveletként implementálhatja, vagy olyan kompenzáló művelettel rendelkezik, amely hiba esetén visszaállítja az állapotot egy korábbi verzióra. Ez a cikk azt ismerteti, hogyan valósíthatja meg ezt a mintát a végleges konzisztencia fenntartása vagy elérése érdekében.