Cache

18 respostas
mcampelo

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

18 Respostas

smota

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

mcampelo

Obrigado, smota.

Vou testar o OSCache e depois posto aqui se resolveu meu problema.

Abraços

louds

Usa o coherence, esse sim é cache de verdade.

danieldestro

Não resolve usar o próprio Oracle Web Cache?

smota

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.

cv1

Hmm… vc ja chegou a testar o Coherence, louds?

mcampelo

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?

danieldestro

Crie um Agente (Thread) que faça isso.

louds

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.

mcampelo

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?

danieldestro

Uma thread à parte.

louds

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.

louds

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) {
				// 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.

cv1

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).

mcampelo

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.

mcampelo

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?

louds

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.

mcampelo

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! :smiley:

Obrigado pela ajuda de todos do Fórum!

Criado 17 de dezembro de 2003
Ultima resposta 23 de dez. de 2003
Respostas 18
Participantes 5