Tomcat webapps comendo toda a memória

1

Estou executando alguns servidores tomcat nos quais implementamos aplicativos que nossos codificadores criam e implementam. O problema é que em alguns de nossos servidores, especialmente os que têm várias solicitações, a memória fica cheia muito rapidamente e o servidor começa a funcionar mal, se é que o faz. Eu sou novo para este papel e meu antecessor menciona isso é devido ao código nos aplicativos não está sendo escrito corretamente que ele come toda a memória até ... o que é justo, mas eu estou querendo saber se há algo que eu possa fazer para mitigar ou eliminar isso como atualmente a solução implementada até que o código seja melhorado é várias reinicializações tomcat semanais, que na minha opinião parece um exagero! (sem trocadilhos)

Abaixo está a saída do htop antes que o tomcat precise ser eliminado e reiniciado (e isso é outra coisa, na maioria das vezes não se pode pedir ao tomcat para sair educadamente, você deve eliminá-lo -9, não tenho certeza se isso é normal)

Eu verifiquei alguns recursos , mas não consegui encontrar nada específico que pudesse classificar meu problema assim, qualquer bom conhecimento seria bem-vindo!

Eu incluí uma imagem, como você pode ver o processo parece ser repetido várias vezes, mas não está usando mais de 300 GB de memória, como algumas pessoas têm dito, mas apenas 7 shows, não toda a certeza do que isso significa.

Na verdade, pode ser um problema com o htop, como se você fizesse um ps, você só pode ver o processo abaixo:

root 5215 3.4 64.8 8310716 5301436 ? Sl Nov04 146:25 /usr/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.awt.headless=true -Xms5G -Xmx5G -XX:PermSize=512m -XX:MaxPermSize=512m -XX:NewSize=1G -XX:MaxNewSize=1G -Duser.langua

De qualquer forma para voltar ao meu ponto, fica sobrecarregado muito fácil, alguma maneira de evitar isso no Tomcat versão 7.0.28?

Aqui está o server.xml

<?xml version='1.0' encoding='utf-8'?>
<Server port="8105" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>


    <Environment name="databasePlaceHolder" type="java.lang.String" value="com_xxx_yyy_au"/>
    <Environment name="com.xxx.databasename" type="java.lang.String" value="com_xxx_yyy_au"/>
    <Environment name="com.xxx.JMS.url" type="java.lang.String" value="tcp://localhost:61616"/>
    <Environment name="remoteServerURL" type="java.lang.String" value="https://yyy.xxx.com/"/>

    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">

    <Connector port="8109" protocol="AJP/1.3" redirectPort="0443" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

Este é o conteúdo do arquivo setenv.sh:

JAVA_OPTS="- Djava.awt.headless = true -Xms5G -Xmx5G -XX: PermSize = 512m -XX: MaxPermSize = 512m -XX: NewSize = 1G -XX: MaxNewSize = 1G -Duser.language = pt -Dusador .region = GB "

JAVA_OPTS="$ {JAVA_OPTS} -XX: + UseParallelGC -XX: + PrintGCDetalhes -XX: + PrintGCDateStamps -XX: + PrintTenuringDistribution"

Esta é a saída do htop, provavelmente está errada

    
por Ulukai 06.11.2015 / 01:13

2 respostas

0

Quanto ao htop estar errado, acho que você ativou as informações do thread, assim, cada entrada do java que você vê é um thread do mesmo processo. Para verificar isso, alterne "mostrar segmentos" (pressione "H" para alternar).

A partir da captura de tela htop, percebo que seu servidor tem 8G de RAM, portanto, se você tiver limitado a JVM a 5G + PermGen + alguma sobrecarga, deverá estar ok, supondo que não haja outros processos com fome de memória em execução.

A próxima coisa a verificar é o coletor de lixo, dependendo da sua versão do java, há um sinalizador (pelo menos no oracle java / openjdk) que faz a JVM registrar cada evento do GC, geralmente: -verbose:gc -XX:+PrintGCDateStamps -Xloggc:SOMEFILENAME e até mesmo aumentando Atividade de GC, em caso de vazamento de memória, você verá a coleta de lixo se tornando mais frequente à medida que o tempo passa, até usar toda a CPU tentando liberar memória sem sucesso, e você pode obter exceções de memória em seus logs. Nesse ponto, você tem que kill -9 do aplicativo para o seu problema. Mas agora você terá um log da atividade post-mortem do GC para provar que há vazamentos de memória ou não.

Em seguida, se você tiver mais de um aplicativo implantado, tente dividir os aplicativos em uma única instância do tomcat, se possível. Ou ative o dump de pilha em memória insuficiente.

Assim como o que fazer sem a possibilidade de consertar o código, supondo que haja memória de alho-poró configurando um monitoramento na freqüência de GC, por exemplo, se houver 3 tentativas completas de GC em um minuto, reinicie o tomcat automaticamente.

Feio, mas se não houver outras opções, você pode dormir à noite.

    
por 07.11.2015 / 18:57
0

Como não vejo os argumentos de linha de comando completos usados para iniciar a JVM e não saber a natureza dos aplicativos que você implantou lá, só posso imaginar que seus aplicativos estão criando muitos objetos 'de longa duração' que fazem seu caminho para o espaço oldgen e você está ficando sem memória lá. Além disso, a coleta de GC no espaço oldgen é bastante cara e, possivelmente, a sua JVM em algum momento não consegue acompanhar as execuções do GC e chegar a um impasse.

Dito isto, posso sugerir os seguintes parâmetros de ajuste da JVM.

Remova os dois abaixo:

-XX:NewSize=1G 
-XX:MaxNewSize=1G

E adicione o seguinte:

-XX:+UseParallelOldGC
-XX:SurvivorRatio=10
-XX:NewRatio=2

Se o problema não for resolvido, continue aumentando o NewRatio para 3, 4, 5 e veja quando a JVM está estável o suficiente para continuar executando sem qualquer problema. Além disso, não sei por que você precisaria de 512M de tamanho de permgen, ou seja, -XX:PermSize=512m . Consulte os desenvolvedores do seu aplicativo para ver se eles realmente precisam disso e reduzi-lo, se possível.

Além disso, quando o problema acontecer, antes de você matar o processo, execute o seguinte e poste a saída aqui que dará pistas para as pessoas que estão tentando ajudá-lo aqui. (nota: você tem que correr como root).

jmap -heap <pid_of_jvm>

PS: A saída htop, conforme explicada por @Fredi está correta, identificou erroneamente IDs de encadeamento LWP como PIDs.

    
por 07.11.2015 / 22:12

Tags