Java: Too many open files

Nedávno jsme narazili na chybu „Too many open files“ v tomcatu běžícím na našem produkčním Linuxovém serveru.

Jak jistě všichni víte v Javě se o správu paměti stará GC. Ten spustí svoji činnost ve chvíli, kdy je spotřebována paměť a je potřeba další.
Při vytvoření FileInputStream se otevře soubor (a vytvoří tzv. file descriptor). K zavření souboru dojde až ve finalizeru tohoto objektu. Finalizer je ovšem volán až ve chvíli, kdy je objekt uvolnění pomocí GC.

Pokud máte pro program přiděleno hodně paměti, nemusí být GC spuštěno dostatečně často a vyčerpá se limit současně otevřených souborů pro JVM/proces. Záludností tohoto problému je, že se objeví zčista jasna třeba i po roce provozu.

Řešení problému existuje několik:

  • explicitně volat metodu close() na FileInputStream a podobných objektech
  • zvýšit limit současně otevřených souborů příkazem ulimit -n 4000 .
    Pozn.: jádro 2.6.x má maximální zakompilovanou hodnotu 1 000 000. Případně je nutno zvýšit i celkový počet otevřených souborů v celém systému echo 512000 > /proc/sys/fs/file-max
  • docílit častější spouštění GC – třeba tak, že snížíte max heap size. Tato třetí varianta je ve většině případů nepoužitelná.

O limitech operačních systému na počet otevřených souborů se více dočtete v kapitole „Appendix A – Operating system limits“ v mé diplomové práci.

Skenování přes web

Nedávno jsme narazili na problém, jak skenovat soubory přes web. Tvoříme informační systém formou webové aplikace a potřebujeme skenovat velké množství dokumentů.

Řešení, kdy uživatel naskenuje dokument v nějaké aplikaci, a pak jej nahraje (tzv. uploadne) na web, je nereálná. Potřebujeme rychlé oboustranné skenování s podavačem. Uživatel se nesmí zdržovat skenováním náhledu, definicí výřezu, rozlišením a barevnou hloubkou. Už vůbec by neměl být zdržován tím, že se soubor nahrává někam na internetový server.

Proto jsme začali uvažovat o nějakém jednodušším řešení (z hlediska jednoduchosti používání).
Pokračování textu Skenování přes web

Využití OpenSSL certifikátu k podepsání JAR souboru

Využít existující certifikát OpenSSL (vygenerovaný např. vlastní certifikační autoritou) k podepsání JAR souboru (např. pro JavaWebStart) není zrovna jednoduchý úkol. Chtěl bych vám popsat návod jak jsme to vyřešili my. K vygenerování OpenSSL certifikátu můžete použít např.

Předpokládejme, že máme certifikát i klíč uloženy v jednom souboru ve formátu PEM.
Nejdříve musíme vše vyexportovat z formátu PEM do PKCS12. Důležité je pojmenovat certifikát v uložišti, protože se na něj budeme později odkazovat při podepisování JAR souboru.

openssl pkcs12 -export -in SoftEU-JavaWebStart.pem -out SoftEU-JavaWebStart.p12 -name softeu

Akce (export do PKCS12) se provádí jen jednou. Tím jsme získali úložiště, se kterým už jarsigner dokáže pracovat. JAR podepíšeme:

jarsigner  -keystore SoftEU-JavaWebStart.p12 -storetype pkcs12 target/softeu-scan-1.jar softeu

A výsledek zkontrolujeme:

jarsigner -verify target/softeu-scan-1.jar


Klíčová slova: jar sign openssl convert keytool java keystore

Tomcat a problémy s kódováním

Před časem jsme měli problémy s kódováním češtiny v tomcatu. Při postu a getu se čeština občas pokazila.

Chtěl bych se tedy podělit s fíglem jak to vyřešit.
Problém nebyl v aplikaci, ale v konfiguraci tomcatu.

Na všech verzích tomcatu (4.x a 5.x) je potřeba přidat

-Dfile.encoding=utf-8

do CATALINA_OPTS (na debianu do /etc/default/tomcat5). Ve windows v Monitor Tomcat do Configure->Java->Java Options.

Pokud používáte tomcat 5.x (což je náš případ) musíte přidat i toto

URIEncoding="UTF-8"

do konfigurace connectoru v server.xml <Connector port="8080" ... URIEncoding="UTF-8" ... /> (více viz. dokumentace u apachů).