Problemen met Azure Service Bus oplossen
In dit artikel worden technieken voor foutonderzoek, gelijktijdigheid, veelvoorkomende fouten voor de referentietypen in de Azure Service Bus Java-clientbibliotheek beschreven en worden oplossingen voor deze fouten beschreven.
Logboekregistratie inschakelen en configureren
Azure SDK voor Java biedt een consistent logboekregistratieverhaal voor hulp bij het oplossen van toepassingsfouten en om hun oplossing te versnellen. De logboeken die worden geproduceerd, leggen de stroom van een toepassing vast voordat de terminalstatus wordt bereikt om het hoofdprobleem op te sporen. Zie Logboekregistratie configureren in de Overzicht van Azure SDK voor Java en Probleemoplossing voor hulp bij logboekregistratie.
Naast het inschakelen van logboekregistratie kunt u het logboekniveau VERBOSE
instellen op of DEBUG
inzichten geven 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:
- Voeg de afhankelijkheden in uw pom.xml toe met behulp van afhankelijkheden uit het voorbeeld van logboekregistratie pom.xml in de sectie 'Afhankelijkheden vereist voor Log4j2'.
- Voeg log4j2.xml toe aan de map src/main/resources .
Logback configureren
Gebruik de volgende stappen om logback te configureren:
- Voeg de afhankelijkheden in uw pom.xml toe met behulp van afhankelijkheden uit het logboekregistratievoorbeeld pom.xml in de sectie 'Afhankelijkheden vereist voor logback'.
- Voeg logback.xml toe aan de map src/main/resources .
AMQP-transportlogboekregistratie inschakelen
Als het inschakelen van clientlogboekregistratie niet voldoende is om uw problemen vast te stellen, kunt u logboekregistratie inschakelen naar een bestand in de onderliggende AMQP-bibliotheek, Qpid Proton-J. Qpid Proton-J gebruikt java.util.logging
. U kunt logboekregistratie inschakelen door een configuratiebestand te maken met de inhoud die wordt weergegeven in de volgende sectie. U kunt ook instellen welke configuratieopties u wilt instellen proton.trace.level=ALL
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 PN_TRACE_FRM=1
omgevingsvariabele in.
Voorbeeldbestand logging.properties
Met het volgende configuratiebestand wordt uitvoer van TRACE-niveau van Proton-J in 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
Logboekregistratie beperken
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 logboeknamenpakketten zoals com.azure.messaging.servicebus
of com.azure.core.amqp
. Zie de XML-bestanden in de secties Log4J 2 configureren en Logback configureren voor voorbeelden.
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 kunt negeren inReceiveLinkHandler
.
- De uitzondering is dat u het
com.azure.messaging.servicebus.implementation
Gelijktijdigheid in ServiceBusProcessorClient
ServiceBusProcessorClient
hiermee kan de toepassing configureren hoeveel aanroepen naar de berichtenhandler gelijktijdig moeten plaatsvinden. Met deze configuratie kunt u meerdere berichten parallel verwerken. Voor een ServiceBusProcessorClient
verbruikende berichten van een entiteit zonder sessie kan de toepassing de gewenste gelijktijdigheid configureren met behulp van de maxConcurrentCalls
API. Voor een entiteit waarvoor een sessie is ingeschakeld, is maxConcurrentSessions
de gewenste gelijktijdigheid tijd maxConcurrentCalls
.
Als de toepassing minder gelijktijdige aanroepen naar de berichthandler ziet dan de geconfigureerde gelijktijdigheid, kan dit komen doordat de threadgroep niet de juiste grootte heeft.
ServiceBusProcessorClient
gebruikt daemon-threads uit de global boundedElastic thread pool van Reactor 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. Als u ServiceBusProcessorClient
de gewenste gelijktijdigheid (maxConcurrentCalls
of maxConcurrentSessions
tijden maxConcurrentCalls
) van de toepassing effectief wilt ondersteunen, moet u een boundedElastic
poollimietwaarde hebben die hoger is dan de gewenste gelijktijdigheid. U kunt de standaardlimiet overschrijven door de systeemeigenschap reactor.schedulers.defaultBoundedElasticSize
in te stellen.
U moet de threadpool en CPU-toewijzing afstemmen op case-by-casebasis. Wanneer u de poollimiet echter overschrijft als uitgangspunt, beperkt u de gelijktijdige threads tot ongeveer 20-30 per CPU-kern. U wordt aangeraden de gewenste gelijktijdigheid per ServiceBusProcessorClient
instantie te caperen 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 overwegen om meerdere ServiceBusProcessorClient
exemplaren uit te voeren waarbij elk exemplaar is gebouwd op basis van een nieuw ServiceBusClientBuilder
exemplaar. Overweeg ook elk ServiceBusProcessorClient
item uit te voeren op een toegewezen host, zoals een container of VM, zodat downtime in één host niet van invloed is 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 zou hebben. 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 in een container, raden we u aan twee of meer vCPU-kernen te gebruiken. Het wordt afgeraden om iets minder dan 1 vCPU-kern te selecteren bij het uitvoeren van een Java-toepassing in een containeromgeving. Zie Containerize uw Java-toepassingen voor uitgebreide aanbevelingen voor het ophalen van bronnen.
Knelpunt voor delen van verbinding
Alle clients die zijn gemaakt op basis van een gedeeld exemplaar ServiceBusClientBuilder
, 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. Bij het delen van de verbinding plaatsen de clients hun werk in de werkwachtrij van deze gedeelde I/O-thread en de voortgang van elke client is afhankelijk van de tijdige voltooiing van het werk in de wachtrij. De I/O-thread verwerkt het ge enqueued werk serieel. Als de I/O-threadwerkwachtrij van een gedeelde verbinding uiteindelijk veel werk in behandeling heeft om mee te maken, zijn de symptomen vergelijkbaar met die van een lage CPU. 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. In de heapdump of in het livegeheugen is het object ReactorDispatcher$workQueue
ook de werkwachtrij van de I/O-thread. Een lange werkwachtrij in de geheugenmomentopname tijdens de knelpuntperiode kan erop wijzen dat de gedeelde I/O-thread overbelast is met werken die in behandeling zijn.
Als de belasting van de toepassing naar een Service Bus-eindpunt redelijk hoog is in termen van het totale aantal verzonden berichten of nettoladinggrootte, moet u daarom een afzonderlijk builder-exemplaar gebruiken voor elke client die u bouwt. Voor elke entiteit , wachtrij of onderwerp, kunt u bijvoorbeeld een nieuwe ServiceBusClientBuilder
entiteit maken en er een client van maken. 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 verstrekte HTTPS-eindpuntadres dat kan worden omgezet in Service Bus of geconfigureerd om verkeer naar Service Bus te routeren. Azure-toepassing Gateway maakt het eenvoudig om een HTTPS-front-end te maken waarmee verkeer naar Service Bus wordt doorgestuurd. U kunt 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 verschillende TLS-protocolversies ondersteunen. Er zijn vooraf gedefinieerde beleidsregels die TLSv1.2 afdwingen als de minimale versie, er bestaan ook oude beleidsregels met TLSv1.0 als minimale versie. Op de HTTPS-front-end wordt een TLS-beleid toegepast.
Op dit moment herkent de Service Bus SDK bepaalde externe TCP-beëindigingen niet door de front-end van Application Gateway, die TLSv1.0 als minimale versie gebruikt. Als de front-end bijvoorbeeld TCP FIN verzendt, ACK-pakketten om de verbinding te sluiten wanneer de eigenschappen worden bijgewerkt, kan de SDK deze niet detecteren, zodat deze niet opnieuw verbinding maakt en clients geen berichten meer kunnen verzenden of ontvangen. Een dergelijke stop vindt alleen plaats wanneer u TLSv1.0 als minimale versie gebruikt. Als u dit wilt beperken, gebruikt u een beveiligingsbeleid met TLSv1.2 of hoger als de minimale versie voor de front-end van Application Gateway.
De ondersteuning voor TLSv1.0 en 1.1 voor alle Azure-services wordt al aangekondigd om te eindigen op 31 oktober 2024, dus de overgang naar TLSv1.2 wordt sterk aanbevolen.
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 voor de duur van de vergrendeling die is ingesteld op resourceniveau. 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 af te sluiten nadat de vergrendeling is verlopen, 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. De vernieuwingstaak wordt standaard vijf minuten uitgevoerd. U kunt de verlengingsduur van de vergrendeling aanpassen met behulp van ServiceBusReceiverClientBuilder.maxAutoLockRenewDuration(Duration)
. Als u de Duration.ZERO
waarde doorgeeft, is de vernieuwingstaak voor vergrendelen uitgeschakeld.
In de volgende lijsten 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 duur van 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 heeft de functie Prefetch ingeschakeld 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 Service Bus-entiteit - wachtrij of onderwerp - en slaat deze op in de buffer voor in-memory prefetch. 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 en heeft invloed op de mogelijkheid om netwerkaanroepen op tijd te vergrendelen. De volgende twee scenario's kunnen dit probleem veroorzaken:
- De toepassing voert te veel ontvangerclients uit die dezelfde verbinding delen. Zie de sectie Knelpunten voor het delen van verbindingen voor meer informatie.
- De toepassing heeft een grote waarde
ServiceBusProcessorClient
of een grotemaxMessages
waardemaxConcurrentCalls
geconfigureerdServiceBusReceiverClient.receiveMessages
. Zie de sectie Gelijktijdigheid in ServiceBusProcessorClient voor meer informatie.
Het aantal vergrendelingsvernieuwingstaken in de client is gelijk aan de maxMessages
of maxConcurrentCalls
parameterwaarden die zijn ingesteld voor ServiceBusProcessorClient
of ServiceBusReceiverClient.receiveMessages
. Een groot aantal vergrendelingsvernieuwingstaken die meerdere netwerkaanroepen maken, kan ook een nadelig effect hebben in de beperking van de Service Bus-naamruimte.
Als de host onvoldoende 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 in een container, raden we u aan twee of meer vCPU-kernen te gebruiken. We raden u niet aan om iets minder dan 1 vCPU-kern te selecteren bij het uitvoeren van Java-toepassingen in containeromgevingen. Zie Containerize uw Java-toepassingen voor uitgebreide aanbevelingen voor het ophalen van bronnen.
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 af te sluiten 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
.
Upgraden naar 7.15.x of nieuwste
Als u problemen ondervindt, moet u deze eerst proberen op te lossen door een upgrade uit te voeren naar de nieuwste versie van de Service Bus SDK. Versie 7.15.x is een belangrijk herontwerp, waardoor langdurige prestatie- en betrouwbaarheidsproblemen worden opgelost.
Versie 7.15.x en hoger vermindert het hoppen van threads, verwijdert vergrendelingen, optimaliseert code in dynamische paden en vermindert geheugentoewijzingen. Deze wijzigingen resulteren in maximaal 45-50 keer hogere doorvoer op de ServiceBusProcessorClient
.
Versie 7.15.x en hoger wordt ook geleverd met verschillende betrouwbaarheidsverbeteringen. Het behandelt verschillende racevoorwaarden (zoals prefetch en kredietberekeningen) en verbeterde foutafhandeling. Deze wijzigingen resulteren in een betere betrouwbaarheid in de aanwezigheid van tijdelijke problemen in verschillende clienttypen.
De nieuwste clients gebruiken
Het nieuwe onderliggende framework met deze verbeteringen, in versie 7.15.x en hoger, wordt de V2-Stack genoemd. Deze releaselijn bevat zowel de vorige generatie van de onderliggende stack- de stack die versie 7.14.x gebruikt - als de nieuwe V2-Stack.
Sommige clienttypen gebruiken standaard de V2-Stack, terwijl andere V2-Stack-opt-in vereisen. U kunt de opt-in of opt-out van een specifieke stack (V2 of de vorige generatie) voor een clienttype uitvoeren door waarden op te geven com.azure.core.util.Configuration
wanneer u de client bouwt.
Voor een V2-Stack-sessie is ServiceBusSessionReceiverClient
bijvoorbeeld aanmelding vereist, zoals wordt weergegeven in het volgende voorbeeld:
ServiceBusSessionReceiverClient sessionReceiver = new ServiceBusClientBuilder()
.connectionString(Config.CONNECTION_STRING)
.configuration(new com.azure.core.util.ConfigurationBuilder()
.putProperty("com.azure.messaging.servicebus.session.syncReceive.v2", "true") // 'false' by default, opt-in for V2-Stack.
.build())
.sessionReceiver()
.queueName(Config.QUEUE_NAME)
.buildClient();
De volgende tabel bevat de clienttypen en bijbehorende configuratienamen en geeft aan of de client momenteel standaard is ingeschakeld voor gebruik van de V2-Stack in de nieuwste versie 7.17.0. Voor een client die zich niet standaard op de V2-Stack bevindt, kunt u het voorbeeld gebruiken dat zojuist wordt weergegeven om u aan te invoegtoepassingen.
Client-type | Configuratienaam | Is V2-Stack standaard ingeschakeld? |
---|---|---|
Afzender en beheerclient | com.azure.messaging.servicebus.sendAndManageRules.v2 |
ja |
Client voor niet-sessieprocessor en reactorontvanger | com.azure.messaging.servicebus.nonSession.asyncReceive.v2 |
ja |
Ontvangerclient van sessieprocessor | com.azure.messaging.servicebus.session.processor.asyncReceive.v2 |
ja |
Sessie reactor ontvanger client | com.azure.messaging.servicebus.session.reactor.asyncReceive.v2 |
ja |
Niet-sessie synchrone ontvangerclient | com.azure.messaging.servicebus.nonSession.syncReceive.v2 |
nee |
Sessiesynchrone ontvangerclient | com.azure.messaging.servicebus.session.syncReceive.v2 |
nee |
Als alternatief voor het gebruik com.azure.core.util.Configuration
kunt u de opt-in of opt-out uitvoeren door dezelfde configuratienamen in te stellen met behulp van omgevingsvariabelen of systeemeigenschappen.
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, raden we u aan een probleem op te slaan in de Azure SDK voor Java GitHub-opslagplaats.