Överföringar av meddelanden, lås och uppgörelser

Den centrala funktionen för en meddelandekö, till exempel Service Bus, är att acceptera meddelanden i en kö eller ett ämne och hålla dem tillgängliga för senare hämtning. Send är den term som ofta används för överföring av ett meddelande till meddelandekoordinatorn. Ta emot är den term som ofta används för överföring av ett meddelande till en hämtningsklient.

När en klient skickar ett meddelande vill den vanligtvis veta om meddelandet överförs korrekt till och godkänns av asynkron meddelandekö eller om något slags fel uppstod. Den här positiva eller negativa bekräftelsen avgör förståelsen för både klienten och mäklaren om meddelandets överföringstillstånd. Därför kallas det för en uppgörelse.

På samma sätt, när mäklaren överför ett meddelande till en klient, vill mäklaren och klienten upprätta en förståelse för om meddelandet har bearbetats och därför kan tas bort, eller om meddelandeleveransen eller bearbetningen misslyckades, och därför kan meddelandet behöva levereras igen.

Lösa sändningsåtgärder

Med hjälp av någon av de Service Bus API-klienter som stöds regleras alltid sändningsåtgärder till Service Bus uttryckligen, vilket innebär att API-åtgärden väntar på att ett godkännanderesultat från Service Bus ska tas emot och sedan slutför sändningsåtgärden.

Om meddelandet avvisas av Service Bus innehåller avvisandet en felindikator och text med ett spårnings-ID i det. Avvisandet innehåller också information om huruvida åtgärden kan göras om med någon förväntan på framgång. I klienten omvandlas den här informationen till ett undantag och skickas till anroparen för sändningsåtgärden. Om meddelandet godkänns slutförs åtgärden tyst.

Advanced Messaging Queuing Protocol (AMQP) är det enda protokoll som stöds för .NET Standard-, Java-, JavaScript-, Python- och Go-klienter. För .NET Framework-klienter kan du använda Service Bus Messaging Protocol (SBMP) eller AMQP. När du använder AMQP-protokollet pipelines och asynkrona meddelandeöverföringar och kvittningar. Vi rekommenderar att du använder api-varianterna för asynkrona programmeringsmodeller.

Den 30 september 2026 drar vi tillbaka Azure Service Bus SDK-biblioteken WindowsAzure.ServiceBus, Microsoft.Azure.ServiceBus och com.microsoft.azure.servicebus, som inte följer Riktlinjerna för Azure SDK. Vi kommer också att avsluta stödet för SBMP-protokollet, så du kommer inte längre att kunna använda det här protokollet efter den 30 september 2026. Migrera till de senaste Azure SDK-biblioteken, som erbjuder kritiska säkerhetsuppdateringar och förbättrade funktioner, före det datumet.

Även om de äldre biblioteken fortfarande kan användas efter den 30 september 2026 får de inte längre officiell support och uppdateringar från Microsoft. Mer information finns i meddelandet om supportavgång.

En avsändare kan placera flera meddelanden på tråden i snabb följd utan att behöva vänta tills varje meddelande bekräftas, vilket annars skulle vara fallet med SBMP-protokollet eller med HTTP 1.1. Dessa asynkrona sändningsåtgärder slutförs när respektive meddelanden accepteras och lagras, på partitionerade entiteter eller när sändningsåtgärden till olika entiteter överlappar varandra. Slutförandena kan också inträffa från den ursprungliga sändningsbeställningen.

Strategin för att hantera resultatet av sändningsåtgärder kan ha omedelbar och betydande prestandapåverkan för ditt program. Exemplen i det här avsnittet är skrivna i C# och gäller för Java-terminer, Java-monoer, JavaScript-löften och motsvarande begrepp på andra språk.

Om programmet genererar mängder meddelanden, som illustreras här med en oformaterad loop, och väntar på att varje sändningsåtgärd ska slutföras innan nästa meddelande, synkrona eller asynkrona API-former skickas, slutförs endast 10 meddelanden efter 10 sekventiella fullständiga rundresor för kvittning.

Med ett förmodat svarstidsavstånd på 70 millisekunder (TCP) tur och retur från en lokal plats till Service Bus och ger bara 10 ms för Service Bus att acceptera och lagra varje meddelande, tar följande loop upp minst 8 sekunder, utan att räkna överföringstiden för nyttolasten eller potentiella trafikstockningseffekter:

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

Om programmet startar de 10 asynkrona sändningsåtgärderna i omedelbar följd och väntar på respektive slutförande separat överlappar tur och retur-tiden för dessa 10 sändningsåtgärder. De 10 meddelandena överförs i omedelbar följd, eventuellt till och med delar TCP-ramar, och den totala överföringstiden beror till stor del på den nätverksrelaterade tid det tar att få meddelandena överförda till asynkron meddelandekö.

Med samma antaganden som för föregående loop kan den totala överlappande körningstiden för följande loop ligga långt under en sekund:

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

Observera att alla asynkrona programmeringsmodeller använder någon form av minnesbaserad, dold arbetskö som innehåller väntande åtgärder. När SKICKA-API:et returnerar placeras sändningsaktiviteten i kö i arbetskön, men protokollgesten påbörjas bara när det är uppgiftens tur att köras. För kod som tenderar att skicka meddelanden och där tillförlitlighet är ett problem bör du vara noga med att inte för många meddelanden sätts "i flygning" på en gång, eftersom alla skickade meddelanden tar upp minnet tills de sätts på tråden.

Semaforer, som visas i följande kodfragment i C#, är synkroniseringsobjekt som aktiverar sådan begränsning på programnivå vid behov. Denna användning av en semafor gör det möjligt för högst 10 meddelanden att vara i flygning på en gång. En av de 10 tillgängliga semaforlåsen tas innan sändningen och den släpps när sändningen slutförs. Den elfte passerar genom loopen väntar tills minst en av de tidigare sändningsåtgärderna har slutförts och gör sedan låset tillgängligt:

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

Program bör aldrig initiera en asynkron sändningsåtgärd på ett "fire and forget"-sätt utan att hämta resultatet av åtgärden. Detta kan läsa in den interna och osynliga uppgiftskö som uppstått till minnesöverbelastning och förhindra att programmet identifierar sändningsfel:

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

Med en AMQP-klient på låg nivå accepterar Service Bus även "presettled"-överföringar. En förinställd överföring är en "fire-and-forget"-åtgärd för vilken resultatet i vilket fall som helst inte rapporteras tillbaka till klienten och meddelandet anses vara avgjort när det skickas. Bristen på feedback till klienten innebär också att det inte finns några tillgängliga åtgärdsdata för diagnostik, vilket innebär att det här läget inte kvalificerar sig för hjälp via Azure-supporten.

Lösa mottagningsåtgärder

För mottagningsåtgärder aktiverar Service Bus API-klienterna två olika explicita lägen: Ta emot och ta bort och Peek-Lock.

ReceiveAndDelete

Läget Ta emot och ta bort uppmanar mäklaren att överväga alla meddelanden som skickas till den mottagande klienten som avgjorda när de skickas. Det innebär att meddelandet anses förbrukat så snart asynkron meddelandekö placerar det på tråden. Om meddelandeöverföringen misslyckas går meddelandet förlorat.

Fördelen med det här läget är att mottagaren inte behöver vidta ytterligare åtgärder på meddelandet och inte heller bromsas genom att vänta på resultatet av uppgörelsen. Om data i de enskilda meddelandena har lågt värde och/eller bara är meningsfulla under en mycket kort tid är det här läget ett rimligt val.

PeekLock

Peek-Lock-läget talar om för den mottagande klienten att den mottagande klienten uttryckligen vill reglera mottagna meddelanden. Meddelandet görs tillgängligt för mottagaren att bearbeta, medan det hålls under ett exklusivt lås i tjänsten så att andra konkurrerande mottagare inte kan se det. Låsets varaktighet definieras ursprungligen på kö- eller prenumerationsnivå och kan utökas av klienten som äger låset via åtgärden RenewMessageLockAsync . Mer information om hur du förnyar lås finns i avsnittet Förnya lås i den här artikeln.

När ett meddelande är låst kan andra klienter som tar emot från samma kö eller prenumeration ta på sig lås och hämta nästa tillgängliga meddelanden som inte är under aktivt lås. När låset på ett meddelande uttryckligen släpps eller när låset upphör att gälla placeras meddelandet på eller nära framsidan av hämtningsordningen för omleverans.

När meddelandet släpps upprepade gånger av mottagare eller om de låter låset förflutit under ett definierat antal gånger (max leveransantal) tas meddelandet automatiskt bort från kön eller prenumerationen och placeras i den associerade kön med obeställbara meddelanden.

Den mottagande klienten initierar kvittningen av ett mottaget meddelande med en positiv bekräftelse när den anropar det fullständiga API:et för meddelandet. Det anger för asynkron meddelandekö att meddelandet har bearbetats och att meddelandet tas bort från kön eller prenumerationen. Mäklaren svarar på mottagarens kvittningsavsikt med ett svar som anger om likviden kunde utföras.

När den mottagande klienten inte kan bearbeta ett meddelande, men vill att meddelandet ska levereras igen, kan den uttryckligen be om att meddelandet släpps och låsas upp omedelbart genom att anropa Abandon API för meddelandet, eller så kan det inte göra någonting och låta låset förfluta.

Om en mottagande klient inte kan bearbeta ett meddelande och vet att det inte hjälper att leverera meddelandet och försöka utföra åtgärden igen, kan det avvisa meddelandet, vilket flyttar det till kön med obeställbara meddelanden genom att anropa DeadLetter-API :et för meddelandet, vilket också gör det möjligt att ange en anpassad egenskap, inklusive en orsakskod som kan hämtas med meddelandet från kön med obeställbara meddelanden.

Kommentar

En underfråga med obeställbara bokstäver finns bara för en kö eller en ämnesprenumeration när du har funktionen för obeställbara meddelanden aktiverad för kön eller prenumerationen.

Ett specialfall av bosättningen är uppskjutet, som diskuteras i en separat artikel.

Åtgärderna Complete, DeadLettereller RenewLock kan misslyckas på grund av nätverksproblem, om det låsta låset har upphört att gälla eller om det finns andra villkor på tjänstsidan som förhindrar avveckling. I ett av de senare fallen skickar tjänsten en negativ bekräftelse som visas som ett undantag i API-klienterna. Om orsaken är en trasig nätverksanslutning tas låset bort eftersom Service Bus inte stöder återställning av befintliga AMQP-länkar på en annan anslutning.

Om Complete det misslyckas, vilket vanligtvis inträffar i slutet av meddelandehanteringen och i vissa fall efter minuter av bearbetningsarbete, kan det mottagande programmet bestämma om det ska bevara arbetets tillstånd och ignorera samma meddelande när det levereras en andra gång, eller om det ska släcka arbetsresultatet och försöka igen när meddelandet skickas igen.

Den typiska mekanismen för att identifiera duplicerade meddelandeleveranser är genom att kontrollera meddelande-ID: t, som kan och bör anges av avsändaren till ett unikt värde, eventuellt justerat med en identifierare från ursprungsprocessen. En jobbschemaläggare skulle förmodligen ange meddelande-ID till identifieraren för det jobb som den försöker tilldela till en arbetare med den angivna arbetaren, och arbetaren skulle ignorera den andra förekomsten av jobbtilldelningen om jobbet redan är klart.

Viktigt!

Det är viktigt att observera att låset som PeekLock eller SessionLock hämtar på meddelandet är flyktigt och kan gå förlorat under följande villkor

  • Tjänstuppdatering
  • OS-uppdatering
  • Ändra egenskaper för entiteten (kö, ämne, prenumeration) medan låset hålls.

När låset går förlorat genererar Azure Service Bus en MessageLockLostException eller SessionLockLostException som visas i klientprogrammet. I så fall bör klientens standardlogik för omförsök automatiskt sätta igång och försöka utföra åtgärden på nytt.

Förnya lås

Standardvärdet för låsvaraktigheten är 1 minut. Du kan ange ett annat värde för låsets varaktighet på kö- eller prenumerationsnivå. Klienten som äger låset kan förnya meddelandelåset med hjälp av metoder för mottagarobjektet. I stället kan du använda funktionen för automatisk låsförnyelse där du kan ange hur lång tid du vill fortsätta att få låset förnyat.

Det är bäst att ange låsvaraktigheten till något högre än den normala bearbetningstiden, så att du inte behöver förnya låset. Det maximala värdet är 5 minuter, så du måste förnya låset om du vill ha det längre. Att ha en längre låsvaraktighet än vad som behövs har också vissa konsekvenser. När klienten till exempel slutar fungera blir meddelandet bara tillgängligt igen när låsets varaktighet har passerat.

Nästa steg