Lançamento de Tomcat 8 - org.apache.catalina.webresources.Cache.getResource Não é possível adicionar o recurso

111

Acabei de atualizar o Tomcat da versão 7.0.52 para 8.0.14.

Estou recebendo isso para muitos arquivos de imagem estática:

org.apache.catalina.webresources.Cache.getResource Não é possível adicionar o recurso em [/base/1325/WA6144-150x112.jpg] ao cache porque não havia espaço livre suficiente disponível após a remoção de entradas de cache expiradas - considere aumentar o tamanho máximo do cache

Não especifiquei nenhuma configuração de recurso particular e não recebi isso para o 7.0.52.

Eu encontrei menção a isso na inicialização em um relatório de bug que supostamente foi corrigido. Para mim, isso não está acontecendo na inicialização, mas constantemente quando o recurso é solicitado.

Alguém mais tendo este problema?

Tentando pelo menos desabilitar o cache, mas não consigo encontrar um exemplo de como especificar para não usar o cache. Os atributos foram retirados do contexto do Tomcat versão 8. Tentei adicionar um recurso, mas não consigo obter a configuração correta.

<Resource name="file" 
    cachingAllowed="false"
    className="org.apache.catalina.webresources.FileResourceSet"
/>  

Obrigado.

iainmac999
fonte
Sem respostas - acho que devo ser a única pessoa com esse problema.
iainmac999
2
A solução está aqui: serverfault.com/questions/644415/…
Dmitry
1
Em relação ao atributo ausente no contexto do Tomcat 8, aqui está um trecho do guia de migração (ênfase minha): " A refatoração de recursos também resultou na remoção de vários atributos da implementação do Contexto padrão (org.apache.catalina.core .StandardContext). Os seguintes atributos agora podem ser configurados através da implementação de recursos usados ​​pela aplicação web ". Mais informações no guia de migração relacionado .
informatik01
@ iainmac999 nunca tendo selecionado uma resposta correta após 2 anos, podemos concordar que funciona nos dois sentidos?
davidjmcclelland

Respostas:

161

Em seu $CATALINA_BASE/conf/context.xmlbloco de adição abaixo antes</Context>

<Resources cachingAllowed="true" cacheMaxSize="100000" />

Para obter mais informações: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Destroyica
fonte
11
Leitores individuais provavelmente desejarão ajustar esse valor cacheMaxSize para algo menos que 100 megas.
Eric Spiegelberg
até agora, a mensagem de erro estava inundando os logs do meu console. Agora está claro. Obrigado
Abubacker Siddik
152

Tive o mesmo problema ao atualizar do Tomcat 7 para o 8: uma grande inundação contínua de avisos de log sobre o cache.

1. Resposta curta

Adicione-o ao Contextelemento xml do seu $CATALINA_BASE/conf/context.xml:

<!-- The default value is 10240 kbytes, even when not added to context.xml.
So increase it high enough, until the problem disappears, for example set it to 
a value 5 times as high: 51200. -->
<Resources cacheMaxSize="51200" />

Portanto, o padrão é 10240(10 mbyte), então defina um tamanho maior do que isso. Em seguida, ajuste as configurações ideais onde os avisos desaparecem. Observe que os avisos podem voltar em situações de tráfego intenso.

1.1 A causa (breve explicação)

O problema é causado pelo fato de o Tomcat não conseguir atingir seu tamanho de cache de destino devido às entradas de cache que são menores que o TTL dessas entradas. Portanto, o Tomcat não tinha entradas de cache suficientes para que pudesse expirar, porque eram muito recentes, de modo que não poderia liberar cache suficiente e, portanto, gera avisos.

O problema não apareceu no Tomcat 7 porque o Tomcat 7 simplesmente não emitia avisos nessa situação. (Fazendo você e eu usarmos configurações de cache insatisfatórias sem sermos notificados.)

O problema aparece ao receber uma quantidade relativamente grande de solicitações HTTP para recursos (geralmente estáticos) em um período de tempo relativamente curto em comparação com o tamanho e o TTL do cache. Se o cache estiver atingindo seu máximo (10 MB por padrão) com mais de 95% de seu tamanho com novas entradas de cache (novo significa menos de 5 segundos no cache), você receberá uma mensagem de aviso para cada recurso da web que o Tomcat tenta para carregar no cache.

1.2 Informação opcional

Use JMX se precisar ajustar cacheMaxSize em um servidor em execução sem reiniciá-lo.

A correção mais rápida seria desabilitar completamente o cache <Resources cachingAllowed="false" />:, mas isso está abaixo do ideal, então aumente cacheMaxSize como acabei de descrever.

2. Resposta longa

2.1 Informações básicas

Um WebSource é um arquivo ou diretório em um aplicativo da web. Por motivos de desempenho, o Tomcat pode armazenar WebSources em cache. O máximo do cache de recursos estáticos (todos os recursos no total) é, por padrão, 10240 kbyte (10 mbyte). Um webResource é carregado no cache quando o webResource é solicitado (por exemplo, ao carregar uma imagem estática) e é então chamado de entrada de cache. Cada entrada de cache possui um TTL (tempo de vida), que é o tempo que a entrada de cache pode permanecer no cache. Quando o TTL expira, a entrada do cache é elegível para ser removida do cache. O valor padrão do cacheTTL é 5000 milissegundos (5 segundos).

Há mais informações sobre o cache, mas isso é irrelevante para o problema.

2.2 A causa

O código a seguir da classe Cache mostra a política de cache em detalhes:

152   // O conteúdo não será armazenado em cache, mas ainda precisamos do tamanho dos metadados 
153 long delta = cacheEntry. getSize (); Tamanho
154 . addAndGet (delta);
156 if (size. Get ()> maxSize) {
157 // Processar recursos não ordenados para velocidade. Trades cache
158 // eficiência (entradas mais novas podem ser removidas antes das
159 // mais antigas ) para velocidade, uma vez que este é o caminho crítico para
160 // processamento de solicitação
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 longo newSize = despejar (
164 . TargetSize, resourceCache valores (). Iteração ());
165 if (newSize> maxSize) {
166 // Não é possível criar espaço suficiente para este recurso
167 // Remova-o do cache
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", caminho));
170 }
171 }

Ao carregar um webResource, o código calcula o novo tamanho do cache. Se o tamanho calculado for maior do que o tamanho máximo padrão, uma ou mais entradas em cache devem ser removidas, caso contrário, o novo tamanho excederá o máximo. Assim, o código calculará um "targetSize", que é o tamanho que o cache deseja manter (como ideal), que é por padrão 95% do máximo. Para alcançar este targetSize, as entradas devem ser removidas / removidas do cache. Isso é feito usando o seguinte código:

215   despejo longo privado  ( long targetSize, Iterator < CachedResource > iter) { 217 long now = System. currentTimeMillis (); 219 longo newSize = size. get (); 221 while (newSize> targetSize && iter. HasNext ()) { 222 CachedResource resource = iter. próximo (); 224           // Não expira nada que foi verificado no TTL 225 if (resource. GetNextCheck ()> now) { 226






continue ;
227 }
229 // Remova a entrada do cache
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = size. get ();
233 }
235 retornar novoTamanho;
236 }

Portanto, uma entrada de cache é removida quando seu TTL expira e o targetSize ainda não foi alcançado.

Após a tentativa de liberar o cache removendo as entradas do cache, o código fará:

165   if (newSize> maxSize) { 
166 // Não é possível criar espaço suficiente para este recurso
167 // Remova-o do cache
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", caminho));
170 }

Portanto, se após a tentativa de liberar o cache, o tamanho ainda ultrapassar o máximo, será exibida a mensagem de aviso sobre a impossibilidade de liberar:

cache.addFail=Unable to add the resource at [{0}] to the cache for web application [{1}] because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache

2.3 O problema

Como diz a mensagem de aviso, o problema é

espaço livre insuficiente disponível após a remoção de entradas de cache expiradas - considere aumentar o tamanho máximo do cache

Se o seu aplicativo da web carregar muitos webResources não armazenados em cache (no máximo de cache, por padrão 10 MB) em um curto período (5 segundos), você receberá o aviso.

A parte confusa é que o Tomcat 7 não mostrou o aviso. Isso é causado simplesmente por este código Tomcat 7:

1606   // Adicionar nova entrada ao cache 
1607 synchronized (cache) {
1608 // Verificar o tamanho do cache e remover elementos se forem muito grandes
1609 if ((cache. Lookup (name) == null ) && cache. Alocar (entry.size) ) {
1610 cache. carregar (entrada);
1611 }
1612 }

combinado com:

231   while (toFree> 0) { 
232 if (tentativas == maxAllocateIterations) {
233 // Desista, nenhuma mudança é feita no cache atual
234 return false ;
235 }

Portanto, o Tomcat 7 simplesmente não exibe nenhum aviso quando não consegue liberar o cache, enquanto o Tomcat 8 exibe um aviso.

Portanto, se você estiver usando o Tomcat 8 com a mesma configuração de cache padrão do Tomcat 7 e recebeu avisos no Tomcat 8, então suas (e minhas) configurações de cache do Tomcat 7 estavam funcionando mal sem aviso.

2.4 Soluções

Existem várias soluções:

  1. Aumentar o cache (recomendado)
  2. Diminua o TTL (não recomendado)
  3. Suprimir avisos de log de cache (não recomendado)
  4. Desativar cache

2.4.1. Aumentar o cache (recomendado)

Conforme descrito aqui: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Adicionando <Resources cacheMaxSize="XXXXX" />dentro do Contextelemento em $CATALINA_BASE/conf/context.xml, onde "XXXXX" representa um tamanho de cache aumentado, especificado em kbytes. O padrão é 10240 (10 mbyte), então defina um tamanho maior do que isso.

Você terá que ajustar para configurações ideais. Observe que o problema pode voltar quando, de repente, houver um aumento nas solicitações de tráfego / recursos.

Para evitar ter que reiniciar o servidor toda vez que você quiser tentar um novo tamanho de cache, você pode alterá-lo sem reiniciar usando JMX.

Para habilitar JMX , adicionar isso para $CATALINA_BASE/conf/server.xmldentro do Serverelemento: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />e descarga catalina-jmx-remote.jarde https://tomcat.apache.org/download-80.cgi e colocá-lo em $CATALINA_HOME/lib. Em seguida, use o jConsole (fornecido por padrão com o Java JDK) para se conectar por JMX ao servidor e verifique as configurações para aumentar o tamanho do cache enquanto o servidor está em execução. As alterações nessas configurações devem entrar em vigor imediatamente.

2.4.2. Diminua o TTL (não recomendado)

Diminua o cacheTtlvalor em um valor inferior a 5000 milissegundos e ajuste para obter as configurações ideais.

Por exemplo: <Resources cacheTtl="2000" />

Isso se resume a ter e preencher um cache na memória RAM sem usá-lo.

2.4.3. Suprimir avisos de log de cache (não recomendado)

Configure o log para desabilitar o logger org.apache.catalina.webresources.Cache.

Para obter mais informações sobre como fazer login no Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html

2.4.4. Desativar cache

Você pode desativar o cache configurando cachingAllowedpara false. <Resources cachingAllowed="false" />

Embora eu possa me lembrar que em uma versão beta do Tomcat 8, eu estava usando JMX para desabilitar o cache. (Não sei exatamente por que, mas pode haver um problema com a desativação do cache via server.xml.)

Devabc
fonte
Aumentar o cache? Duvido que funcione ... Eu vi isso: private long maxSize = 10 * 1024 * 1024; na fonte. grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
HoaPhan
você encontrou a resposta de porque tomcat8 está inundando avisos de cache
PHP Avenger
@HoaPhan 10 * 1024 * 1024 é um máximo de 10 MB para todo o cache no total. Dependendo do tráfego do webapp, isso pode ser alcançado em segundos. Aumentar o suficiente funcionará.
Devabc de
@PHPAvenger Tomcat 7 não avisou nada nesta situação, enquanto o Tomcat 8 sim, então pode ser visto como um recurso de aviso. O problema é que ele avisa não apenas uma vez, mas a cada solicitação de recurso para o cache. Seria uma melhoria avisar apenas após um determinado período de tempo ou acertos do alvo do cache.
Devabc de
@Devabc resposta perfeita! Um TÃO clássico!
gaurav de
9

Você tem mais recursos estáticos para os quais o cache tem espaço. Você pode fazer o seguinte:

  • Aumente o tamanho do cache
  • Diminua o TTL para o cache
  • Desativar cache

Para obter mais detalhes, consulte a documentação dessas opções de configuração.

Mark Thomas
fonte
1
Obrigado pelo comentário. Eu entendo o significado da exceção e é claro que li a documentação que você vinculou, no entanto, não entendo por que isso mudaria de 7 para 8 sem alterações de configuração. Ou seja, por que o manipulador de recursos do sistema de arquivos padrão seria diferente em 8 para 7, sem referência a qualquer alteração, e é suspeito que um bug de inicialização foi relatado e supostamente corrigido.
iainmac999 de
1
Talvez se você tivesse lido o guia de migração - especificamente tomcat.apache.org/migration-8.html#Web_application_resources - as coisas ficariam mais claras.
Mark Thomas
Ajudaria se a documentação fizesse um pouco mais para a) explicar quais recursos vão para esse cache e por quê (muitos mal-entendidos são abundantes sobre isso!) Eb) qual impacto as diferentes configurações podem ter (por exemplo, apenas criar cegamente a configuração de cache de cada webapp bastante grande pode consumir uma tonelada de memória) e como ajustá-la corretamente. Também ajudaria se houvesse uma distinção no código e na configuração entre o armazenamento em cache de recursos estáticos usados ​​pelo próprio aplicativo e os arquivos estáticos solicitados por agentes de usuário e meramente entregues pelo aplicativo.
Volkerk
4

Isso não é uma solução no sentido de que não resolve as condições que fazem com que a mensagem apareça nos registros, mas a mensagem pode ser suprimida anexando o seguinte a conf/logging.properties:

org.apache.catalina.webresources.Cache.level = SEVERE

Isso filtra os logs “Não foi possível adicionar o recurso”, que estão no nível WARNING.

Em minha opinião, a WARNINGnão é necessariamente um erro que precisa ser corrigido, mas pode ser ignorado, se desejado.

Geoffrey Booth
fonte
8
Haha. isso não resolve o problema. Simplesmente não mostra isso. WTF!
T3rm1 de
Isso resolve o problema da extração excessiva de madeira, que pode ser um problema significativo por si só. Ele retorna ao comportamento das versões anteriores do tomcat, onde as coisas funcionavam suficientemente bem para muitos, portanto, nesse sentido, ele "resolve" o problema. Ele não resolve o problema de realmente ajustar o cache do tomcat, que a resposta do devabc cobre muito bem.
volkerk