Partitionerade köer och ämnen

Azure Service Bus använder flera asynkrona 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 över 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 ett meddelandearkiv. Dessutom gör ett tillfälligt avbrott i ett meddelandearkiv inte en partitionerad kö eller ett ämne otillgängligt. Partitionerade köer och ämnen kan innehålla alla avancerade Service Bus-funktioner, till exempel stöd för transaktioner och sessioner.

Anteckning

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

  • Partitionering är tillgängligt när entiteten 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 Premium-meddelande-SKU:n, och alla köer och ämnen i det 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 SKU:erna Basic eller Standard skapar vi alltid 16 partitioner.
  • När partitionering är aktiverat i Premium-SKU:n 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 befintligt ä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 det tar emot fler mottagningsbegäranden. En mottagande klient känner inte till partitioneringen. 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 partitionerna vars meddelandekö svarade först. Det finns ingen garanti för att det returnerade meddelandet är det äldsta i alla partitioner.

Det kostar ingenting att skicka ett meddelande till eller ta emot ett meddelande från en partitionerad kö eller ett ämne.

Anteckning

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 inte är tillgänglig för tillfället 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 meddelandekoordinator. Sessioner gör det möjligt för Service Bus att garantera meddelandeordning samt konsekvens för sessionstillstånd.

PartitionKey: Om ett meddelande har partitionsnyckelegenskapen, men inte sessions-ID:t, använder Service Bus partitionsnyckelns egenskapsvärde som partitionsnyckel. Om meddelandet har både sessions-ID och partitionsnyckelns egenskaper inställda måste båda egenskaperna vara identiska. Om partitionsnyckelegenskapen är inställd på ett annat värde än sessions-ID-egenskapen returnerar Service Bus ett ogiltigt åtgärdsfel. Partitionsnyckelegenskapen 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 asynkron 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:t 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 asynkron meddelandekö. Med det här ID:t kan Service Bus identifiera och eliminera dubblettmeddelanden. Om dubblettidentifieringsfunktionen inte är aktiverad anser Service Bus inte att meddelande-ID-egenskapen är en partitionsnyckel.

Inte använda en partitionsnyckel

I avsaknad av en partitionsnyckel distribuerar Service Bus meddelanden med resursallokering till alla partitioner i den partitionerade kön eller ä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 uppnår dock inte den garanterade ordning som en partitionsnyckel tillhandahåller.

En mer ingående diskussion om kompromissen mellan tillgänglighet (ingen partitionsnyckel) och konsekvens (med en partitionsnyckel) finns i Tillgänglighet och konsekvens i Event Hubs. Förutom att partitions-ID:t 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. Om det inte finns någon 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 det 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. Ett 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 sessions-ID-egenskapen anges för meddelandet. 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. Vid försök returnerar Service Bus ett ogiltigt åtgärdsfel. Ett 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 minskas. På det hela taget är konsekvensen fortfarande mycket högre än icke-partitionerade 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, till exempel antal meddelanden, aggregeras från alla partitioner. Om en partition inte är felfri rapporteras statusen för entitetens tillgänglighet som begränsad.
  • Meddelandescenarier med låg volym: 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 mottagningsbegäranden utför klientdelen en mottagning på alla partitioner och cachelagrar alla mottagna svar. En efterföljande mottagningsbegäran för samma anslutning skulle ha nytta av den här cachelagringen och svarstiderna blir 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 lågvolymscenarier 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 alla 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 i ett visst antal meddelanden bör det anropa granskningsåtgärden upprepade gånger tills det får 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 tillämpar Service Bus följande begränsningar för partitionerade köer och ämnen:

  • Partitionerade köer och ämnen har inte stöd för 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 Basic- och Standard-SKU:n. 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 Portal, PowerShell, CLI, Resource Manager mall, .NET, Java, Python och JavaScript. Mer information finns i Aktivera partitionering (Basic/Standard).

Läs om huvudbegreppen i meddelandespecifikationen för AMQP 1.0 i protokollguiden för AMQP 1.0.