Üzenetek átvitele, zárolása és elszámolása

Egy üzenetközvetítő, például a Service Bus központi képessége, hogy üzeneteket fogad egy üzenetsorba vagy témakörbe, és a későbbi lekéréshez elérhetővé teszi őket. A küldés az üzenetnek az üzenetközvetítőbe történő átvitelére használt kifejezés. A fogadás az üzenet lekéréses ügyfélnek való átadására gyakran használt kifejezés.

Amikor egy ügyfél üzenetet küld, általában tudni szeretné, hogy az üzenet megfelelően van-e átadva és elfogadva a közvetítőnek, vagy valamilyen hiba történt-e. Ez a pozitív vagy negatív visszaigazolás rendezi az ügyfél és a közvetítő megértését az üzenet átviteli állapotáról. Ezért ezt nevezik kiegyenlítésnek.

Hasonlóképpen, amikor a közvetítő egy üzenetet továbbít egy ügyfélnek, a közvetítő és az ügyfél szeretné megtudni, hogy az üzenet sikeresen feldolgozva van-e, ezért eltávolítható-e, vagy az üzenet kézbesítése vagy feldolgozása sikertelen volt-e, és így előfordulhat, hogy az üzenetet újra kell kézbesíteni.

Küldési műveletek rendezése

A támogatott Service Bus API-ügyfelek bármelyikének használatával a Service Busba történő küldési műveletek mindig explicit módon lesznek rendezve, ami azt jelenti, hogy az API-művelet megvárja, amíg a Service Bus elfogadási eredménye megérkezik, majd befejezi a küldési műveletet.

Ha a Service Bus elutasítja az üzenetet, az elutasítás egy hibajelzőt és egy nyomkövetési azonosítót tartalmazó szöveget tartalmaz. Az elutasítás azt is tartalmazza, hogy a művelet újrapróbálkozhat-e bármilyen sikeres várakozással. Az ügyfélben ez az információ kivételként jelenik meg, és a küldési művelet hívójához kerül. Ha az üzenet elfogadásra kerül, a művelet csendesen befejeződik.

Az Advanced Messaging Queuing Protocol (AMQP) az egyetlen protokoll, amelyet a .NET Standard, Java, JavaScript, Python és Go ügyfelek támogatnak. .NET-keretrendszer ügyfelek esetében használhatja a Service Bus Messaging Protocol (SBMP) vagy az AMQP protokollt. Az AMQP protokoll használatakor az üzenetátvitelek és -elszámolások folyamatalapúak és aszinkronok lesznek. Javasoljuk, hogy az aszinkron programozási modell API-változatait használja.

2026. szeptember 30-án kivonjuk az Azure Service Bus SDK-kódtárakat a WindowsAzure.ServiceBus, a Microsoft.Azure.ServiceBus és a com.microsoft.azure.servicebus kódtárakból, amelyek nem felelnek meg az Azure SDK irányelveinek. Az SBMP protokoll támogatását is megszüntetjük, így 2026. szeptember 30. után már nem használhatja ezt a protokollt. Migrálás a legújabb Azure SDK-kódtárakba, amelyek kritikus fontosságú biztonsági frissítéseket és továbbfejlesztett képességeket kínálnak ezen dátum előtt.

Bár a régebbi kódtárak 2026. szeptember 30-tól továbbra is használhatók, a Microsoft már nem kap hivatalos támogatást és frissítéseket. További információkért lásd a támogatási nyugdíjazási bejelentést.

A feladó gyorsan egymás után több üzenetet is elhelyezhet a vezetéken anélkül, hogy várnia kellene az egyes üzenetek nyugtázására, ahogyan egyébként az SBMP protokoll vagy a HTTP 1.1 esetében is. Ezek az aszinkron küldési műveletek a megfelelő üzenetek elfogadásakor és tárolásakor, particionált entitásokon vagy a különböző entitásokra történő küldéskor befejeződnek. A befejezések az eredeti küldési rendelésből is előfordulhatnak.

A küldési műveletek eredményének kezelésére szolgáló stratégia azonnali és jelentős teljesítménybeli hatással lehet az alkalmazásra. Az ebben a szakaszban szereplő példák C# nyelven vannak megírva, és java határidős, Java-monos, JavaScript-ígéretekre és más nyelveken egyenértékű fogalmakra vonatkoznak.

Ha az alkalmazás egy egyszerű hurokkal illusztrált üzeneteket hoz létre, és az egyes küldési műveletek befejezésére vár, mielőtt a következő üzenetet, szinkron vagy aszinkron API-alakzatokat küldené, akkor 10 üzenet küldése csak 10 egymást követő teljes körút után fejeződik be a kiegyenlítéshez.

A feltételezett 70 ezredmásodperces Átviteli vezérlési protokoll (TCP) ciklikus késési távolsága egy helyszíni helytől a Service Busig, és mindössze 10 ms-t ad a Service Busnak az egyes üzenetek elfogadásához és tárolásához, a következő ciklus legalább 8 másodpercet vesz igénybe, nem számítva a hasznos adatok átvitelének idejét vagy az útvonalak torlódásának lehetséges hatásait:

for (int i = 0; i < 10; i++)
{
    // creating the message omitted for brevity
    await sender.SendMessageAsync(message);
}

Ha az alkalmazás azonnal elindítja a 10 aszinkron küldési műveletet, és külön várja azok befejezését, a 10 küldési művelethez tartozó oda-vissza menetidő átfedésben van. A 10 üzenet közvetlen egymás után kerül átadásra, akár TCP-keretek megosztásával is, és az átvitel teljes időtartama nagyban függ a hálózattal kapcsolatos időtől, amíg az üzeneteket átviszik a közvetítőhöz.

Az előző ciklushoz hasonló feltételezések mellett a következő ciklus teljes átfedésben lévő végrehajtási ideje egy másodperc alatt is megmaradhat:

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    tasks.Add(sender.SendMessageAsync(message));
}
await Task.WhenAll(tasks);

Fontos megjegyezni, hogy az összes aszinkron programozási modell valamilyen memóriaalapú rejtett munkasort használ, amely függőben lévő műveleteket tartalmaz. Amikor a küldési API visszatér, a küldési feladat várólistára kerül a munkahelyi várólistán, de a protokoll kézmozdulata csak akkor indul el, ha a feladat éppen fut. Az olyan kódok esetében, amelyek általában üzenetkitöréseket küldenek, és ahol a megbízhatóság aggodalomra ad okot, ügyelni kell arra, hogy ne legyen túl sok üzenet egyszerre "repülés közben", mert az összes elküldött üzenet memóriát vesz fel, amíg a vezetékre nem kerülnek.

A semaphorok, ahogyan az a C# kódrészletében látható, olyan szinkronizálási objektumok, amelyek szükség esetén engedélyezik az ilyen alkalmazásszintű szabályozást. A szemaphore használata legfeljebb 10 üzenet egyidejű repülését teszi lehetővé. A küldés előtt a rendszer a 10 elérhető szemaphore-zárolás egyikeként jelenik meg, és a küldés befejezésekor ki lesz adva. A 11. áthalad a hurokon, amíg az előző küldési műveletek közül legalább egy befejeződik, majd elérhetővé teszi a zárolását:

var semaphore = new SemaphoreSlim(10);

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    await semaphore.WaitAsync();

    tasks.Add(sender.SendMessageAsync(message).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

Az alkalmazások soha nem kezdeményeznek aszinkron küldési műveletet "tűz és felejtés" módon a művelet eredményének lekérése nélkül. Ezzel betöltheti a belső és láthatatlan feladatsort a memória kimerüléséig, és megakadályozhatja, hogy az alkalmazás észlelje a küldési hibákat:

for (int i = 0; i < 10; i++)
{
    sender.SendMessageAsync(message); // DON’T DO THIS
}

Alacsony szintű AMQP-ügyfél esetén a Service Bus "előre beállított" átviteleket is elfogad. Az előre beállított átvitel egy olyan tűz- és felejtési művelet, amelynek eredményét a rendszer nem jelenti vissza az ügyfélnek, és az üzenet elküldésekor kiegyenlítettnek minősül. Az ügyfélnek küldött visszajelzés hiánya azt is jelenti, hogy a diagnosztika nem érhető el végrehajtható adatokkal, ami azt jelenti, hogy ez a mód nem jogosult a Azure-támogatás keresztüli segítségre.

Fogadási műveletek rendezése

Fogadási műveletek esetén a Service Bus API-ügyfelek két különböző explicit módot engedélyeznek: a Fogadás és törlés és a Betekintő zárolást.

ReceiveAndDelete

A Fogadás és törlés mód arra utasítja a közvetítőt, hogy fontolja meg a fogadó ügyfélnek küldött összes üzenetet a küldéskor kiegyenlítettnek. Ez azt jelenti, hogy az üzenet akkor tekinthető felhasználtnak, amint a közvetítő a vezetékre helyezi. Ha az üzenetátvitel sikertelen, az üzenet elveszik.

Ennek a módnak az az előnye, hogy a fogadónak nem kell további lépéseket tennie az üzeneten, és nem is lassítja a kiegyenlítés kimenetelére való várakozás. Ha az egyes üzenetekben szereplő adatok értéke alacsony, és/vagy csak nagyon rövid ideig értelmezhetők, ez a mód ésszerű választás.

PeekLock

A Betekintő-zárolás mód azt jelzi a közvetítőnek, hogy a fogadó ügyfél explicit módon szeretné rendezni a fogadott üzeneteket. Az üzenet elérhetővé válik a fogadó számára a feldolgozáshoz, miközben a szolgáltatás kizárólagos zárolása alatt tartja, hogy más, versengő fogadók ne láthassák. A zárolás időtartama kezdetben az üzenetsor vagy az előfizetés szintjén van meghatározva, és a renewMessageLockAsync művelettel meghosszabbítható a zárolást birtokoló ügyfél számára. A zárolások megújításával kapcsolatos részletekért tekintse meg a jelen cikk Zárolások megújítása szakaszát.

Ha egy üzenet zárolva van, az ugyanabból az üzenetsorból vagy előfizetésből érkező többi ügyfél zárolhatja az üzeneteket, és lekérheti a következő, nem aktív zárolás alatt álló üzeneteket. Ha az üzenet zárolása explicit módon ki van adva, vagy ha a zárolás lejár, az üzenet a lekérési sorrend előlapján vagy annak közelében lesz elhelyezve az újrarendeléshez.

Ha az üzenetet a fogadók ismételten feloldják, vagy egy meghatározott számú alkalommal engedélyezik a zárolást (maximális kézbesítési szám), a rendszer automatikusan eltávolítja az üzenetet az üzenetsorból vagy az előfizetésből, és a társított kézbesítetlen levelek üzenetsorába helyezi.

A fogadó ügyfél pozitív nyugtával kezdeményezi a fogadott üzenetek kiegyenlítését, amikor meghívja az üzenet Complete API-ját. Azt jelzi a közvetítőnek, hogy az üzenet feldolgozása sikeresen megtörtént, és az üzenet el lesz távolítva az üzenetsorból vagy az előfizetésből. A közvetítő válaszol a fogadó elszámolási szándékára egy válaszsal, amely jelzi, hogy a kiegyenlítés végrehajtható-e.

Ha a fogadó ügyfél nem tudja feldolgozni az üzenetet, de azt szeretné, hogy az üzenetet újra kézbesítse, explicit módon kérheti az üzenet azonnali kiadását és zárolásának feloldását az üzenet lemondási API-jának meghívásával, vagy nem tehet semmit, és hagyhatja, hogy a zárolás elteljen.

Ha egy fogadó ügyfél nem tudja feldolgozni az üzenetet, és tudja, hogy az üzenet újbóli kézbesítése és a művelet újrapróbálkozása nem fog segíteni, elutasíthatja az üzenetet, amely az üzenet DeadLetter API meghívásával áthelyezi azt a holtbetűs üzenetsorba, ami lehetővé teszi egy egyéni tulajdonság beállítását is, beleértve egy okkódot is, amely lekérhető az üzenettel a kézbesítetlen levelek üzenetsorából.

Feljegyzés

Egy üzenetsorhoz vagy témakör-előfizetéshez csak akkor létezik holtbetűs alqueue, ha engedélyezve van a kézbesítetlen levelek funkció az üzenetsorhoz vagy az előfizetéshez.

A kiegyenlítés különleges esete a halasztás, amelyet egy külön cikkben tárgyalunk.

A Complete, , DeadLettervagy RenewLock műveletek hálózati problémák miatt meghiúsulhatnak, ha a zárolt zárolás lejárt, vagy más szolgáltatásoldali feltételek megakadályozzák az elszámolást. Az utóbbi esetekben a szolgáltatás negatív visszaigazolást küld, amely kivételként jelentkezik az API-ügyfelekben. Ha az ok egy megszakadt hálózati kapcsolat, a zárolás megszakad, mivel a Service Bus nem támogatja a meglévő AMQP-kapcsolatok helyreállítását egy másik kapcsolaton.

Ha Complete nem sikerül, amely általában az üzenetkezelés végén és bizonyos esetekben a munka feldolgozásának percei után következik be, a fogadó alkalmazás eldöntheti, hogy megőrzi-e a munka állapotát, és figyelmen kívül hagyja-e ugyanazt az üzenetet a második alkalommal történő kézbesítéskor, vagy a munka eredményét és újrapróbálkozását az üzenet újbóli kézbesítésekor.

Az ismétlődő üzenetküldő üzenetek azonosításának tipikus mechanizmusa az üzenetazonosító ellenőrzése, amelyet a feladó egyedi értékre állíthat be és kell beállítania, esetleg az eredeti folyamatból származó azonosítóhoz igazítva. A feladatütemező valószínűleg annak a feladatnak az azonosítójára állítja az üzenetazonosítót, amelyet egy adott feldolgozóval rendelkező feldolgozóhoz próbál hozzárendelni, és a feldolgozó figyelmen kívül hagyja a feladat-hozzárendelés második előfordulását, ha a feladat már elkészült.

Fontos

Fontos megjegyezni, hogy a PeekLock vagy a SessionLock által az üzeneten beszerzett zárolás változékony, és a következő feltételek mellett elveszhet

  • Szolgáltatásfrissítés
  • Operációs rendszer frissítése
  • Az entitás tulajdonságainak módosítása (üzenetsor, témakör, előfizetés) a zárolás megtartása közben.

A zárolás elvesztése után az Azure Service Bus létrehoz egy MessageLockLostException vagy SessionLockLostException objektumot, amely megjelenik az ügyfélalkalmazásban. Ilyen esetben az ügyfél alapértelmezett újrapróbálkozási logikájának automatikusan működésbe kell lépnie, hogy újra megkísérelje a műveletet.

Zárolások megújítása

A zárolási időtartam alapértelmezett értéke 1 perc. A zárolás időtartamának más értéket is megadhat az üzenetsor vagy az előfizetés szintjén. A zárolást birtokoló ügyfél megújíthatja az üzenetzárolást a fogadó objektum metódusainak használatával. Ehelyett használhatja az automatikus zárolásmegújítási funkciót, ahol megadhatja, hogy mennyi ideig szeretné megújítani a zárolást.

A legjobb, ha a zárolás időtartamát a normál feldolgozási időnél magasabbra állítja, így nem kell megújítani a zárolást. A maximális érték 5 perc, ezért meg kell újítania a zárolást, ha hosszabb ideig szeretné használni. A szükségesnél hosszabb zárolási időtartamnak is vannak következményei. Ha például az ügyfél nem működik, az üzenet csak a zárolási időtartam leteltét követően válik ismét elérhetővé.

Következő lépések