Řešení potíží se službou Azure Service Bus
Tento článek se zabývá technikami šetření selhání, souběžností, běžnými chybami typů přihlašovacích údajů v klientské knihovně Azure Service Bus v Javě a kroky pro zmírnění těchto chyb.
Povolení a konfigurace protokolování
Sada Azure SDK pro Javu nabízí konzistentní scénář protokolování, který pomáhá řešit chyby aplikací a urychlit jejich řešení. Protokoly vytvořené zachytí tok aplikace před dosažením konečného stavu, aby pomohly nalézt kořenový problém. Pokyny k protokolování najdete v tématu Konfigurace protokolování v sadě Azure SDK pro javu a Přehled řešení potíží.
Kromě povolení protokolování poskytuje nastavení úrovně protokolu na VERBOSE
nebo DEBUG
přehled o stavu knihovny. Následující části ukazují ukázkové konfigurace log4j2 a logback, které snižují nadměrné množství zpráv, když je povolené podrobné protokolování.
Konfigurace Log4J 2
Ke konfiguraci Log4J 2 použijte následující kroky:
- Do pom.xml přidejte závislosti pomocí závislostí z ukázky protokolování pom.xmlv části Závislosti vyžadované pro Log4j2.
- Do složky
src/main/resources přidejte log4j2.xml .
Konfigurace zpětného protokolování
Ke konfiguraci zpětného přihlašování použijte následující postup:
- Přidejte do pom.xml závislosti pomocí těch z ukázky protokolování pom.xmlv části "Závislosti vyžadované pro Logback."
- Do složky
src/main/resources přidejte logback.xml .
Povolení protokolování přenosu AMQP
Pokud povolení protokolování klienta nestačí k diagnostice problémů, můžete povolit protokolování do souboru v podkladové knihovně AMQP Qpid Proton-J. Qpid Proton-J používá java.util.logging
. Protokolování můžete povolit vytvořením konfiguračního souboru s obsahem zobrazeným v další části. Nebo nastavte proton.trace.level=ALL
a libovolné možnosti konfigurace, které chcete pro implementaci java.util.logging.Handler
. Třídy implementace a jejich možnosti najdete v tématu Package java.util.logging v dokumentaci k sadě Java 8 SDK.
Pokud chcete trasovat přenosové rámce AMQP, nastavte proměnnou prostředí PN_TRACE_FRM=1
.
Ukázkový soubor logging.properties
Následující konfigurační soubor protokoluje výstup na úrovni TRACE z Proton-J do souboru 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
Omezení protokolování
Jedním ze způsobů, jak snížit logování, je změnit úroveň podrobností. Dalším způsobem je přidat filtry, které vyloučí protokoly z balíčků názvů protokolovacího nástroje, jako jsou com.azure.messaging.servicebus
nebo com.azure.core.amqp
. Příklady najdete v souborech XML v sekcích Konfigurace Log4J 2 a Konfigurace logback.
Když odesíláte chybu, jsou zprávy z logu tříd v následujících balíčcích zajímavé:
com.azure.core.amqp.implementation
com.azure.core.amqp.implementation.handler
- Výjimkou je, že zprávu
onDelivery
můžete vReceiveLinkHandler
ignorovat .
- Výjimkou je, že zprávu
com.azure.messaging.servicebus.implementation
Souběžnost v ServiceBusProcessorClient
ServiceBusProcessorClient
umožňuje aplikaci nakonfigurovat, kolik volání obslužné rutiny zpráv by mělo probíhat souběžně. Tato konfigurace umožňuje paralelně zpracovávat více zpráv. Aplikace používající ServiceBusProcessorClient
na odebírání zpráv z entity mimo relaci může nastavit požadovanou souběžnost pomocí rozhraní API maxConcurrentCalls
. U entity s povolenými relacemi je požadovaná úroveň souběžnosti maxConcurrentSessions
krát maxConcurrentCalls
.
Pokud aplikace sleduje méně souběžných volání obslužné rutiny zpráv, než je nakonfigurovaná souběžnost, může to být proto, že vláknový fond není správně nastaven.
ServiceBusProcessorClient
používá démonická vlákna z globálního fondu vláken boundedElastic k aktivaci obslužné rutiny zprávy. Maximální počet souběžných vláken v tomto fondu je omezen limitem. Ve výchozím nastavení je toto omezení desetkrát větší než počet dostupných jader procesoru. Aby ServiceBusProcessorClient
efektivně podporovala požadovanou úroveň souběžného provádění aplikace (maxConcurrentCalls
nebo maxConcurrentSessions
krát maxConcurrentCalls
), musíte mít hodnotu stropu fondu boundedElastic
, která je vyšší než požadovaná úroveň souběžnosti. Výchozí limit můžete přepsat nastavením systémové vlastnosti reactor.schedulers.defaultBoundedElasticSize
.
Fond vláken a přidělení procesoru byste měli vyladit podle jednotlivých případů. Pokud však přepíšete limit fondu, jako výchozí bod omezte souběžná vlákna na přibližně 20 až 30 na jedno jádro procesoru. Doporučujeme nastavit požadovanou souběžnost na instanci ServiceBusProcessorClient
na přibližně 20–30. Profilujte a změřte konkrétní případ použití a odpovídajícím způsobem vylaďte aspekty souběžnosti. V případě scénářů s vysokým zatížením zvažte spuštění více ServiceBusProcessorClient
instancí, ve kterých je každá instance sestavena z nové instance ServiceBusClientBuilder
. Zvažte také spuštění jednotlivých ServiceBusProcessorClient
ve vyhrazeném hostiteli , jako je kontejner nebo virtuální počítač, aby výpadek v jednom hostiteli neměl vliv na celkové zpracování zpráv.
Mějte na paměti, že nastavení vysoké hodnoty pro limit fondu na hostiteli s málo jádry CPU by mohlo mít nepříznivé důsledky. Mezi příznaky nízkých prostředků procesoru nebo fondu s příliš mnoha vlákny na méně procesorech patří: časté vypršení časového limitu, ztráta zámku, zablokování nebo nižší propustnost. Pokud používáte aplikaci Java v kontejneru, doporučujeme použít dvě nebo více jader vCPU. Při spouštění aplikace Java v kontejnerizovaných prostředích nedoporučujeme vybírat nic menšího než 1 jádro vCPU. Podrobná doporučení týkající se zdrojů najdete viz Kontejnerizace vašich aplikací v Javě.
Kritické body sdílení připojení
Všichni klienti vytvoření z sdíleného instance ServiceBusClientBuilder
sdílejí stejné připojení k oboru názvů služby Service Bus.
Použití sdíleného připojení umožňuje operace multiplexingu mezi klienty na jednom připojení, ale sdílení se může stát kritickým bodem také v případě, že existuje mnoho klientů nebo klienti společně generují vysoké zatížení. Každé připojení má přidružené vstupně-výstupní vlákno. Při sdílení připojení klienti umístí svou práci do pracovní fronty tohoto sdíleného vstupně-výstupního vlákna a průběh každého klienta závisí na včasném dokončení jeho práce ve frontě. Vstupně-výstupní vlákno zpracovává zařazenou práci sériově. To znamená, že pokud pracovní fronta vlákna pro vstupně-výstupní operace sdíleného připojení skončí s velkým množstvím čekající práce, pak jsou příznaky podobné těm, které se objevují při nízkém výkonu procesoru. Tato podmínka je popsaná v předchozí části o souběžnosti – například nečinnost klientů, vypršení časového limitu, ztráta uzamčení nebo zpomalení v procesu obnovy.
Sada Service Bus SDK používá pro vlákno vstupně-výstupních operací připojení vzor pojmenování reactor-executor-*
. Když aplikace zaznamená kritický bod sdíleného připojení, může se to projevit v využití procesoru ve vlákně vstupně-výstupních operací. Také v výpisu haldy nebo v živé paměti je objekt ReactorDispatcher$workQueue
pracovní frontou vstupně-výstupního vlákna. Dlouhá pracovní fronta v snímku paměti během období kritického bodu může znamenat, že sdílené vstupně-výstupní vlákno je přetížené čekajícími operacemi.
Proto pokud je zatížení aplikace do koncového bodu služby Service Bus přiměřeně vysoké z hlediska celkového počtu odeslaných zpráv nebo velikosti datové části, měli byste pro každého klienta, kterého sestavíte, použít samostatnou instanci tvůrce. Například pro každou entitu – frontu nebo téma – můžete vytvořit nový ServiceBusClientBuilder
a z něj vytvořit klienta. V případě extrémně vysokého zatížení pro konkrétní entitu můžete chtít vytvořit pro danou entitu více instancí klienta nebo spustit klienty v několika hostitelích , například kontejnery nebo virtuální počítače, aby bylo možné vyrovnávat zatížení.
Klienti se zastaví při používání vlastního koncového bodu služby Application Gateway.
Adresa vlastního koncového bodu odkazuje na adresu koncového bodu HTTPS poskytovanou aplikací, která se dá přeložit na Service Bus nebo nakonfigurovanou tak, aby směrovala provoz do služby Service Bus. Azure Application Gateway usnadňuje vytvoření front-endu HTTPS, který přesměruje provoz do služby Service Bus. Sadu Service Bus SDK pro aplikaci můžete nakonfigurovat tak, aby jako vlastní koncový bod pro připojení ke službě Service Bus používala front-endovou IP adresu služby Application Gateway.
Application Gateway nabízí několik zásad zabezpečení podporujících různé verze protokolu TLS. Existují předdefinované zásady, které vynucují TLSv1.2 jako minimální verzi, existují také staré zásady s TLSv1.0 jako minimální verzí. Front-end HTTPS bude mít použitou zásadu TLS.
V současné chvíli sada SDK služby Service Bus nerozpozná určité vzdálené ukončení protokolu TCP front-endem služby Application Gateway, která jako minimální verzi používá TLSv1.0. Pokud například front-end odešle TCP FIN, pakety ACK zavřou připojení při aktualizaci jeho vlastností, sada SDK ho nedokáže rozpoznat, takže se znovu nepřipojí a klienti už nebudou moct odesílat ani přijímat zprávy. K takovému zastavení dochází pouze při použití TLSv1.0 jako minimální verze. Pokud chcete zmírnit omezení, použijte zásadu zabezpečení s TLSv1.2 nebo vyšší jako minimální verzi front-endu služby Application Gateway.
Podpora TLSv1.0 a 1.1 ve všech službách Azure je již oznámena do 31. října 2024, takže přechod na TLSv1.2 se důrazně doporučuje.
Zpráva nebo zámek relace se ztratí.
Fronta nebo odběr tématu služby Service Bus má nastavenou dobu uzamčení na úrovni prostředku. Když klientský příjemce stáhne zprávu z prostředku, zprostředkovatel služby Service Bus aplikuje počáteční zámek na zprávu. Počáteční zámek trvá po dobu, která je nastavena na úrovni prostředku. Pokud se zámek zprávy neprodlouží před vypršením platnosti, zprostředkovatel Service Bus zprávu uvolní, aby ji zpřístupnil ostatním příjemcům. Pokud se aplikace pokusí dokončit nebo opustit zprávu po vypršení platnosti zámku, volání rozhraní API selže s chybou com.azure.messaging.servicebus.ServiceBusException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue
.
Klient služby Service Bus podporuje spuštění úlohy obnovení zámku na pozadí, která obnovuje zámek zprávy nepřetržitě pokaždé, než vyprší jeho platnost. Ve výchozím nastavení se úloha prodlužování zámku spustí po dobu 5 minut. Dobu trvání prodloužení platnosti zámku můžete upravit pomocí ServiceBusReceiverClientBuilder.maxAutoLockRenewDuration(Duration)
. Pokud předáte hodnotu Duration.ZERO
, úloha prodlužování zámku je deaktivována.
Následující seznamy popisují některé vzory použití nebo hostitelské prostředí, které můžou vést ke ztrátě zámku:
Úloha prodloužení zámku je zakázaná a doba zpracování zpráv aplikace překračuje dobu trvání zámku nastavenou na úrovni prostředku.
Doba zpracování zpráv aplikace překračuje nakonfigurovanou dobu trvání úlohy obnovení zámku. Mějte na paměti, že pokud není doba trvání prodloužení zámku explicitně nastavená, výchozí hodnota je 5 minut.
Aplikace zapnula funkci Prefetch nastavením hodnoty prefetch na kladné celé číslo pomocí
ServiceBusReceiverClientBuilder.prefetchCount(prefetch)
. Pokud je funkce předběžného načtení povolena, klient načte počet zpráv, který odpovídá počtu předběžného načtení z entity platformy Service Bus – ať už se jedná o frontu nebo téma – a uloží je do vyrovnávací paměti pro předběžné načtení. Zprávy zůstanou ve vyrovnávací paměti předběžného načtení, dokud nebudou přijaty do aplikace. Klient neprodlužuje uzamčení zpráv, když jsou ve vyrovnávací paměti předběžného načítání. Pokud zpracování aplikace trvá tak dlouho, že během pobytu ve vyrovnávací paměti předběžného načtení vyprší platnost zámku zpráv, může aplikace získat zprávy s již neplatným zámkem. Další informace najdete v tématu Proč není předběžné načítání výchozí volbou?Hostitelské prostředí má občasné problémy se sítí – například přechodné selhání sítě nebo výpadek – které brání úloze pro obnovení zámku k včasnému obnovení zámku.
Hostitelské prostředí nemá dostatek procesorů nebo občasný nedostatek cyklů procesoru, což zpožďuje provedení úlohy obnovení zámku včas.
Čas hostitelského systému není přesný – například hodiny jsou posunuté – což zpožďuje úlohu obnovení zámku a brání jí v běhu včas.
Vstupně-výstupní vlákno připojení je přetížené, což ovlivňuje jeho schopnost provádět síťová volání na obnovování zámků včas. Tento problém může způsobovat následující dva scénáře:
- Aplikace spouští příliš mnoho příjemců, kteří sdílejí stejné připojení. Další informace najdete v části Kritické body sdílení připojení.
- Aplikace nakonfigurovala
ServiceBusReceiverClient.receiveMessages
neboServiceBusProcessorClient
tak, aby měla velkémaxMessages
nebomaxConcurrentCalls
hodnoty. Další informace najdete v části Konkurence ve ServiceBusProcessorClient.
Počet úloh obnovení zámku v klientovi se rovná hodnotám parametrů maxMessages
nebo maxConcurrentCalls
nastaveným pro ServiceBusProcessorClient
nebo ServiceBusReceiverClient.receiveMessages
. Velký počet úloh obnovení zámku, které provádí více síťových volání, může mít také nepříznivý vliv na omezování oboru názvů služby Service Bus.
Pokud hostitel nemá dostatečné prostředky, může být zámek stále ztracen, i když je spuštěno pouze několik úloh pro obnovu zámku. Pokud používáte aplikaci Java v kontejneru, doporučujeme použít dvě nebo více jader vCPU. Při spouštění aplikací Java v kontejnerizovaných prostředích nedoporučujeme vybírat nic menšího než 1 jádro vCPU. Podrobná doporučení týkající se získávání zdrojů najdete v tématu Kontejnerizace vašich aplikací v Javě.
Stejné poznámky týkající se zámků jsou relevantní také pro frontu služby Service Bus nebo odběr tématu, které má povolenou relaci. Když se klient příjemce připojí k relaci v prostředku, broker aplikuje počáteční zámek na tu relaci. Aby bylo možné zachovat zámek v relaci, musí úloha obnovení zámku v klientovi zachovat zámek relace před vypršením jeho platnosti. U prostředku s povolenou relací se podkladové oddíly někdy přesunou, aby se dosáhlo vyrovnávání zatížení mezi uzly Service Bus , například když se přidají nové uzly pro sdílení zatížení. Když k tomu dojde, mohou být ztraceny zámky relace. Pokud se aplikace pokusí dokončit nebo opustit zprávu po ztrátě zámku relace, volání rozhraní API selže s chybou com.azure.messaging.servicebus.ServiceBusException: The session lock was lost. Request a new session receiver
.
Upgrade na verzi 7.15.x nebo nejnovější
Pokud narazíte na nějaké problémy, měli byste se nejprve pokusit je vyřešit upgradem na nejnovější verzi sady Service Bus SDK. Verze 7.15.x je zásadním návrhem, který řeší dlouhotrvající problémy týkající se výkonu a spolehlivosti.
Verze 7.15.x a novější snižuje přeskakování vláken, odstraňuje zámky, optimalizuje kód v kritických úsecích a snižuje přidělení paměti. Výsledkem těchto změn je až 45 až 50krát vyšší propustnost ServiceBusProcessorClient
.
Verze 7.15.x a novější přináší také různá vylepšení spolehlivosti. Řeší několik podmínek závodu (například předběžné načtení a výpočty kreditů) a zlepšené zpracování chyb. Tyto změny vedou k lepší spolehlivosti v přítomnosti přechodných problémů v různých typech klientů.
Používání nejnovějších klientů
Nová základní architektura s těmito vylepšeními – ve verzi 7.15.x a novější – se nazývá V2-Stack. Tato verze zahrnuje jak předchozí generaci základního stacku, stack, který používá verze 7.14.x, tak nový V2-Stack.
Ve výchozím nastavení některé typy klientů používají sadu V2-Stack, zatímco jiné vyžadují V2-Stack opt-in. Můžete dosáhnout zařazení nebo vyloučení konkrétní verze (V2 nebo předchozí generace) pro konkrétní typ klienta tím, že při vytváření klienta zadáte hodnoty com.azure.core.util.Configuration
.
Například příjem relací založených na sadě V2 s ServiceBusSessionReceiverClient
vyžaduje aktivaci, jak je znázorněno v následujícím příkladu:
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();
Následující tabulka uvádí typy klientů a odpovídající názvy konfigurace a udává, jestli je klient ve výchozím nastavení povolený, aby používal V2-Stack v nejnovější verzi 7.17.0. U klienta, který není ve výchozím nastavení na V2-Stack, můžete k vyjádření souhlasu použít právě zobrazený příklad.
Typ klienta | Název konfigurace | Je V2-Stack nastaveno jako výchozí? |
---|---|---|
Odesílatel a klient pro správu | com.azure.messaging.servicebus.sendAndManageRules.v2 |
Ano |
Klient bez relace procesoru a příjemce reaktoru | com.azure.messaging.servicebus.nonSession.asyncReceive.v2 |
Ano |
Klient pro zpracování a příjem relací | com.azure.messaging.servicebus.session.processor.asyncReceive.v2 |
Ano |
Klient přijímače relačních reaktorů | com.azure.messaging.servicebus.session.reactor.asyncReceive.v2 |
Ano |
Synchronní klient příjemce bez relace | com.azure.messaging.servicebus.nonSession.syncReceive.v2 |
Ne |
Klient synchronního příjemce relace | com.azure.messaging.servicebus.session.syncReceive.v2 |
Ne |
Jako alternativu k používání com.azure.core.util.Configuration
můžete vyjádřit výslovný souhlas nebo výslovný nesouhlas nastavením stejných názvů konfigurací pomocí proměnných prostředí nebo systémových vlastností.
Další kroky
Pokud pokyny pro řešení potíží v tomto článku nepomohly vyřešit problémy při používání klientských knihoven Azure SDK pro Javu, doporučujeme, abyste problém v úložišti Azure SDK pro Javu na GitHubu.