Olá,
possuo uma aplicação WEB rodando em Weblogic (6.x).
É uma aplicação bem simples que recebe requests XML, executa o serviço necessário (Oracle ou Tuxedo) e finalmente retorna XML.
Para cada request feito, precisamos fazer duas consultas no banco de dados para autenticar o usuário que está fazendo o request e para verificar se o serviço está disponível.
Nossa meta é colocar esses dados em Cache e evitar ir ao Oracle a cada request. Esse Cache precisaria ser atualizado de X em X minutos.
Qual a melhor maneira de se fazer isso?
Obrigado,
Marco Campelo
Cache
18 Respostas
Tente o OSCache.
Ele tem tags pra cache dinamico em servidor web (servlets e JSP) e uma API muito boa (seu caso) pra integrar com aplicações … muito boa mesmo.
[]s
Obrigado, smota.
Vou testar o OSCache e depois posto aqui se resolveu meu problema.
Abraços
Usa o coherence, esse sim é cache de verdade.
Não resolve usar o próprio Oracle Web Cache?
eheheh é, isso é verdade, se você quiser gastar uma graninha (começa em $1,995 USD) ele deve servir.
Nunca usei mas ouço falar muuuuuuuuito bem dele.
Hmm… vc ja chegou a testar o Coherence, louds?
Vi que uma das soluções é cara e outra (não cheguei a verificar se era free ou não) só teria suporte a partir do Weblogic 7.x.
Resolvi meu problema colocando um objeto como variável de instância da servlet.
Esse objeto é criado no init() e fica disponível para todos os requests posteriores.
Resolveu meu problema perfeitamente.
Gostaria da sugestão de vocês de como atualizar esse objeto de tempos em tempos.
É possível utilizar TimerTask dentro de uma Servlet?
Crie um Agente (Thread) que faça isso.
Já fiz uns testes em casa e na faculdade. É realmente muito bom, escala muito bem pra clusters pequenos; digo isso baseado no fato que em lugar algum eu achei como configurar o coherence de acordo com a topologia do cluster.
O único problema mesmo é o preço, $ 5000/cpu a versão enterprise, isso para uma instalação grande pode representar um custo astronomico. Como referencia, um dell power edge quad xeon 2ghz sai por menos de $20k.
Como disse anteriormente, resolvi o problema do cache utilizando uma variavel de instancia na Servlet.
Para fazer as atualizacoes do Cache de tempos em tempos, utilizei as classes Timer e TimerTask.
Esta tudo funcionando corretamente, mas verifiquei que de X em X minutos a chamada ao DAO para atualizar o cache acontece 3 vezes.
Pelo que entendi, cada Thread da Servlet faz uma chamada para fazer sua própria atualização.
Tem como contornar isso?
Uma thread à parte.
Seu problema é que o container pode criar quantas instancias do seu servlet ele quiser.
Não use uma variavel de instancia, use uma no ServletContext.
Ai basta coordenar entre as várias threads a atualização do cache.
Algo +/- assim:
public abstract class SimpleCache {
private boolean updating = false;
private Object obj;
private long expire;
static final long TTL = 5 * 60 * 1000;
public SimpleCache() {
expire = System.currentTimeMillis() + TTL;
obj = load();
}
protected abstract Object load();
public Object get() {
synchronized(this) {
//expirou?
if(System.currentTimeMillis() >= expire) {
//já tem alguma thread carregando?
if(updating)
return obj;
updating = true;
} else {
return obj;
}
}
Object tmp = load();
synchronized(this) {
obj = tmp;
updating = false;
expire = System.currentTimeMillis() + TTL;
}
return tmp;
}
}
Bastaria voce subclassear, implementar load() e colocar 1 instancia dessa classe no teu context.
A menos que vc esteja usando um Servlet SingleThreadModel, ou saiba bem MESMO o que vc esta fazendo, isso eh uma pessima ideia, uma vez que o servidor de aplicacoes usa um pool de threads para os requests (ou seja, o seu Servlet pode estar servindo zilhoes de clientes exatamente ao mesmo tempo).
A menos que vc esteja usando um Servlet SingleThreadModel, ou saiba bem MESMO o que vc esta fazendo, isso eh uma pessima ideia, uma vez que o servidor de aplicacoes usa um pool de threads para os requests (ou seja, o seu Servlet pode estar servindo zilhoes de clientes exatamente ao mesmo tempo).
Não há problema, pois os dados em Cache não são específicos de um usuário. São dados comuns a qualquer request. O objetivo é deixar essas informações disponíveis para qualquer usuário. O fato da Servlet servir a zilhões de clientes não é um problema.
O problema é o fato do Update estar rodando X vezes de acordo com o número de threads em execução.
Situação atual:
Criei uma classe Cache implementando o pattern Singleton.
Na minha servlet, tenho uma variável de instancia:
private volatile Cache cache;
No init() da Servlet, faço um:
cache = Cache.getInstance();
Dentro do construtor da classe Cache, estou utilizando Timer e TimerTask para fazer acesso ao banco de dados de X em X minutos e atualizar o Cache em memória.
Mesmo utilizando Singleton, continuo com o problema de várias Threads fazendo atualização do Cache.
Alguma sugestão?
Tem alguma coisa muito estranha ai
Pq Timer cria 1 thread propria para executar as TimerTasks.
Quer 1 sugestão?
No teu DAO logue um stacktrace no método que carrega os dados. Ai voce vai poder saber de onde as chamas estão ocorrendo.
Apenas para fechar o tópico, cheguei a uma solução para o problema.
Mesmo implementando a classe Cache como um Singleton, meu application server (em algumas situações) estava criando várias threads.
Descobri que quando eu dava um undeploy na aplicação, a thread do Cache continuava rodando.
Para resolver este problema, implementei o método destroy() na Servlet que termina a Thread. Agora tudo está funcionando redondo! 
Obrigado pela ajuda de todos do Fórum!