Configuração do threadpool JRun

1

Eu e minha equipe lutamos para manter estável o aplicativo ColdFusion em cluster durante a maior parte dos últimos 6 meses, com poucos resultados. Estamos nos voltando para SF na esperança de encontrar alguns especialistas JRun ou novas idéias porque não conseguimos descobrir isso.

A configuração:
Duas instâncias do ColdFusion 7.0.2 em cluster com o JRun 4 (com a atualização mais recente) no IIS 6 no Windows Server 2003. Duas CPUs quad core, 8 GB de RAM.

A questão:
De vez em quando, geralmente uma vez por semana, uma das instâncias parará completamente de atender à solicitação. Não há nenhuma atividade nele e precisamos reiniciá-lo.

O que sabemos:
Toda vez que isso acontece, o log de erros do JRun está sempre cheio de java.lang.OutOfMemoryError: não é possível criar um novo thread nativo.

Depois de ler a documentação do JRun da Macromedia / Adobe e muitas postagens de blog confusas, reduzimos o número para configurações de pool de threads JRun incorretas / não otimizadas no jrun.xml da instância.

Parte relevante do nosso jrun.xml:

<service class="jrun.servlet.jrpp.JRunProxyService" name="ProxyService">
    <attribute name="activeHandlerThreads">500</attribute>
    <attribute name="backlog">500</attribute>
    <attribute name="deactivated">false</attribute>
    <attribute name="interface">*</attribute>
    <attribute name="maxHandlerThreads">1000</attribute>
    <attribute name="minHandlerThreads">1</attribute>
    <attribute name="port">51003</attribute>
    <attribute name="threadWaitTimeout">300</attribute>
    <attribute name="timeout">300</attribute>
{snip}  
</service>

Eu habilitei o registro de métricas do JRun na semana passada para coletar dados relacionados aos encadeamentos. Este é um resumo dos dados depois de deixá-lo registrar por uma semana.

Valores médios:

{jrpp.listenTh}       1
{jrpp.idleTh}         9
{jrpp.delayTh}        0
{jrpp.busyTh}         0
{jrpp.totalTh}       10
{jrpp.delayRq}        0
{jrpp.droppedRq}      0
{jrpp.handledRq}      4
{jrpp.handledMs}   6036
{jrpp.delayMs}        0
{freeMemory}      48667
{totalMemory}    403598
{sessions}          737
{sessionsInMem}     737

Valores máximos:

{jrpp.listenTh}       10
{jrpp.idleTh}         94
{jrpp.delayTh}         1
{jrpp.busyTh}         39
{jrpp.totalTh}       100
{jrpp.delayRq}         0
{jrpp.droppedRq}       0
{jrpp.handledRq}      87
{jrpp.handledMs}  508845
{jrpp.delayMs}         0
{freeMemory}      169313
{totalMemory}     578432
{sessions}          2297
{sessionsInMem}     2297

Alguma idéia do que poderíamos experimentar agora?

Felicidades!

EDIT # 1 - > Coisas que esqueci de mencionar: Windows Server 2003 Enterprise com JVM 1.4.2 (para JRun)

O tamanho máximo do heap é de aproximadamente 1,4 GB. Nós costumávamos ter vazamentos, mas nós os consertamos, agora o aplicativo usa em torno de 400MB, raramente mais. O tamanho de heap máximo é definido como 1200 MB, portanto, não o atingimos. Quando tivemos vazamentos, a JVM acabou de explodir e a instância foi reiniciada. Isso não está acontecendo agora, ele simplesmente pára de lidar com o pedido recebido.

Estávamos pensando que isso tem a ver com o tópico seguinte a esta postagem do blog: link

A exceção Java que está sendo lançada é do tipo OutOfMemory, mas na verdade não está dizendo que ficamos sem espaço no heap, apenas que não foi possível criar novos threads. O tipo de exceção é um pouco enganador.

Basicamente, o blog está dizendo que 500HandlerThreads ativos podem ser muito altos, mas minhas métricas parecem mostrar que não chegamos perto daquilo que está nos confundindo.

    
por jfrobishow 01.12.2009 / 16:44

2 respostas

3

Bem, vamos analisar alguns problemas de imagem maiores antes de entrar nos detalhes de configuração do JRun.

Se você está recebendo exceções java.lang.OutOfMemoryError no log de erros do JRun, bem, você está sem memória. Não há upvote para isso, por favor ;-). Você não disse se estava executando o Windows de 32 ou 64 bits, mas disse que tem 8 GB de RAM, o que terá algum impacto em uma resposta. Se você está ou não executando uma JVM de 32 ou 64 bits (e qual versão) também afetará as coisas. Então, essas são algumas respostas que nos ajudarão a chegar ao fundo disso.

Independentemente disso, seu aplicativo está ficando sem memória. Está ficando sem memória por um ou mais desses motivos:

  1. Seu aplicativo está com vazamento de memória. Alguns objetos usados pelo seu aplicativo são continuamente referenciados e, portanto, nunca qualificados para coleta de lixo; ou pior, algum objeto criado novo em cada solicitação é referenciado por outro objeto em perpetuidade e, portanto, nunca é elegível para coleta de lixo. A manipulação correta de sessões do J2EE pode ser particularmente complicada a esse respeito.
  2. A quantidade de memória necessária para manipular cada solicitação simultânea (no nível de solicitação simultânea configurado) excede a quantidade de memória disponível no heap da JVM. Por exemplo, você tem um tamanho de heap de 1 GB e cada solicitação pode usar até 10 MB. Seu servidor de aplicativos é ajustado para permitir 150 solicitações simultâneas. (Números simplistas, eu sei). Nesse caso, você definitivamente ficaria sem memória se tivesse 100 ou mais solicitações simultâneas sob carga (se cada solicitação utilizasse a quantidade máxima de memória necessária para atender à solicitação).

Outras coisas a serem lembradas: no Windows de 32 bits, uma JVM de 32 bits só pode alocar aproximadamente 1,4 GB de memória. Não me lembro de tudo, se uma JVM de 32 bits no Windows de 64 bits tiver uma limitação menor que o máximo teórico de 4 GB para qualquer processo de 32 bits.

ATUALIZADO

Eu li a postagem do blog vinculada via TalkingTree e a outra postagem vinculada a esse post também. Não corri para este caso exato, mas tive a seguinte observação: o registro de métricas do JRUN pode não registrar os "valores máximos" citados em um período de pico de uso do encadeamento. Acho que registra as métricas em um intervalo fixo e recorrente. Isso é bom para mostrar as características de desempenho médio do aplicativo, mas pode não capturar o estado do JRUN antes que a condição de erro comece a ocorrer.

Sem saber sobre o funcionamento interno do gerenciamento de threads do JRUN, eu ainda digo que ele realmente está sem memória. Talvez ele não esteja sem memória porque seu aplicativo precisou alocar memória no heap da JVM e nenhum estava disponível, mas está sem memória porque o JRUN tentou criar outro encadeamento para manipular uma solicitação recebida e a memória heap necessária para suportar outro encadeamento. t disponível - em outras palavras, os threads não são gratuitos - eles também exigem memória heap.

Suas opções parecem ser as seguintes:

  1. Reduza a quantidade de memória que seu aplicativo usa em cada solicitação ou -
  2. Reduza experimentalmente o valor dos parâmetros de ajuste de encadeamento na configuração do JRUN para tornar mais encadeamentos na fila para processamento em vez de se tornarem executáveis ao mesmo tempo, ou -
  3. Reduza o número de solicitações simultâneas no administrador do ColdFusion (página Solicitação de ajuste, campo "Número máximo de solicitações simultâneas de modelos")
Independentemente da opção que você escolher, acho que uma correção válida aqui será de natureza experimental. Você vai ter que fazer uma mudança e ver o que afeta o aplicativo. Você tem um ambiente de teste de carga, certo?

    
por 03.12.2009 / 20:09
0

Experimente e reduza o tamanho máximo de heap. Cada thread requer recursos nativos (junto com o próprio material do java). O AS virtual utilizável é de 2 GB; 1.2GB é reservado para o heap. Parte dos 800MB restantes é usada para código (segmentos de texto de java e todas as DLLs necessárias), então há alocações nativas requeridas pelo JRE e suas dependências ... e os encadeamentos: para cada encadeamento por padrão, 1MB de AS é reservado ( embora apenas uma página esteja realmente comprometida), 100 threads = 100MB (apenas para as pilhas). Agora adicione um pouco de espaço extra entre as várias partes, alguma fragmentação ... OOM; -)

    
por 04.12.2009 / 23:32