demoiselle / framework

Repositório principal contendo o Core e Extensions: JPA, Security, WS
https://demoiselle.org
127 stars 77 forks source link

Deadlock usando Wildfly 10.1.0.Final - Demoiselle 3.0.1 #118

Closed renalexster closed 6 years ago

renalexster commented 6 years ago

Configurações do Ambiente

Descrição do Problema

Meu servidor Wildfly está apresentando Threads consumindo 100% de CPU por conta de um problema que acredito fortemente ser de paralelismo (concorrência).

Fiz uma análise detalhada do servidor e encontrei Threads relacionadas ao demoiselle-security, especificamente CorsFilter.java e SecurityFilter.java travando o pool de Threads do parallelStream do Java (ForkJoinPool)

"ForkJoinPool.commonPool-worker-2" - Thread t@110
   java.lang.Thread.State: RUNNABLE
    at java.util.TreeMap.getEntryUsingComparator(TreeMap.java:374)
    at java.util.TreeMap.getEntry(TreeMap.java:343)
    at java.util.TreeMap.get(TreeMap.java:277)
    at org.jboss.resteasy.specimpl.MultivaluedTreeMap.get(MultivaluedTreeMap.java:185)
    at org.jboss.resteasy.specimpl.MultivaluedTreeMap.getOrCreate(MultivaluedTreeMap.java:71)
    at org.jboss.resteasy.specimpl.MultivaluedTreeMap.putSingle(MultivaluedTreeMap.java:64)
    at org.demoiselle.jee.security.filter.CorsFilter.lambda$filter$0(CorsFilter.java:54)
    at org.demoiselle.jee.security.filter.CorsFilter$$Lambda$320/884119018.accept(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1751)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
    at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.util.concurrent.ForkJoinPool$WorkQueue.localPopAndExec(ForkJoinPool.java:950)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1607)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)

O que acontece é que as classes CorsFilter.java e SecurityFilter.java do demoiselle-security utilizam o parallelStream para realizar um put em um Map do JAX-RS javax.ws.rs.container.ContainerResponseContext (ver imagem abaixo, linha 54, res.getHeaders().putSingle... )

corsfilter java

O grande problema é que a implementação do res.getHeader() do resteasy, utiliza um Map do tipo TreeMap (que não é thread-safe, https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html).

Portanto, o acesso concorrente no TreeMap está gerando em certo momento de saturação do sistema, um deadlock, causando CPU load muito alto e consequentemente perda de performance na aplicação.

Segue abaixo o print do status da JVM no momento do Lock, e o Thread dump (Full e apenas as Threads em Lock). Além da configuração detalhada do ambiente.

threads-jvm

overview-jvm

monitor-jvm

ThreadDump-FULL.txt ThreadsLOCK.txt

renalexster commented 6 years ago

Complementando a informação.

Eu realizei um teste baixando o código do demoiselle e alterei a parte do parallelStream para stream(), o servidor não apresentou problemas com essa implementação.

joaquimpedrooliveira commented 6 years ago

@renalexster , fiz um pull request com tua sugestão: #119

renalexster commented 6 years ago

Olá @joaquimpedrooliveira,

Alguma previsão de quando sai o novo release do demoiselle? E se essa alteração já vai estar presente?

Obrigado.

joaquimpedrooliveira commented 6 years ago

@renalexster, mandei o pull request mas não faço parte do time do Demoiselle. Acredito que o @botelhojp ou o @PauloGladson possam dar essa resposta.

botelhojp commented 6 years ago

Como o ajuste é bem pontual, vamos aceitar o pull request e gerar snapshot hoje. Fico aguardando avaliação para geração de versão final.

botelhojp commented 6 years ago

Gerada versão 3.0.3-SNAPSHOT. @renalexster, você poderia fazer a mesma avaliação de desempenho para essa versão?

renalexster commented 6 years ago

@botelhojp, Realizei o mesmo teste de carga de antes, usando JMeter e agora não tive problemas de CPU load.

posfix

Como se pode perceber na imagem, após o encerramento do teste, o CPU volta a ficar IDLE.

Obrigado.

renalexster commented 6 years ago

Olá @botelhojp,

Eu realizei o teste com o stream() e o servidor se comporta sem dead lock agora. Você sabe dizer se tem previsão de quando sai um novo release nos repositórios maven?

clovisjunior commented 6 years ago

Olá @renalexster ,

Foi gerado a release 3.0.3, você já pode atualizar o pom.xml do projeto.

https://oss.sonatype.org/content/repositories/releases/org/demoiselle/jee/demoiselle-core/3.0.3/

Vou encerrar essa issue, qualquer coisa reabrimos.