2016-09-28 67 views
5

Son birkaç gündür büyük bir uygulamada bir sınıf yükleyici sızıntısını analiz ettim ve problemi çözdüm.SolrJ, HttpClient, JVM veya benim başvurumda geçersiz SSL sertifikası nedeniyle sınıf yükleyici sızıntısı var mı?

@Bean(destroyMethod = "close") 
public SolrClient solrClient() { 
    return new HttpSolrClient(SOLR_URL); 
} 

SolrJ (org.apache.solr:solr-solrj:5.4.1) Apache HttpClient (org.apache.httpcomponents:httpclient:4.4.1) kullanır:

başvurum bir @Bean kullanılan yöntem vasıtasıyla initialilzed edilecektir SolrJ kullanır. HttpClient, SSL bağlamını javax.net.ssl.SSLSocketFactory gibi normal java sınıflarını kullanarak başlatır. Bu şekilde java, trustManager'ı yükler ve tüm güvenilir sertifikaları analiz eder. Bir hata varsa, sertifika (bir örnek sun.security.x509.X509CertImpl) bir listede saklanır ve atılan istisna tarafından zenginleştirilir. Bu istisna yutuldu ve başvurum habersiz kalıyor.

, benim Uygulama adanmış WebappClassLoader yılında Bildiğim kadarıyla gördüğünüz gibi, SSL Bağlam Sistemi/Kök ClassLoader içindedir

olduğunu ve şimdi referansları içeren SSL bağlamı içinde bir IOException olduğundan bu sorundur Benim uygulamada stacktrace, backtrace ve benzeri sınıfları.

Ama şimdi bunun nereden geldiğini bilmiyorum. SolrJ istemcisi, Apache HttpClient, Java'nın kendisi mi (JVM), yoksa benim uygulamam mı? Bu aynı zamanda bir geçici çözüm (classloader sızıntısına neden başvuruları kaldıran bir kapatma kanca) içerir https://github.com/CptS/solrj-classloader-leak :

Burada bulabilirsiniz sorunu yeniden oluşturmaya küçük bir uygulama yaptık. Eğer (bunu yorumlama yoluyla) kapatma kanca devre dışı bırakmak ve temiz bir Tomcat başlatırsanız

bu izleyerek üretebilir (aşağıda "çoğaltmak Çevre" bölümü) arasındaki adımları:

  1. savaşını dağıtmak demo projesi, (A)
  2. yeniden bu (B)
  3. yeniden tekrar (C)
  4. Tetik GC (D)
  5. undeploy
  6. Trigg er GC (E)
  7. metaspace tamamen (F) temizlenmiş değil alır Görüyor

enter image description here

Bir yığın dökümü oluşturmak ettik ve GŞ kısa yol şuna benzer:

enter image description here

Bu

benim büyük uygulamada aynıydı.>SSLContextImpl#trustManager - ->X509TrustManager#trustedCerts SSLContextImpl.DefaultSSLContext#defaultImpl: belirtilen Geçici çözüm (biraz https://github.com/mjiderhamn/classloader-leak-prevention esinlenerek, ama bu ne yazık ki benim sorunu çözmez) bu unparseableExtensions ve için yansıma kullanarak aramaları bu yolla why alanda depolanan İstisna kaldırır ->X509CertImpl#info ->X509CertInfo#extensions ->CertificateExtensions#unparseableExtensions - eğer yardımcı olur>UnparseableExtension#why

bunu yaparak i istisna stacktrace var birisi:

java.io.IOException: No data available in passed DER encoded value. 
    at sun.security.x509.GeneralNames.<init>(GeneralNames.java:61) 
    at sun.security.x509.IssuerAlternativeNameExtension.<init>(IssuerAlternativeNameExtension.java:136) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
    at sun.security.x509.CertificateExtensions.parseExtension(CertificateExtensions.java:113) 
    at sun.security.x509.CertificateExtensions.init(CertificateExtensions.java:88) 
    at sun.security.x509.CertificateExtensions.<init>(CertificateExtensions.java:78) 
    at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:702) 
    at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167) 
    at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1804) 
    at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195) 
    at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:100) 
    at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339) 
    at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:755) 
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56) 
    at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224) 
    at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70) 
    at java.security.KeyStore.load(KeyStore.java:1445) 
    at sun.security.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(TrustManagerFactoryImpl.java:226) 
    at sun.security.ssl.SSLContextImpl$DefaultSSLContext.getDefaultTrustManager(SSLContextImpl.java:767) 
    at sun.security.ssl.SSLContextImpl$DefaultSSLContext.<init>(SSLContextImpl.java:733) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
    at java.security.Provider$Service.newInstance(Provider.java:1595) 
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:236) 
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:164) 
    at javax.net.ssl.SSLContext.getInstance(SSLContext.java:156) 
    at javax.net.ssl.SSLContext.getDefault(SSLContext.java:96) 
    at javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:122) 
    at org.apache.http.conn.ssl.SSLSocketFactory.getSystemSocketFactory(SSLSocketFactory.java:190) 
    at org.apache.http.impl.conn.SchemeRegistryFactory.createSystemDefault(SchemeRegistryFactory.java:85) 
    at org.apache.http.impl.client.SystemDefaultHttpClient.createClientConnectionManager(SystemDefaultHttpClient.java:121) 
    at org.apache.http.impl.client.AbstractHttpClient.getConnectionManager(AbstractHttpClient.java:484) 
    at org.apache.solr.client.solrj.impl.HttpClientUtil.setMaxConnections(HttpClientUtil.java:234) 
    at org.apache.solr.client.solrj.impl.HttpClientConfigurer.configure(HttpClientConfigurer.java:40) 
    at org.apache.solr.client.solrj.impl.HttpClientUtil.configureClient(HttpClientUtil.java:149) 
    at org.apache.solr.client.solrj.impl.HttpClientUtil.createClient(HttpClientUtil.java:125) 
    at org.apache.solr.client.solrj.impl.HttpSolrClient.<init>(HttpSolrClient.java:189) 
    at org.apache.solr.client.solrj.impl.HttpSolrClient.<init>(HttpSolrClient.java:162) 
    at de.test.spring.SolrJConfig.solrClient(SolrJConfig.java:20) 
    at de.test.spring.SolrJConfig$$EnhancerBySpringCGLIB$$dbd4362f.CGLIB$solrClient$0(<generated>) 
    at de.test.spring.SolrJConfig$$EnhancerBySpringCGLIB$$dbd4362f$$FastClassBySpringCGLIB$$8e7566a6.invoke(<generated>) 
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) 
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309) 
    at de.test.spring.SolrJConfig$$EnhancerBySpringCGLIB$$dbd4362f.solrClient(<generated>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) 
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) 
    at de.test.WicketApplication.init(WicketApplication.java:32) 
    at org.apache.wicket.Application.initApplication(Application.java:950) 
    at org.apache.wicket.protocol.http.WicketFilter.init(WicketFilter.java:429) 
    at org.apache.wicket.protocol.http.WicketFilter.init(WicketFilter.java:353) 
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279) 
    at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:260) 
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:105) 
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4640) 
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5247) 
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) 
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:724) 
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:700) 
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:714) 
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:919) 
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1703) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 

Benim geçici çözümüm şu an için sorunu çözüyor, ama elbette bu sadece bir çözüm.

Bilmek istiyorum ve belki birisi Sorumu birini veya birkaçını yanıtlayabilir:

  1. bu "böcek" SolrJ, HttpClient, Java ya da benim uygulamada mı?
  2. Bu benim uygulamam durumunda, ne yapıyorum yanlış?
  3. Uygulamam değilse, bilinen bir sorun mu? Bununla ilgili hiçbir bilgi bulamıyorum. (Nerede) bir hata bileti oluşturmalıyım?
  4. Neden "geçersiz" sertifikası var mı? (BTW: Belki de bu sertifikayı güven deposundan kaldırırsam sızıntı da giderdi ... Test edemedim ama geçersiz veya hasarlı bir sertifikanın asla bir sınıf yükleyici sızıntısına yol açmaması gerektiğini düşünüyorum ...)
  5. Bu konuda biraz daha fazla bilgi var mı? Bu davranışı algılayan tek kişi olduğumu düşünemiyorum (bu benim görüşüm dışında ... soru 2'ye bakın).
Sonunda

ama en az benim Çevre çoğaltmak:

  • Tomcat Versiyon: Apache Tomcat/8.0.14 (Debian)
  • JVM Versiyon: 1.8.0_91-b14
  • JVM Satıcı: Oracle Corporation,
  • OS Adı: Linux
  • OS Sürümü: 3.16.0-4 amd64
  • Mimari: amd64
+0

arasında 4.2.1.7: Ben 'README için Solr sunucu ve anahtar deposu hakkında bazı bilgiler ekledik.GitHub'da md: https://github.com/CptS/solrj-classloader-leak#environment –

+0

GÜNCELLEME: Mattias Jiderhamn benim düşünceme göre bir java hatası olduğunu düşünüyor: https://github.com/mjiderhamn/classloader- sızıntı önleme/sorunlar/58 # issuecomment-252438440 –

+0

İlk bakışta bir JDK hatası gibi gelmiyor. Daha fazla değerlendirme için daha fazla bilgiye ihtiyacınız var. Anahtar deposundaki sertifika geçerliyse GC davranışı tekrarlanabilir mi? Performans için, SSLContext bazı güvenilir sertifikaları statik alanlarda önbelleğe alabilir. SSLContext'in ilk kez kullanımı için bellek kullanımı artabilir. Birden çok kez dağıtım/dağıtımdan kaldırmanın davranışı nedir? Örneğin, 10 kez 1-7/A-F yapın. –

cevap

0

Neden X.509 şartname takip etmeyen bir "geçersiz" sertifika

anahtar deposunda cert "Verenin Alternatif Adı" uzantısı değeri boş vardır. Bkz bölüm 4.2.1.6 ve sorunu yeniden isteyenler için RFC 5280.

$ keytool -exportcert ... -file ... 
$ keytool -printcert -v -file ... 
... 
#10: ObjectId: 2.5.29.18 Criticality=false 
Unparseable IssuerAlternativeName extension due to 
java.io.IOException: No data available in passed DER encoded value. 

0000: 30 00            0. 
+0

Evet, bunu anlıyorum. Sry, sorum yanlış yazılmıştı. Taze yüklü bir oracle jvm ve bir de (yeni yüklenmiş) tomcat ile yeni yüklü ve temiz bir debian. Hiçbir sertifikayı kendim yüklemedim. Bu nedenle geçersiz sertifika dağıtılmış bir paketten geliyor. Bu beni şaşırttı ve bu soruyla kastettiğim şey buydu. –