Problemen met Azure Service Bus oplossen

In dit artikel worden technieken voor foutonderzoek, gelijktijdigheid en veelvoorkomende fouten in de Azure Service Bus Java-clientbibliotheek beschreven. Gebruik deze richtlijnen om hoofdoorzaken te identificeren en risicobeperkingsstappen toe te passen om Azure Service Bus problemen sneller op te lossen.

Logboekregistratie inschakelen en configureren

Azure SDK voor Java biedt een consistente logregistratie om te helpen bij het oplossen van toepassingsfouten en hun oplossing te versnellen. In de logboeken die u maakt, wordt de stroom van een toepassing vastgelegd voordat de terminalstatus wordt bereikt om het hoofdprobleem op te sporen. Zie Logboekregistratie configureren in de Azure SDK voor Java en Overzicht van probleemoplossingvoor hulp bij logboekregistratie.

Naast het inschakelen van logboekregistratie biedt het instellen van het logboekniveau op VERBOSE of DEBUG inzicht in de status van de bibliotheek. In de volgende secties ziet u voorbeeldconfiguraties voor log4j2 en logback om de overmatige berichten te verminderen wanneer uitgebreide logboekregistratie is ingeschakeld.

Log4J 2 configureren

Gebruik de volgende stappen om Log4J 2 te configureren:

  1. Voeg de afhankelijkheden in uw pom.xml toe met behulp van afhankelijkheden uit het logboekregistratievoorbeeld pom.xmlin de sectie 'Afhankelijkheden vereist voor Log4j2'.
  2. Voeg log4j2.xml toe aan je src/main/resources directory.

Logback configureren

Gebruik de volgende stappen om logback te configureren:

  1. Voeg de afhankelijkheden in uw pom.xml toe met behulp van afhankelijkheden uit het voorbeeld van logboekregistratie pom.xmlin de sectie 'Afhankelijkheden vereist voor logback'.
  2. Voeg logback.xml toe aan uw src/main/resources map.

AMQP-transportlogboekregistratie inschakelen

Als het inschakelen van clientlogboekregistratie niet voldoende is om uw problemen vast te stellen, kunt u logboekregistratie inschakelen in een bestand van de onderliggende AMQP-bibliotheek, Qpid Proton-J. Qpid-Proton-J maakt gebruik van java.util.logging. U kunt logboekregistratie inschakelen door een configuratiebestand te maken met de inhoud die wordt weergegeven in de volgende sectie. Of stel proton.trace.level=ALL en de gewenste configuratieopties in voor de java.util.logging.Handler-implementatie. Zie Package java.util.logging in de Java 8 SDK-documentatie voor de implementatieklassen en de bijbehorende opties.

Als u de AMQP-transportframes wilt traceren, stelt u de omgevingsvariabele PN_TRACE_FRM=1 in.

Voorbeeldbestand logging.properties

Het volgende configuratiebestand logt TRACE-niveau uitvoer van Proton-J naar het bestand 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

Logging verminderen

Een manier om logboekregistratie te verminderen, is door de uitgebreidheid te wijzigen. Een andere manier is om filters toe te voegen die logboeken uitsluiten van loggernaampakketten zoals com.azure.messaging.servicebus of com.azure.core.amqp. Zie de XML-bestanden in de secties Configure Log4J 2 en Configure Logback.

Wanneer u een fout verzendt, zijn de logboekberichten van klassen in de volgende pakketten interessant:

  • com.azure.core.amqp.implementation
  • com.azure.core.amqp.implementation.handler
    • De uitzondering is dat u het onDelivery bericht in ReceiveLinkHandlerkunt negeren.
  • com.azure.messaging.servicebus.implementation

Gelijktijdigheid in ServiceBusProcessorClient

ServiceBusProcessorClient hiermee kunt u configureren hoeveel aanroepen naar de berichtenhandler gelijktijdig plaatsvinden. Met deze configuratie kunt u meerdere berichten parallel verwerken. Voor een ServiceBusProcessorClient dat berichten verwerkt van een entiteit zonder sessies, kunt u de gewenste gelijktijdigheid configureren met behulp van de maxConcurrentCalls API. Voor een entiteit met sessieondersteuning is de gewenste gelijktijdigheid maxConcurrentSessions keer maxConcurrentCalls.

Als u minder gelijktijdige aanroepen naar de berichtenhandler ziet dan de geconfigureerde gelijktijdigheid, kan dit komen doordat de threadpool niet op de juiste manier wordt aangepast.

ServiceBusProcessorClient gebruikt daemon-threads uit de globale Reactor-boundedElastic- threadpool om de berichthandler aan te roepen. Het maximum aantal gelijktijdige threads in deze groep wordt beperkt door een limiet. Deze limiet is standaard tien keer het aantal beschikbare CPU-kernen. Opdat ServiceBusProcessorClient de gewenste gelijktijdigheid (maxConcurrentCalls of maxConcurrentSessions keer maxConcurrentCalls) van de toepassing effectief ondersteunt, moet u een limietwaarde voor boundedElastic hebben die hoger is dan de gewenste gelijktijdigheid. U kunt de standaardlimiet overschrijven door de systeemeigenschap in te stellen reactor.schedulers.defaultBoundedElasticSize.

Stem de threadpool en CPU-toewijzing van geval tot geval af. Wanneer u echter de poollimiet overschrijdt, beperk dan als uitgangspunt de gelijktijdige threads tot ongeveer 20-30 per CPU-kern. Beperk het gewenste aantal gelijktijdige verzoeken per ServiceBusProcessorClient-instantie tot ongeveer 20-30. Profileer en meet uw specifieke use case en stem de gelijktijdigheidsaspecten dienovereenkomstig af. Voor scenario's met hoge belasting kunt u meerdere ServiceBusProcessorClient instanties uitvoeren waarbij elk exemplaar is gebouwd op basis van een nieuwe ServiceBusClientBuilder-instantie. Overweeg ook om elke ServiceBusProcessorClient uit te voeren in een toegewezen host, zoals een container of VM, zodat downtime in één host geen invloed heeft op de algehele berichtverwerking.

Houd er rekening mee dat het instellen van een hoge waarde voor de poollimiet op een host met weinig CPU-kernen nadelige gevolgen heeft. Sommige tekenen van lage CPU-resources of een pool met te veel threads op minder CPU's zijn: frequente time-outs, vergrendeling verloren, impasse of lagere doorvoer. Als u de Java-toepassing uitvoert op een container, gebruikt u twee of meer vCPU-kernen. Selecteer niets minder dan 1 vCPU-kern bij het uitvoeren van Java toepassing in containeromgevingen. Zie Containerize uw Java-toepassingenvoor diepgaande aanbevelingen over resourcebeheer.

Knelpunt voor delen van verbinding

Alle clients die u vanuit een gedeeld exemplaar ServiceBusClientBuilder maakt, delen dezelfde verbinding met de Service Bus naamruimte.

Door een gedeelde verbinding te gebruiken, kunnen multiplexingbewerkingen tussen clients op één verbinding worden uitgevoerd, maar delen kan ook een knelpunt worden als er veel clients zijn of de clients samen een hoge belasting genereren. Aan elke verbinding is een I/O-thread gekoppeld. Wanneer u een verbinding deelt, plaatsen de clients hun werk in de werkwachtrij van deze gedeelde I/O-thread en is de voortgang van elke client afhankelijk van de tijdige voltooiing van het werk in de wachtrij. De I/O-thread verwerkt de ingeklokte taken serieel. Dat wil zeggen: als de werkwachtrij van de I/O-thread van een gedeelde verbinding uiteindelijk veel openstaand werk te verwerken krijgt, zijn de symptomen vergelijkbaar met die van laag CPU-gebruik. Deze voorwaarde wordt beschreven in de vorige sectie over gelijktijdigheid, bijvoorbeeld clients die vastlopen, time-outs, verloren vergrendeling of vertraging in herstelpad.

Service Bus SDK maakt gebruik van het reactor-executor-* naamgevingspatroon voor de I/O-thread voor de verbinding. Wanneer de toepassing het knelpunt van de gedeelde verbinding ondervindt, kan dit worden weerspiegeld in het CPU-gebruik van de I/O-thread. Ook is in de heapdump of in het actieve geheugen het object ReactorDispatcher$workQueue de werkwachtrij van de I/O-thread. Een lange werkwachtrij in de momentopname van het geheugen tijdens de knelpuntperiode kan erop wijzen dat de gedeelde I/O-thread overbelast is met in behandeling zijnde werken.

Daarom, als de belasting van een toepassing op een Service Bus-eindpunt redelijk hoog is in termen van het totale aantal verzonden en ontvangen berichten of de payloadgrootte, gebruikt u voor elke client die u maakt een afzonderlijke builderinstantie. Voor elke entiteit, wachtrij of onderwerp, kunt u bijvoorbeeld een nieuwe ServiceBusClientBuilder maken en er een client van bouwen. In het geval van extreem hoge belasting voor een specifieke entiteit, kunt u meerdere clientexemplaren voor die entiteit maken of clients uitvoeren op meerdere hosts, bijvoorbeeld containers of VM's, om de taakverdeling te verdelen.

Clients stoppen wanneer het aangepaste eindpunt van Application Gateway wordt gebruikt

Het aangepaste eindpuntadres verwijst naar een door de toepassing opgegeven HTTPS-eindpuntadres dat u naar Service Bus kunt laten verwijzen of kunt configureren om verkeer naar Service Bus te routeren. Azure Application Gateway maakt het eenvoudig om een HTTPS-front-end te maken waarmee verkeer naar Service Bus wordt doorgestuurd. U kunt de Service Bus SDK configureren voor een toepassing om een front-end-IP-adres van Application Gateway te gebruiken als het aangepaste eindpunt om verbinding te maken met Service Bus.

Application Gateway biedt verschillende beveiligingsbeleidsregels die ondersteuning bieden voor verschillende TLS-protocolversies. Er zijn vooraf gedefinieerde beleidsregels die TLS 1.2 afdwingen als de minimale versie en oudere beleidsregels die TLS 1.0 als minimale versie gebruiken. U past een TLS-beleid toe op de HTTPS-front-end.

Op dit moment herkent de Service Bus SDK bepaalde externe TCP-beëindigingen niet door de front-end van Application Gateway, die TLS 1.0 als minimale versie gebruikt. Als de front-end bijvoorbeeld TCP FIN- en ACK-pakketten verzendt om de verbinding te sluiten wanneer de eigenschappen worden bijgewerkt, kan de SDK deze pakketten niet detecteren. Er wordt dus geen verbinding meer gemaakt en clients kunnen geen berichten meer verzenden of ontvangen. Deze stop vindt alleen plaats wanneer u TLS 1.0 als minimale versie gebruikt. Als u dit probleem wilt verhelpen, gebruikt u een beveiligingsbeleid waarmee TLS 1.2 of hoger wordt ingesteld als de minimale versie voor de Application Gateway-front-end.

Ondersteuning voor TLS 1.0 en 1.1 voor alle Azure-services wordt al aangekondigd om te eindigen op 31 oktober 2024, dus overgang naar TLS 1.2.

Bericht- of sessievergrendeling gaat verloren

Een Service Bus-wachtrij of -onderwerpabonnement heeft een vergrendelingsduur ingesteld op resourceniveau. Wanneer de ontvangerclient een bericht uit de resource haalt, past de Service Bus-broker een eerste vergrendeling toe op het bericht. De initiële vergrendeling duurt zolang de vergrendeling op resourceniveau is ingesteld. Als de berichtvergrendeling niet wordt vernieuwd voordat het verloopt, geeft de Service Bus broker het bericht vrij om het beschikbaar te maken voor andere ontvangers. Als de toepassing probeert een bericht te voltooien of te verlaten na het verlopen van de vergrendeling, mislukt de API-aanroep met de fout com.azure.messaging.servicebus.ServiceBusException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue.

De Service Bus-client ondersteunt het uitvoeren van een taak voor het vernieuwen van een achtergrondvergrendeling waarmee de berichtvergrendeling voortdurend wordt vernieuwd voordat deze verloopt. Standaard draait de vergrendelingsvernieuwingstaak gedurende 5 minuten. U kunt de verlengingsduur van de vergrendeling aanpassen met behulp van ServiceBusReceiverClientBuilder.maxAutoLockRenewDuration(Duration). Als u de Duration.ZERO waarde doorgeeft, wordt de taak voor het vernieuwen van vergrendeling uitgeschakeld.

In de volgende lijst worden enkele van de gebruikspatronen of hostomgevingen beschreven die kunnen leiden tot een fout waarbij de vergrendeling is verbroken:

  • De taak voor het verlengen van vergrendeling is uitgeschakeld en de verwerkingstijd van het bericht van de toepassing overschrijdt de vergrendelingsduur die is ingesteld op resourceniveau.

  • De verwerkingstijd van het bericht van de toepassing overschrijdt de geconfigureerde tijd voor het vernieuwen van de vergrendeling. Houd er rekening mee dat als de duur van het vergrendelen niet expliciet is ingesteld, de standaardwaarde is ingesteld op 5 minuten.

  • De toepassing schakelt de functie Prefetch in door de prefetch-waarde in te stellen op een positief geheel getal met behulp van ServiceBusReceiverClientBuilder.prefetchCount(prefetch). Wanneer de functie Prefetch is ingeschakeld, haalt de client het aantal berichten op dat gelijk is aan de prefetch uit de entiteit Service Bus - wachtrij of onderwerp - en slaat deze op in de prefetchbuffer in het geheugen. De berichten blijven in de prefetchbuffer staan totdat ze in de toepassing worden ontvangen. De client breidt de vergrendeling van de berichten niet uit terwijl ze zich in de prefetchbuffer bevinden. Als de verwerking van de toepassing zo lang duurt dat berichtvergrendelingen verlopen terwijl ze in de prefetchbuffer blijven, kan de toepassing de berichten verkrijgen met een verlopen vergrendeling. Zie Waarom is Prefetch niet de standaardoptie?

  • De hostomgeving heeft af en toe netwerkproblemen, bijvoorbeeld tijdelijke netwerkstoringen of storingen, die verhinderen dat de taak voor het vernieuwen van vergrendeling de vergrendeling op tijd verlengt.

  • De hostomgeving mist voldoende CPU's of heeft af en toe een tekort aan CPU-cycli waardoor de taak voor het verlengen van de vergrendeling op tijd wordt vertraagd.

  • De tijd van het hostsysteem is niet nauwkeurig, bijvoorbeeld de klok is scheef, waardoor de taak voor het verlengen van de vergrendeling wordt vertraagd en deze niet op tijd wordt uitgevoerd.

  • De I/O-thread van de verbinding is overbelast, wat van invloed is op de mogelijkheid om netwerkoproepen voor het vernieuwen van locks op tijd uit te voeren. De volgende twee scenario's kunnen dit probleem veroorzaken:

  • Een veelvoorkomend toepassingspatroon dat de kans op een verloren vergrendelingsfout vergroot, omvat het plannen van langlopende vergrendelingsvernieuwingstaken, bijvoorbeeld taken met een duur van meerdere uren. Zoals eerder vermeld, kunnen verschillende factoren buiten de controle van een Service Bus-client de succesvolle verlenging van de vergrendeling verstoren, dus applicaties moeten vermijden te veronderstellen dat verlenging voor langere periodes gegarandeerd is. Om te voorkomen dat langlopende bewerkingen opnieuw moeten worden verwerkt, kunt u overwegen om het werk in kleinere segmenten te verdelen of idempotente controlepuntlogica te implementeren.

Het aantal vergrendelingsvernieuwingstaken in de client is gelijk aan de parameterwaarden maxMessages of maxConcurrentCalls die zijn ingesteld voor ServiceBusProcessorClient of ServiceBusReceiverClient.receiveMessages. Een groot aantal taken voor het vernieuwen van vergrendelingen die meerdere netwerkaanroepen doen, kan ook een nadelig effect hebben bij het beperken van de Service Bus-naamruimte.

Als de host niet voldoende resources heeft, kan de vergrendeling nog steeds verloren gaan, zelfs als er slechts enkele taken voor het vernieuwen van vergrendelingen worden uitgevoerd. Als u de Java-toepassing uitvoert op een container, gebruikt u twee of meer vCPU-kernen. Selecteer niets minder dan 1 vCPU-kern bij het uitvoeren van Java toepassingen in een containeromgeving. Zie Containerize uw Java-toepassingenvoor diepgaande aanbevelingen over resourcebeheer.

Dezelfde opmerkingen over vergrendelingen zijn ook relevant voor een Service Bus-wachtrij of een onderwerpabonnement waarvoor sessie is ingeschakeld. Wanneer de ontvangerclient verbinding maakt met een sessie in de resource, past de broker een eerste vergrendeling toe op de sessie. Als u de vergrendeling van de sessie wilt behouden, moet de taak voor het vernieuwen van de vergrendeling in de client de sessievergrendeling blijven vernieuwen voordat deze verloopt. Voor een resource waarvoor een sessie is ingeschakeld, worden de onderliggende partities soms verplaatst om taakverdeling te bereiken tussen Service Bus-knooppunten, bijvoorbeeld wanneer er nieuwe knooppunten worden toegevoegd om de belasting te delen. Als dat gebeurt, kunnen sessievergrendelingen verloren gaan. Als de toepassing probeert een bericht te voltooien of te verlaten nadat de sessievergrendeling is verbroken, mislukt de API-aanroep met de fout com.azure.messaging.servicebus.ServiceBusException: The session lock was lost. Request a new session receiver.

Volgende stappen

Als de richtlijnen voor probleemoplossing in dit artikel niet helpen bij het oplossen van problemen wanneer u de Azure SDK voor Java clientbibliotheken gebruikt, moet u een probleem indienen in de Azure SDK voor Java GitHub opslagplaats.