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

Den centrala funktionen för en a broker för meddelanden, till exempel Service Bus att acceptera meddelanden i en kö eller ett ämne och hålla dem tillgängliga för senare hämtning. Skicka är den term som ofta används för överföring av ett meddelande till meddelandekoordinatorn. Mottagning ä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 har överförts korrekt till och godkänts av den a broker eller om någon typ av fel har uppstått. Den här positiva eller negativa bekräftelsen avgör förståelsen för både klienten och den a broker om överföringstillståndet för meddelandet. Därför kallas det för en likvid .

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

Setling send operations (Sätt skicka åtgärder)

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

Om meddelandet avvisas av Service Bus innehåller avvisningen en felindikator och text med ett spårnings-ID i det. Avvisningen innehåller också information om huruvida åtgärden kan göras om med en förväntad lyckad åtgärd. I klienten omvandlas den här informationen till ett undantag och aktiveras till anroparen av skicka-åtgärden. Om meddelandet har godkänts slutförs åtgärden tyst.

När du använder AMQP-protokollet, som är det exklusiva protokollet för klienterna .NET Standard, Java, JavaScript, Python och Go och ett alternativ för .NET Framework-klienten, pipelines för meddelandeöverföringar och likvider. Vi rekommenderar att du använder API-varianterna för den asynkrona programmeringsmodellen.

En avsändare kan placera flera meddelanden i snabb följd utan att behöva vänta på att varje meddelande bekräftas, vilket annars skulle vara fallet med SBMP-protokollet eller med HTTP 1.1. De asynkrona sändåtgärderna slutförs när respektive meddelanden accepteras och lagras, på partitionerade entiteter eller när skicka-åtgärden till olika entiteter överlappar. Slutförandet kan också ske utanför den ursprungliga skicka-ordern.

Strategin för hantering av resultatet av skicka-å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-framtider, Java-mono, JavaScript-löften och motsvarande begrepp på andra språk.

Om programmet genererar stora mängd meddelanden, vilket illustreras här med en oformaterad loop, och väntar på slutförandet av varje sändningsåtgärd innan nästa meddelande skickas, så slutförs endast 10 sekventiella fullständiga turer fram och tillbaka för likvidning.

Med ett förmodat 70 millisekunders TCP-svarstidsavstånd för tur och retur från en lokal plats till Service Bus och bara ger 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 överbelastningseffekter av vägen:

for (int i = 0; i < 100; i++)
{
  // creating the message omitted for brevity
  await client.SendAsync(…);
}

Om programmet startar de 10 asynkrona sändåtgärderna i omedelbar följd och väntar på att slutföras separat överlappar tur och retur-tiden för de 10 skickande åtgärderna. De 10 meddelandena överförs i omedelbar följd, eventuellt även delning av TCP-bildrutor, och den totala överföringstiden beror till stor del på den nätverksrelaterade tid det tar att överföra meddelandena till den a broker.

Genom att göra samma antaganden som för den tidigare loopen kan den totala överlappande körningstiden för följande loop hålla sig väl under en sekund:

var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
  tasks.Add(client.SendAsync(…));
}
await Task.WhenAll(tasks);

Det är viktigt att observera att alla asynkrona programmeringsmodeller använder någon form av minnesbaserad, dold arbetskö som innehåller väntande åtgärder. När API:et för att skicka returneras köas skicka-uppgiften i den arbetskön, men protokollgesten börjar först när det är aktivitetens tur att köras. För kod som tenderar att skicka burst-meddelanden och där tillförlitlighet är ett problem bör du vara försiktig så att inte för många meddelanden läggs "i gång" samtidigt, eftersom alla skickade meddelanden tar upp minne tills de faktiskt har lagts till i kabeln.

Semaforer, som du ser i följande kodfragment i C#, är synkroniseringsobjekt som möjliggör sådan begränsning på programnivå vid behov. Den här användningen av en semaphore gör att högst 10 meddelanden kan skickas samtidigt. Ett av de 10 tillgängliga semaphore-låsen tas före skicka och släpps när skicka slutförs. Den 11:e passerar genom loopen väntar tills minst en av de tidigare skickar 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 < 100; i++)
{
  await semaphore.WaitAsync();

  tasks.Add(client.SendAsync(…).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

Program bör aldrig initiera en asynkron send-åtgärd på ett "fire and forget"-sätt utan att hämta resultatet av åtgärden. På så sätt kan den interna och osynliga uppgiftskön läsas in upp till minnesbelastning och förhindra att programmet identifierar skicka fel:

for (int i = 0; i < 100; i++)
{

  client.SendAsync(message); // DON’T DO THIS
}

Med en AMQP-klient på låg nivå Service Bus också "förreglerade" överföringar. En förbestämd överföring är en fire-and-forget-åtgärd för vilken resultatet, oavsett hur det går, inte rapporteras tillbaka till klienten och meddelandet anses vara avvägt när det skickas. Bristen på feedback till klienten innebär också att det inte finns några tillgängliga användbara data för diagnostik, vilket innebär att det här läget inte är kvalificerat för hjälp via Azure-supporten.

Reglera mottagningsåtgärder

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

ReceiveAndDelete

Läget för att ta emot och ta bort talar om för den autjämnaren att alla meddelanden som skickas till den mottagande klienten ska övervägas när de skickas. Det innebär att meddelandet anses förbrukat så snart den a broker har lagt det på kabeln. 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 för meddelandet och inte heller saktas ned genom att vänta på resultatet av likvidresultatet. Om de data som finns i de enskilda meddelandena har ett 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 a broker 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 inledningsvis på kö- eller prenumerationsnivå och kan utökas av klienten som äger låset. 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 få 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, visas meddelandet igen vid eller nära framsidan av hämtningsordningen för återleverans.

När meddelandet släpps upprepade gånger av mottagare eller om de låter låset förflyta under ett definierat antal gånger (Maximaltantal leveranser) tas meddelandet automatiskt bort från kön eller prenumerationen och placeras i den associerade kön för döda meddelanden.

Den mottagande klienten initierar likvid av ett mottaget meddelande med en positiv bekräftelse när den anropar Complete API:et för meddelandet. Det indikerar för den a broker att meddelandet har bearbetats och att meddelandet tas bort från kön eller prenumerationen. Koordinatorn svarar på mottagarens likvidavsikt med ett svar som anger om likviden kan utföras.

Om den mottagande klienten inte kan bearbeta ett meddelande men vill att meddelandet ska levereras igen kan den uttryckligen be om att meddelandet ska släppas och låsas upp direkt genom att API:et anropas för meddelandet, eller så kan den inte göra någonting och låta låset gå Abandon ut.

Om en mottagande klient inte kan bearbeta ett meddelande och vet att det inte hjälper att återskapa meddelandet och försöka igen, kan det avvisa meddelandet, vilket flyttar det till kön för obeställbara meddelanden genom att anropa 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 DeadLetter meddelanden.

Ett särskilt fall av likvid är upp skjuta upp, vilket beskrivs i en separat artikel.

Åtgärderna , eller 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 CompleteDeadletter som förhindrar RenewLock likvidning. I ett av de senare fallen skickar tjänsten en negativ bekräftelse som visar sig som ett undantag i API-klienterna. Om orsaken är en bruten nätverksanslutning tas låset bort eftersom Service Bus inte stöder återställning av befintliga AMQP-länkar på en annan anslutning.

Om misslyckas, vilket vanligtvis inträffar i slutet av meddelandehanteringen och i vissa fall efter några minuters bearbetning, kan det mottagande programmet bestämma om det bevarar arbetets tillstånd och ignorerar samma meddelande när det levereras en andra gång, eller om det tar bort arbetsresultatet och försöker igen när meddelandet Complete levereras igen.

Den typiska mekanismen för att identifiera duplicerade meddelandeleveranser är att kontrollera meddelande-ID:t, som kan och ska anges av avsändaren till ett unikt värde, eventuellt justerat med en identifierare från den ursprungliga processen. En jobbschema skulle förmodligen ange meddelande-ID:t till identifieraren för jobbet som det försöker tilldela till en arbetsroll med den angivna arbetsrollen, och arbetaren ignorerar den andra förekomsten av jobbtilldelningen om jobbet redan är klart.

Viktigt

Det är viktigt att notera att låset som PeekLock hämtar i meddelandet är beständigt och kan gå förlorat under följande förhållanden

  • Tjänstuppdatering
  • OS-uppdatering
  • Ändra egenskaper för entiteten (Kö, Ämne, Prenumeration) medan låset är låst.

När låset går förlorat genererar Azure Service Bus en LockLostException som visas i klientprogramkoden. I det här fallet ska klientens standardlogik för omförsök automatiskt starta och försöka igen.

Förnya lås

Standardvärdet för låsvaraktigheten är 30 sekunder. Du kan ange ett annat värde för låsvaraktigheten på kö- eller prenumerationsnivå. Klienten som äger låset kan förnya meddelandelåset med hjälp av metoder på mottagarobjektet. I stället kan du använda funktionen för automatisk låsförnyelse där du kan ange hur länge du vill att låset ska förnyas.

Nästa steg