Portál AbcLinuxu, 25. dubna 2024 16:20


Dotaz: Trvale zablokovaný socket v Javě

Luboš Doležel (Doli) avatar 25.7.2011 20:01 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
Trvale zablokovaný socket v Javě
Přečteno: 331×
Odpovědět | Admin
Ahoj, řeším na Ábíčku problém s načítáním RSS, kdy se načítací vlákno natrvalo zasekne a nikdy se neodblokuje. jstack ukazuje toto:
"links scheduler" daemon prio=10 tid=0x00007fdb642d8800 nid=0x442e runnable [0x00007fdb61d24000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(SocketInputStream.java:129)
	at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
	- locked <0x00000000a79a4be8> (a java.io.BufferedInputStream)
	at sun.net.www.MeteredStream.read(MeteredStream.java:116)
	- locked <0x00000000a79a4bc0> (a sun.net.www.MeteredStream)
	at java.io.FilterInputStream.read(FilterInputStream.java:116)
	at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2672)
	at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
	- locked <0x00000000a79a7558> (a java.io.BufferedInputStream)
	at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
	at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:151)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read(InputStreamReader.java:167)
	at com.sun.syndication.io.XmlReader.read(XmlReader.java:394)
	at java.io.Reader.read(Reader.java:104)
	at com.sun.syndication.io.impl.XmlFixerReader.read(XmlFixerReader.java:215)
	at com.sun.syndication.io.impl.XmlFixerReader.read(XmlFixerReader.java:299)
	at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1742)
	at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1416)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2792)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
	at org.jdom.input.SAXBuilder.build(SAXBuilder.java:453)
	at org.jdom.input.SAXBuilder.build(SAXBuilder.java:851)
	at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:194)
	at com.sun.syndication.io.SyndFeedInput.build(SyndFeedInput.java:123)
	at cz.abclinuxu.scheduler.UpdateLinks.parseRSS(UpdateLinks.java:240)
	at cz.abclinuxu.scheduler.UpdateLinks.synchronize(UpdateLinks.java:166)
	at cz.abclinuxu.scheduler.UpdateLinks.run(UpdateLinks.java:126)
	at java.util.TimerThread.mainLoop(Timer.java:512)
	at java.util.TimerThread.run(Timer.java:462)
V kódu bylo odjakživa nastaveno toto, ale evidentně to nemá žádný dopad:
System.setProperty ("sun.net.client.defaultReadTimeout", "7000");
System.setProperty ("sun.net.client.defaultConnectTimeout", "7000");
Řádek, který blokuje, vypadá takto:
SyndFeed feed = input.build(new XmlReader(new URL(rssUrl)));
netstat ukazuje tento řádek se spojením, na kterém to visí:
tcp6       0      0 82.208.17.52:60328      208.93.0.168:80         SPOJENO    
Podle wiresharku se už na tomto socketu žádné pakety nevyměňují a stojí to a stojí... Máte nápad, co s tím?
Nástroje: Začni sledovat (1) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

25.7.2011 20:49 petr_p | skóre: 59 | blog: pb
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
Odpovědět | | Sbalit | Link | Blokovat | Admin

S javou zkušenosti nemám, ale podle výpisu to tipuji na uváznutí:

at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:151)
	- locked <0x00000000a79a7580> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read(InputStreamReader.java:167)

Předpokládám, že 0x00000000a79a7580 je adresa zámku. Podívejte se do zdrojáku, co se tam má dít.

Netstat tvrdí, že žádná data v jaderném bufferu socketu nečekají, až si je aplikace přečte.

Můžete zkusit odesláním TCP FIN packetu se správným sekvenčním číslem TCP spojení uzavřít a tím ověřit, jestli vlákno opravdo uvázlo. (Například nástrojem hping, existuje i specializované udělátko, na jehož název si teď nevzpomenu.)

Luboš Doležel (Doli) avatar 25.7.2011 21:08 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
Myslím si, že ty zámky jsou v pořádku, protože se to přes ně dostalo až do nativní metody a navíc je vlákno RUNNABLE.

Za tip s podvržením FIN paketu děkuju.
26.7.2011 09:17 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ve výchozím nastavení je tam timeout -1 (čekat donekonečna), a podle mne není možnost to nastavit přes systémovou vlastnost (ty vlastnosti uvedené v dotazu to neovlivňují). Ono je lepší vyhnout se téhle automatice, kdy se z URL rovnou na pozadí vytvoří stream – nedá se tam pak nic nakonfigurovat ani řídit. Tady je podle mne jediná možnost – z toho URL si ručně vytvořit URLConnection, tam nastavit connectionTimeout, a už nakonfigurované URLConnection pak předat XMLReaderu. A nebo se úplně vykašlat na implementaci HTTP klienta od Sunu a použít třeba Apache HttpComponents – k tomu Sunovskému nemám moc důvěru, nedá se moc konfigurovat ani řídit, a nevypadá moc odladěně (ten kód se v průběhu jednotlivých updatů JRE/JDK pořád mění a opravují se tam dost podstatné chyby).
26.7.2011 12:08 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
Ještě k tomu samotnému spojení – chtělo by to podívat se do té HTTP komunikace. Jestli se tam třeba neposílají Keep-Alive hlavičky a spojení se tedy neudržuje otevřené záměrně. Jinak při HTTP komunikaci by spojení měl uzavírat server, takže pokud spojení neuzavřel, je chyba na druhé straně (a problém s timeoutem je až chybné řešení této chyby).
26.7.2011 11:53 Ivan
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ty pouzivas IPv6? Jakou verzi JVM pouzivas? Pokud pamatuju tak IPv6 bylo v Java silene zabugovany. Pro dalsi investigaci muzes:

- poslat vystup z tcpdumpu/(wiresharku) a zjisitit kdo komu poslal posledni packet

- attachnout strace/(nebo jeste lepe gdb) k JVM a zjistit na jaky syscall v kernelu JVM ceka

- spustit netstat na protistrane.

PS: ty dve nuly ve vypisu netstatu znamenaji, ze nic neni v read/write bufferu TCP socketu v kernelu.
Luboš Doležel (Doli) avatar 26.7.2011 12:32 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
Rozbalit Rozbalit vše Re: Trvale zablokovaný socket v Javě
java version "1.6.0_26"

Schválně jsem zkusil IPv6 stack zakázat (nebojte, Ábíčko přes IPv6 stále běží dál) - to mě zajímá. Jinak jsem přepsal kód, aby se timeouty nastavovaly přímo na URLConnection, ale to nasadím až pak. Bohužel jsem narazil na zmínky, že timeouty u URLConnection nefungují moc spolehlivě.

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.