Dela via


Felsöka Azure Service Bus

Den här artikeln beskriver metoder för felundersökning, samtidighet, vanliga fel för autentiseringstyperna i Azure Service Bus Java-klientbiblioteket och åtgärdssteg för att lösa dessa fel.

Aktivera och konfigurera loggning

Azure SDK för Java erbjuder en konsekvent loggningshistoria som hjälper dig att felsöka programfel och för att påskynda lösningen. De loggar som produceras fångar upp flödet för en applikation innan det når terminaltillståndet för att hjälpa till att lokalisera rotproblemet. Vägledning om loggning finns i Konfigurera loggning i Azure SDK för Java och Felsökningsöversikt.

Förutom att aktivera loggning ger inställningen loggnivån till VERBOSE eller DEBUG insikter om bibliotekets tillstånd. I följande avsnitt visas exempelkonfigurationerna log4j2 och logback för att minska överdrivna meddelanden när utförlig loggning är aktiverad.

Konfigurera Log4J 2

Använd följande steg för att konfigurera Log4J 2:

  1. Lägg till beroendena i din pom.xml genom att använda dem från loggningsexemplet pom.xmli avsnittet "Beroenden som krävs för Log4j2".
  2. Lägg till log4j2.xml i mappen src/main/resources.

Konfigurera tillbakaloggning

Använd följande steg för att konfigurera tillbakaloggning:

  1. Lägg till beroendena i din pom.xml genom att använda dem från exempel på loggning pom.xmli avsnittet "Beroenden som krävs för logback".
  2. Lägg till logback.xml i mappen src/main/resources.

Aktivera AMQP-transportloggning

Om det inte räcker med att aktivera klientloggning för att diagnostisera dina problem kan du aktivera loggning till en fil i det underliggande AMQP-biblioteket Qpid Proton-J-. Qpid Proton-J använder java.util.logging. Du kan aktivera loggning genom att skapa en konfigurationsfil med innehållet som visas i nästa avsnitt. Du kan också ange proton.trace.level=ALL och vilka konfigurationsalternativ du vill för java.util.logging.Handler implementeringen. Implementeringsklasserna och deras alternativ finns i Package java.util.logging i Java 8 SDK-dokumentationen.

Om du vill spåra AMQP-transportramarna anger du miljövariabeln PN_TRACE_FRM=1.

Exempelfil för logging.properties

Följande konfigurationsfil loggar TRACE-nivåutdata från Proton-J till filen proton-trace.log:

handlers=java.util.logging.FileHandler
.level=OFF
proton.trace.level=ALL
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=proton-trace.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tr] %3$s %4$s: %5$s %n

Minska loggning

Ett sätt att minska loggningen är att ändra verbositeten. Ett annat sätt är att lägga till filter som exkluderar loggar från loggningsnamnspaket som com.azure.messaging.servicebus eller com.azure.core.amqp. Exempel finns i XML-filerna i avsnitten Konfigurera Log4J 2 och Konfigurera loggback.

När du skickar en bugg är loggmeddelandena från klasser i följande paket intressanta:

  • com.azure.core.amqp.implementation
  • com.azure.core.amqp.implementation.handler
    • Undantaget är att du kan ignorera meddelandet onDelivery i ReceiveLinkHandler.
  • com.azure.messaging.servicebus.implementation

Samtidighet i ServiceBusProcessorClient

ServiceBusProcessorClient gör det möjligt för programmet att konfigurera hur många anrop till meddelandehanteraren som ska ske samtidigt. Den här konfigurationen gör det möjligt att bearbeta flera meddelanden parallellt. För en ServiceBusProcessorClient som använder meddelanden från en entitet som inte är en session kan programmet konfigurera önskad samtidighet med hjälp av maxConcurrentCalls-API:et. För en sessionsaktiverad entitet är den önskade samtidigheten maxConcurrentSessions gånger maxConcurrentCalls.

Om programmet observerar färre samtidiga anrop till meddelandehanteraren än den konfigurerade samtidigheten kan det bero på att trådpoolen inte har rätt storlek.

ServiceBusProcessorClient använder daemontrådar från den globala boundedElastic trådpoolen för att anropa meddelandehanteraren. Det maximala antalet samtidiga trådar i den här poolen begränsas av ett tak. Som standard är det här taket tio gånger så många tillgängliga CPU-kärnor. För att ServiceBusProcessorClient effektivt ska kunna stödja programmets önskade samtidighet (maxConcurrentCalls eller maxConcurrentSessions gånger maxConcurrentCalls) måste du ha ett boundedElastic pooltaksvärde som är högre än den önskade samtidigheten. Du kan åsidosätta standardtaket genom att ange systemegenskapen reactor.schedulers.defaultBoundedElasticSize.

Du bör justera trådpoolen och CPU-allokeringen från fall till fall. Men när du åsidosätter pooltaket begränsar du som utgångspunkt de samtidiga trådarna till cirka 20–30 per CPU-kärna. Vi rekommenderar att du anger en gräns för önskad samtidighet per ServiceBusProcessorClient instans till cirka 20–30. Profilera och mät ditt specifika användningsfall och justera samtidighetsaspekterna i enlighet med detta. För scenarier med hög belastning bör du överväga att köra flera ServiceBusProcessorClient instanser där varje instans skapas från en ny ServiceBusClientBuilder instans. Överväg också att köra varje ServiceBusProcessorClient på en dedikerad värd , till exempel en container eller virtuell dator, så att driftstopp i en värd inte påverkar den övergripande meddelandebearbetningen.

Tänk på att det skulle få negativa effekter att ange ett högt värde för pooltaket på en värd med få CPU-kärnor. Vissa tecken på låg CPU-resurser eller en pool med för många trådar på färre processorer är: frekventa timeouter, förlorade lås, dödläge eller lägre dataflöde. Om du kör Java-programmet på en container rekommenderar vi att du använder två eller flera vCPU-kärnor. Vi rekommenderar inte att du väljer något mindre än 1 vCPU-kärna när du kör Java-program i containerbaserade miljöer. Detaljerade rekommendationer om resurstilldelning finns i Containerize your Java applications.

Flaskhals för anslutningsdelning

Alla klienter som skapats från en delad ServiceBusClientBuilder instans delar samma anslutning till Service Bus-namnområdet.

Att använda en delad anslutning möjliggör multiplexeringsåtgärder mellan klienter på en anslutning, men delning kan också bli en flaskhals om det finns många klienter, eller om klienterna tillsammans genererar hög belastning. Varje anslutning har en I/O-tråd associerad med den. Vid delning av en anslutning lägger klienterna sitt arbete i den delade I/O-trådens arbetskö, och varje klients framsteg beror på hur snabbt arbetet i kön slutförs. I/O-tråden hanterar det kodade arbetet seriellt. Om arbetskön för I/O-tråden i en delad anslutning slutar med mycket arbete som väntar på att bli hanterat, liknar symtomen på lågt CPU-utnyttjande. Det här villkoret beskrivs i föregående avsnitt om samtidighet – till exempel klienter som stannar upp, tidsgräns, förlorat lås eller långsammare återställningssökväg.

Service Bus SDK använder reactor-executor-* namnmönster för anslutnings-I/O-tråden. När programmet upplever flaskhalsen för delad anslutning kan det återspeglas i I/O-trådens CPU-användning. Dessutom, i heapdumpet eller i det levande minnet är objektet ReactorDispatcher$workQueue arbetskön för I/O-tråden. En lång arbetskö i minnesögonblicksbilden under flaskhalsperioden kan tyda på att den delade I/O-tråden är överbelastad med väntande arbeten.

Om programinläsningen till en Service Bus-slutpunkt är relativt hög när det gäller totalt antal mottagna meddelanden eller nyttolaststorlek bör du därför använda en separat builder-instans för varje klient som du skapar. För varje entitet – kö eller ämne – kan du till exempel skapa en ny ServiceBusClientBuilder och skapa en klient från den. Vid extremt hög belastning på en viss entitet kanske du antingen vill skapa flera klientinstanser för den entiteten eller köra klienter på flera värdar , till exempel containrar eller virtuella datorer, för att belastningsutjämning.

Klienter får stopp vid användning av en anpassad slutpunkt för Application Gateway

Den anpassade slutpunktsadressen refererar till en HTTPS-slutpunktsadress som tillhandahålls av programmet och som kan matchas med Service Bus eller konfigureras för att dirigera trafik till Service Bus. Azure Application Gateway gör det enkelt att skapa en HTTPS-klientdel som vidarebefordrar trafik till Service Bus. Du kan konfigurera Service Bus SDK för ett program att använda en Application Gateway-klientdels-IP-adress som anpassad slutpunkt för att ansluta till Service Bus.

Application Gateway erbjuder flera säkerhetsprinciper som stöder olika TLS-protokollversioner. Det finns fördefinierade principer som framtvingar TLSv1.2 som lägsta version. Det finns också gamla principer med TLSv1.0 som lägsta version. HTTPS-klientdelen har en TLS-princip tillämpad.

Just nu känner Service Bus SDK inte igen vissa TCP-fjärravslut av Application Gateway-klientdelen, som använder TLSv1.0 som lägsta version. Om klientdelen till exempel skickar TCP FIN, ACK-paket för att stänga anslutningen när dess egenskaper uppdateras, kan SDK:t inte identifiera den, så den återansluts inte och klienter kan inte skicka eller ta emot meddelanden längre. Ett sådant stopp sker bara när du använder TLSv1.0 som lägsta version. Du kan minska problemet genom att använda en säkerhetsprincip med TLSv1.2 eller senare som lägsta version för Application Gateway-klientdelen.

Stödet för TLSv1.0 och 1.1 för alla Azure-tjänster har redan upphör den 31 oktober 2024, så övergången till TLSv1.2 rekommenderas starkt.

Meddelande- eller sessionslåset går förlorat

En Service Bus-kö eller ämnesprenumeration har en låsvaraktighet som är inställd på resursnivå. När mottagarklienten hämtar ett meddelande från resursen tillämpar Service Bus-koordinatorn ett första lås på meddelandet. Det initiala låset varar under den låsvaraktighet som angetts på resursnivå. Om meddelandelåset inte förnyas innan det upphör att gälla släpper Service Bus-koordinatorn meddelandet för att göra det tillgängligt för andra mottagare. Om programmet försöker slutföra eller avbryta ett meddelande efter att låset upphört att gälla misslyckas API-anropet med felet com.azure.messaging.servicebus.ServiceBusException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue.

Service Bus-klienten har stöd för att köra en förnyelseaktivitet för bakgrundslås som förnyar meddelandelåset kontinuerligt varje gång innan det upphör att gälla. Som standard körs uppgiften för låsförnyelse i 5 minuter. Du kan justera låsets förnyelsetid med hjälp av ServiceBusReceiverClientBuilder.maxAutoLockRenewDuration(Duration). Om du skickar Duration.ZERO-värdet inaktiveras låsförnyingsaktiviteten.

De följande listorna beskriver några av de användningsmönster eller värdmiljöer som kan leda till låsförlustfelet:

  • Aktiviteten för att förnya låset är inaktiverad och programmets meddelandebearbetningstid överskrider den låsvaraktighet som angetts på resursnivå.

  • Applikationens meddelandebearbetningstid överskrider den konfigurerade varaktigheten för låsförnyelseuppgiften. Observera att om inte varaktigheten för låsförnyelse uttryckligen anges, är standardvärdet 5 minuter.

  • Programmet har aktiverat funktionen Prefetch genom att ange prefetch-värdet till ett positivt heltal med hjälp av ServiceBusReceiverClientBuilder.prefetchCount(prefetch). När prefetch-funktionen är aktiverad hämtar klienten antalet meddelanden som är lika med prefetchen från Service Bus-entiteten – kö eller ämne – och lagrar dem i minnesintern prefetch-bufferten. Meddelandena finns kvar i prefetch-bufferten tills de tas emot i programmet. Klienten utökar inte låset för meddelandena medan de är i prefetch-bufferten. Om programbearbetningen tar så lång tid att meddelandelåset upphör att gälla medan det finns kvar i prefetch-bufferten kan programmet hämta meddelandena med ett utgånget lås. Mer information finns i Varför är Prefetch inte standardalternativet?

  • Värdmiljön har tillfälliga nätverksproblem – till exempel tillfälligt nätverksfel eller avbrott – som hindrar låsförnyelseaktiviteten från att förnya låset i tid.

  • Värdmiljön saknar tillräckligt med processorer eller har brist på CPU-cykler tillfälligt som fördröjer låsförnyingsaktiviteten från att köras i tid.

  • Värdsystemtiden är inte korrekt – till exempel är klockan felinställd – vilket fördröjer låsförnyelseuppgiften och hindrar den från att köras enligt schemat.

  • Anslutnings-I/O-tråden är överbelastad, vilket påverkar dess förmåga att förnya lås genom nätverksanrop i tid. Följande två scenarier kan orsaka det här problemet:

    • Programmet kör för många mottagarklienter som delar samma anslutning. Mer information finns i avsnittet Flaskhals för anslutningsdelning.
    • Programmet har konfigurerat ServiceBusReceiverClient.receiveMessages eller ServiceBusProcessorClient att ha stora maxMessages eller maxConcurrentCalls värden. Mer information finns i avsnittet Concurrency i ServiceBusProcessorClient.

Antalet aktiviteter för att förnya lås i klienten är lika med de maxMessages- eller maxConcurrentCalls parametervärden som angetts för ServiceBusProcessorClient eller ServiceBusReceiverClient.receiveMessages. Ett stort antal aktiviteter för att förnya låset som gör flera nätverksanrop kan också ha en negativ effekt vid begränsning av Service Bus-namnområde.

Om värdenheten inte har tillräckligt med resurser kan man fortfarande förlora låset, även om det bara körs några få aktiviteter för att förnya låset. Om du kör Java-programmet på en container rekommenderar vi att du använder två eller flera vCPU-kärnor. Vi rekommenderar inte att du väljer något mindre än 1 vCPU-kärna när du kör Java-program i containerbaserade miljöer. Detaljerade rekommendationer om resurstilldelning finns i Containerize your Java applications.

Samma anmärkningar om lås är också relevanta för en Service Bus-kö eller en ämnesprenumeration som har session aktiverad. När mottagarklienten ansluter till en session i resursen, tillämpar mäklaren ett initialt lås på sessionen. För att behålla låset på sessionen måste klienten fortsätta att förnya sessionslåset innan det går ut. För en sessionsaktiverad resurs flyttas de underliggande partitionerna ibland för att uppnå belastningsutjämning mellan Service Bus-noder, till exempel när nya noder läggs till för att dela belastningen. När det händer kan sessionslås gå förlorade. Om programmet försöker slutföra eller avbryta ett meddelande när sessionslåset har förlorats misslyckas API-anropet med felet com.azure.messaging.servicebus.ServiceBusException: The session lock was lost. Request a new session receiver.

Nästa steg

Om felsökningsguiden i den här artikeln inte hjälper dig att lösa problem när du använder Azure SDK för Java-klientbibliotek rekommenderar vi att du ange ett problem i Azure SDK för Java GitHub-lagringsplatsen.