como lidar com bibliotecas compartilhadas para muitos aplicativos da Web usando as mesmas bibliotecas

Nós temos uma aplicação web feita em Java, que usa struts2, spring e JasperReport. Este aplicativo é executado no glassfish 4.0.

As bibliotecas do aplicativo estão na pasta WEB-INF / lib, e também no glassfish são instaladas 4 mais do que as mesmas bibliotecas.

Glassfish é configurado para usar 1024mb para heapspace e 512m para permgen, e a maior parte do consumo de memory quando eu uso bibliotecas por aplicativo está nas ações de struts e nas classs spring aop (usando o netbeans profiler).

O problema que estamos tendo é a quantidade de memory consumida por ter bibliotecas no carregador de class por aplicativo porque é alta e gera erros de PermGen e também notamos que o aplicativo é executado mais lentamente com mais usuários.

Por causa disso, tentamos usar bibliotecas compartilhadas, colocamos na pasta domain1 / lib e descobrimos que, com um único aplicativo implantado, o tempo de carregamento e o consumo de memory são muito menores, e o aplicativo funciona mais rápido em geral. Mas quando implantamos o restante dos aplicativos no servidor, apenas o primeiro aplicativo carregado funciona bem e o restante tem erros quando chamamos as ações do struts2. Acreditamos que isso ocorre porque cada aplicativo possui configurações ligeiramente diferentes em struts2 e log4j.

Nós também tentamos colocar apenas certas bibliotecas em glassfish e deixando apenas struts2 no aplicativo, mas ele mostra InvocationTargetException, porque todas as bibliotecas dependem da lib do apache-common e não importa se colocamos essas lib em um lugar ou outro. Além disso, se colocarmos em ambos os lugares, o aplicativo não será iniciado.

  1. Existe alguma configuração especial ou melhores práticas para o uso de bibliotecas compartilhadas?
  2. Existe uma maneira de usar bibliotecas compartilhadas, mas configurações de carga por aplicativo? ou nós temos que mudar as configurações para torná-las todas iguais?

Existe alguma configuração especial ou melhor prática para usar bibliotecas compartilhadas? Existe uma maneira de usar bibliotecas compartilhadas, mas configurações de carga por aplicativo? ou nós temos que mudar as configurações para torná-las todas iguais?

Estas são questões realmente interessantes … Eu não uso o GlassFish, mas, de acordo com a documentação :

Carregamento de Classe Específica da Aplicação

[…] Você pode especificar classs de biblioteca específicas de módulos ou aplicativos […] Use o comando asadmin deploy com a opção --libraries e especifique […]

Isolamento do Carregador de Classe de Circunvolução

Como cada aplicativo ou universo de carregador de classs de módulo implantado individualmente é isolado, um aplicativo ou módulo não pode carregar classs de outro aplicativo ou módulo. Isso impede que duas classs nomeadas de modo similar em diferentes aplicativos ou módulos interfiram umas nas outras.

Para contornar essa limitação de bibliotecas, classs de utilitário ou módulos implementados individualmente acessados ​​por mais de um aplicativo, você pode include o caminho relevante para as classs necessárias de uma das seguintes maneiras:

  • Usando o Common Class Loader
  • Compartilhando Bibliotecas em um Cluster
  • Empacotando o JAR do cliente para um aplicativo em outro aplicativo

Usando o Common Class Loader

Para utilizar o carregador de classs Common, copie os arquivos JAR no domain-dir/lib ou as-install/lib ou copie os arquivos .class (e outros arquivos necessários, como arquivos .properties) para o domain-dir/lib/classs , reinicie o servidor.

O uso do Common Class Loader torna um aplicativo ou módulo acessível a todos os aplicativos ou módulos implementados em servidores que compartilham a mesma configuração. No entanto, essa acessibilidade não se estende aos clientes do aplicativo. Para obter mais informações, consulte Usando bibliotecas com clientes de aplicativos. […]

Então eu tentaria:

Solução 1

  • colocar todas as bibliotecas, exceto Struts2 jars sob domain1/lib ,
  • colocar apenas flasks domain1/lib/applibs sob domain1/lib/applibs ,

então corra

 $ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp1.war $ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp2.war 

Para isolar o carregamento de classs das bibliotecas Struts2, mantendo o restante sob o controle do Common Classloader.

Solução 2

  • colocar todas as bibliotecas, exceto Struts2 jars sob domain1/lib ,
  • colocar apenas os flasks domain1/lib/applibs sob domain1/lib/applibs , em diferentes cópias com nomes diferentes, por exemplo, anexando o _appname nos nomes dos jar

então corra

 $ asadmin deploy --libraries struts2-core-2.3.15.2_FooApp1.jar FooApp1.war $ asadmin deploy --libraries struts2-core-2.3.15.2_FooApp2.jar FooApp2.war 

Para impedir o compartilhamento das bibliotecas, istantiating (mock) diferentes versões deles.

Espero que ajude, deixe-me saber se alguns dos trabalhos acima.

Eu apostaria que colocar as libs sob lib / ou lib / ext não resolveria seus problemas de desempenho. Você não escreveu nada sobre os aplicativos ou configurações do servidor, como tamanho do aplicativo, espaço Heap e PermGen disponível, mas mesmo assim eu recomendaria ficar com libs separadas por aplicativo.

Se você colocar as libs nos diretórios do servidor, elas serão compartilhadas entre todos os aplicativos. Você perderá a opção de atualizar apenas um dos seus aplicativos para um novo framework ou se livrar de qualquer um deles. Sua implantação será vinculada a uma arquitetura de servidor específica.

E você escreveu que não resolveu seus problemas, pode até criar novos.

Eu recomendaria investir algumas horas para ajustar o servidor. Se ele for executado com padrões, aloque mais PermGen e HeapSpace.

Se isso não ajudar, você deve analisar profundamente o que está errado. As bibliotecas compartilhadas podem ser uma solução, mas você ainda não conhece o problema. A IBM oferece algumas ferramentas legais e gratuitas para analisar os despejos de heap, isso pode ser um bom ponto de partida.

Você pode tentar criar o que é conhecido como WAR magro . Empacote todos os seus WARs dentro de um EAR e mova todos os JARs comuns de WEB-INF/lib para a pasta lib/ no EAR (não se esqueça de configurar no application.xml ).

Eu vim aqui em busca de orientação sobre a instalação de bibliotecas que são compartilhadas entre vários aplicativos ou projetos. Estou profundamente desapontado ao ler que a prática aceita favorece a instalação de uma cópia de cada biblioteca compartilhada em cada projeto. Portanto, se você tiver dez aplicativos Web, todos eles usam, por exemplo, httpcomponents-client, mysql-connector-java, etc., sua instalação contém dez cópias de cada.

Esse comportamento me lembra, dolorosamente, do modo de pensar que me motivou a abandonar o mainframe em favor do PC; o pensamento parecia ser “não me importa quantos resources meu aplicativo consome. De fato, gostaria de poder me gabar sobre o que é um recurso”. Com licença, por favor, enquanto eu vomito.

  • A interface exposta por uma biblioteca é um contrato imutável que não está sujeito a mudanças no capricho do desenvolvedor .

  • Existe esse conceito chamado compatibilidade com versões anteriores. Se você quebrá-lo, você cria uma nova interface.

Conheço pelo menos dois tipos de interfaces que aderem à letra e ao espírito dessas regras.

  1. De longe, a mais antiga são as bibliotecas do sistema IBM System / 370 . Você pode ter Foo e Foo2 , onde o último estende e / ou quebra o contrato feito pela interface Foo alguma forma que o torna incompatível.

  2. Desde o seu início no projeto Unix da Bell Labs, a biblioteca de tempo de execução C padrão aderiu às regras acima.

  3. Embora seja muito mais recente, a especificação da interface COM da Microsoft impõe a mesma regra.

Para seu crédito, a Microsoft geralmente também adota essas regras na API do Win32 , embora haja algumas exceções nessa API. Até certo ponto, eles retrocederam com o .NET Framework, que parece servilmente seguir os passos do ambiente Java que tão ansiosamente procura replace.

Eu tenho usado bibliotecas desde 1978, e meu entendimento era e é que o objective de colocar código em uma biblioteca era torná-lo reutilizável. Embora a manutenção de cópias do código da biblioteca em cada aplicativo elimine a necessidade de implementá-lo novamente para cada novo projeto, isso complica seriamente a atualização, pois agora você tem dez (ou mais) cópias da biblioteca, cada uma das quais deve ser atualizada.

Se as bibliotecas aderirem à regra de que uma interface é um contrato imutável, por que não deveriam viver em um diretório de biblioteca compartilhada , assim como as bibliotecas do sistema Unix que vivem em seu diretório /lib , a partir do qual tudo que é executado no host compartilha uma cópia única da biblioteca de tempo de execução C padrão, Zlib e assim por diante.

Colora-me seriamente desapontado.

Intereting Posts