Partitionerade köer och ämnen

Azure Service Bus använder flera meddelandeköer för att bearbeta meddelanden och flera meddelandearkiv för att lagra meddelanden. En konventionell kö eller ett ämne hanteras av en enda meddelandekö och lagras i ett meddelandearkiv. Med Service Bus-partitioner kan köer och ämnen, eller meddelandeentiteter, partitioneras mellan flera meddelandeköer och meddelandearkiv. Partitionering innebär att det totala dataflödet för en partitionerad entitet inte längre begränsas av prestanda för en enda meddelandekö eller meddelandearkiv. Dessutom renderar ett tillfälligt avbrott i ett meddelandearkiv inte en partitionerad kö eller ett ämne som inte är tillgängligt. Partitionerade köer och ämnen kan innehålla alla avancerade Service Bus-funktioner, till exempel stöd för transaktioner och sessioner.

Kommentar

Det finns vissa skillnader mellan SKU:n Basic/Standard och Premium när det gäller partitionering.

  • Partitionering är tillgängligt när entitet skapas för alla köer och ämnen i Basic- eller Standard-SKU:er. Ett namnområde kan ha både partitionerade och icke-partitionerade entiteter.
  • Partitionering är tillgängligt när namnområdet skapas för SKU:n för Premium-meddelanden, och alla köer och ämnen i namnområdet partitioneras. Alla tidigare migrerade partitionerade entiteter i Premium-namnområden fortsätter att fungera som förväntat.
  • När partitionering är aktiverat i Basic- eller Standard-SKU:er skapar vi alltid 16 partitioner.
  • När partitionering är aktiverat i Premium SKU anges mängden partitioner när namnområdet skapas.

Det går inte att ändra partitioneringsalternativet i ett befintligt namnområde, en kö eller ett ämne. du kan bara ange alternativet när du skapar entiteten.

Så här fungerar det

Varje partitionerad kö eller ämne består av flera partitioner. Varje partition lagras i ett annat meddelandearkiv och hanteras av en annan meddelandekö. När ett meddelande skickas till en partitionerad kö eller ett ämne tilldelar Service Bus meddelandet till en av partitionerna. Valet görs slumpmässigt av Service Bus eller med hjälp av en partitionsnyckel som avsändaren kan ange.

När en klient vill ta emot ett meddelande från en partitionerad kö, eller från en prenumeration till ett partitionerat ämne, frågar Service Bus alla partitioner efter meddelanden och returnerar sedan det första meddelandet som hämtas från något av meddelandearkiven till mottagaren. Service Bus cachelagrar de andra meddelandena och returnerar dem när de tar emot fler mottagningsbegäranden. En mottagande klient känner inte till partitioneringen. det klientinriktade beteendet för en partitionerad kö eller ett ämne (till exempel läsa, slutföra, skjuta upp, deadletter, prefetching) är identiskt med beteendet för en vanlig entitet.

Granskningsåtgärden på en icke-partitionerad entitet returnerar alltid det äldsta meddelandet, men inte på en partitionerad entitet. I stället returneras det äldsta meddelandet i en av de partitioner vars meddelandekö svarade först. Det finns ingen garanti för att det returnerade meddelandet är det äldsta i alla partitioner.

Det kostar inget extra när du skickar ett meddelande till eller tar emot ett meddelande från en partitionerad kö eller ett ämne.

Kommentar

Granskningsåtgärden returnerar det äldsta meddelandet från partitionen baserat på dess sekvensnummer. För partitionerade entiteter utfärdas sekvensnumret i förhållande till partitionen. Mer information finns i Meddelandesekvensering och tidsstämplar.

Användning av partitionsnycklar

När ett meddelande placeras i en partitionerad kö eller ett ämne söker Service Bus efter förekomsten av en partitionsnyckel. Om den hittar en väljer den partitionen baserat på den nyckeln. Om den inte hittar någon partitionsnyckel väljer den partitionen baserat på en intern algoritm.

Använda en partitionsnyckel

Vissa scenarier, till exempel sessioner eller transaktioner, kräver att meddelanden lagras i en specifik partition. Alla dessa scenarier kräver användning av en partitionsnyckel. Alla meddelanden som använder samma partitionsnyckel tilldelas till samma partition. Om partitionen är tillfälligt otillgänglig returnerar Service Bus ett fel.

Beroende på scenariot används olika meddelandeegenskaper som en partitionsnyckel:

SessionId: Om ett meddelande har angett sessions-ID-egenskapen använder Service Bus den som partitionsnyckel. På så sätt hanteras alla meddelanden som tillhör samma session av samma meddelandekö. Sessioner gör det möjligt för Service Bus att garantera meddelandeordning samt konsekvensen i sessionstillstånd.

PartitionKey: Om ett meddelande har egenskapen partitionsnyckel, men inte sessions-ID-egenskapen, använder Service Bus egenskapsvärdet för partitionsnyckeln som partitionsnyckel. Om meddelandet har både sessions-ID:t och partitionsnyckelns egenskaper inställda måste båda egenskaperna vara identiska. Om egenskapen partitionsnyckel är inställd på ett annat värde än sessions-ID-egenskapen returnerar Service Bus ett ogiltigt åtgärdsfel. Egenskapen partitionsnyckel ska användas om en avsändare skickar icke-sessionsmedvetna transaktionsmeddelanden. Partitionsnyckeln säkerställer att alla meddelanden som skickas i en transaktion hanteras av samma meddelandekö.

MessageId: Om kön eller ämnet skapades med dubblettidentifieringsfunktionen och sessions-ID:t eller partitionsnyckelegenskaperna inte har angetts, fungerar egenskapsvärdet för meddelande-ID som partitionsnyckel. (Microsoft-klientbiblioteken tilldelar automatiskt ett meddelande-ID om det sändande programmet inte gör det.) I det här fallet hanteras alla kopior av samma meddelande av samma meddelandekö. Med det här ID:t kan Service Bus identifiera och eliminera dubblettmeddelanden. Om dubblettidentifieringsfunktionen inte är aktiverad betraktar Service Bus inte meddelande-ID-egenskapen som en partitionsnyckel.

Använder inte en partitionsnyckel

I avsaknad av en partitionsnyckel distribuerar Service Bus meddelanden på ett resursallokeringssätt till alla partitioner i den partitionerade kön eller det partitionerade ämnet. Om den valda partitionen inte är tillgänglig tilldelar Service Bus meddelandet till en annan partition. På så sätt lyckas sändningsåtgärden trots att ett meddelandearkiv tillfälligt inte är tillgängligt. Du kommer dock inte att uppnå den garanterade ordning som en partitionsnyckel tillhandahåller.

En mer ingående diskussion om kompromissen mellan tillgänglighet (ingen partitionsnyckel) och konsekvens (med hjälp av en partitionsnyckel) finns i Tillgänglighet och konsekvens i Event Hubs. Förutom att partitions-ID inte exponeras för användare gäller den här informationen lika för partitionerade Service Bus-entiteter.

Om du vill ge Service Bus tillräckligt med tid för att skicka meddelandet till en annan partition måste tidsgränsvärdet som anges av klienten som skickar meddelandet vara större än 15 sekunder. Standardvärdet på 60 sekunder rekommenderas.

En partitionsnyckel "fäster" ett meddelande till en specifik partition. Om meddelandearkivet som innehåller den här partitionen inte är tillgängligt returnerar Service Bus ett fel. I avsaknad av en partitionsnyckel kan Service Bus välja en annan partition och åtgärden lyckas. Därför rekommenderar vi att du inte anger en partitionsnyckel om den inte krävs.

Avancerade ämnen

Använda transaktioner med partitionerade entiteter

Meddelanden som skickas som del i en transaktion måste ange en partitionsnyckel. Nyckeln kan vara en av följande egenskaper: sessions-ID, partitionsnyckel eller meddelande-ID. Alla meddelanden som skickas som en del av samma transaktion måste ange samma partitionsnyckel. Om du försöker skicka ett meddelande utan en partitionsnyckel i en transaktion returnerar Service Bus ett ogiltigt åtgärdsfel. Om du försöker skicka flera meddelanden inom samma transaktion som har olika partitionsnycklar returnerar Service Bus ett ogiltigt åtgärdsfel. Till exempel:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.PartitionKey = "myPartitionKey";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

Om någon av de egenskaper som fungerar som en partitionsnyckel har angetts fäster Service Bus meddelandet på en specifik partition. Det här beteendet inträffar oavsett om en transaktion används eller inte. Vi rekommenderar att du inte anger en partitionsnyckel om det inte behövs.

Använda transaktioner i sessioner med partitionerade entiteter

Om du vill skicka ett transaktionsmeddelande till ett sessionsmedveten ämne eller kö måste meddelandet ha sessions-ID-egenskapen inställd. Om partitionsnyckelegenskapen också anges måste den vara identisk med sessions-ID-egenskapen. Om de skiljer sig returnerar Service Bus ett ogiltigt åtgärdsfel.

Till skillnad från vanliga (icke-partitionerade) köer eller ämnen går det inte att använda en enda transaktion för att skicka flera meddelanden till olika sessioner. Om ett försök görs returnerar Service Bus ett ogiltigt åtgärdsfel. Till exempel:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.SessionId = "mySession";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

Automatisk vidarebefordran av meddelanden med partitionerade entiteter

Service Bus stöder automatisk vidarebefordran av meddelanden från, till eller mellan partitionerade entiteter. Du kan aktivera den här funktionen när du skapar eller uppdaterar köer och prenumerationer. Mer information finns i Aktivera vidarebefordran av meddelanden. Om meddelandet anger en partitionsnyckel (sessions-ID, partitionsnyckel eller meddelande-ID) används partitionsnyckeln för målentiteten.

Överväganden och riktlinjer

  • Funktioner med hög konsekvens: Om en entitet använder funktioner som sessioner, dubblettidentifiering eller explicit kontroll över partitioneringsnyckeln dirigeras meddelandeåtgärderna alltid till en specifik partition. Om någon av partitionerna upplever hög trafik eller om det underliggande arkivet är felfritt, misslyckas dessa åtgärder och tillgängligheten minskar. På det hela taget är konsekvensen fortfarande mycket högre än icke-partiska entiteter. endast en delmängd av trafiken har problem, till skillnad från all trafik. Mer information finns i den här diskussionen om tillgänglighet och konsekvens.
  • Hantering: Åtgärder som Skapa, Uppdatera och Ta bort måste utföras på alla partitioner i entiteten. Om en partition inte är felfri kan det leda till fel för dessa åtgärder. För åtgärden Hämta måste information som antal meddelanden aggregeras från alla partitioner. Om en partition inte är felfri rapporteras statusen för entitetstillgänglighet som begränsad.
  • Scenarier med låg volymmeddelande: För sådana scenarier, särskilt när du använder HTTP-protokollet, kan du behöva utföra flera mottagningsåtgärder för att få alla meddelanden. För att ta emot begäranden utför klientdelen en mottagning på alla partitioner och cachelagrar alla mottagna svar. En efterföljande mottagningsbegäran för samma anslutning skulle dra nytta av den här cachelagringen och svarstiderna är lägre. Men om du har flera anslutningar eller använder HTTP upprättas en ny anslutning för varje begäran. Därför finns det ingen garanti för att den hamnar på samma nod. Om alla befintliga meddelanden är låsta och cachelagrade i en annan klientdel returnerar mottagningsåtgärden null. Meddelanden upphör så småningom att gälla och du kan ta emot dem igen. HTTP keep-alive rekommenderas. När du använder partitionering i scenarier med låg volym kan det ta längre tid än förväntat att ta emot åtgärder. Därför rekommenderar vi att du inte använder partitionering i dessa scenarier. Ta bort befintliga partitionerade entiteter och återskapa dem med partitionering inaktiverat för att förbättra prestanda.
  • Bläddra/granska meddelanden: Granskningsåtgärden returnerar inte alltid det antal meddelanden som efterfrågas. Det finns två vanliga orsaker till det här beteendet. En orsak är att den aggregerade storleken på samlingen med meddelanden överskrider den maximala storleken. En annan orsak är att en partition i partitionerade köer eller ämnen kanske inte har tillräckligt med meddelanden för att returnera det begärda antalet meddelanden. Om ett program i allmänhet vill granska/bläddra bland ett visst antal meddelanden bör det anropa granskningsåtgärden upprepade gånger tills det hämtar det antalet meddelanden, eller så finns det inga fler meddelanden att granska. Mer information, inklusive kodexempel, finns i Meddelandebläddring.

Begränsningar för partitionerade entiteter

För närvarande medför Service Bus följande begränsningar för partitionerade köer och ämnen:

  • För partitionerade premiumnamnområden är meddelandestorleken begränsad till 1 MB när meddelandena skickas individuellt och batchstorleken är begränsad till 1 MB när meddelandena skickas i en batch.
  • Partitionerade köer och ämnen stöder inte att skicka meddelanden som tillhör olika sessioner i en enda transaktion.
  • Service Bus tillåter för närvarande upp till 100 partitionerade köer eller ämnen per namnområde för SKU:n Basic och Standard. Varje partitionerad kö eller ämne räknas mot kvoten på 10 000 entiteter per namnområde.

Nästa steg

Du kan aktivera partitionering med hjälp av Azure-portalen, PowerShell, CLI, Resource Manager-mallen, .NET, Java, Python och JavaScript. Mer information finns i Aktivera partitionering (Basic/Standard).

Läs mer om huvudbegreppen i meddelandespecifikationen advanced message queueing protocol (AMQP) 1.0 i protokollguiden för AMQP 1.0.