Memcached é um sistema de cache em memória distribuido muito fácil de usar. Como recentemente tive uma experiência maravilhosa com esta ferramenta acredito que é interessante expô-la neste post (prometo que o próximo post será sobre MongoDB). A natureza do Memcached é extremamente genérica – trata-se de um serviço de rede – sendo assim, o que descreverei pode ser aplicado sem grandes mudanças a básicamente qualquer linguagem/ambiente de execução. Mas antes de falar sobre minha experiência, vou falar um pouco sobre o funcionamento da criatura e como usá-lo com Java (consequentemente, com Groovy também).
Idéia básica
Para muitos, o conceito de cache é algo novo. Sendo assim, convém fazer uma introdução ao conceito. Imagine que você possua um conjunto de informações que repetidas vezes precise ser buscado na sua base de dados. A cada consulta, você precisa:
- Enviar a consulta (por exemplo: SQL)
- Esperar o processamento do SGBD
- Receber o resultado obtido
- Transformá-lo, tornando-o útil para sua aplicação
O objetivo do cache é evitar temporáriamente os três últimos passos do procedimento que descrevi acima, retornando para o usuário o resultado do processamento dos dados em estado cru. Se 2 + 2 são 4, por que calcular este valor toda vez que você receber esta pergunta se é possível armazenar apenas o resultado e reaproveitá-lo quando necessário?
O Servidor Memcached
O Memcached é um serviço de rede. No site oficial (http://www.memcached.org) é possível baixar a última versão, que vêm como código fonte (veja este link para maiores detalhes sobre como proceder com a instalação). Se estiver usando Linux, instalá-lo é ainda mais fácil, visto que muito provávelmente a criatura já estará disponível nos repositórios de sua distribuição.
Instalado, basta executar o comando memcached para iniciar o serviço. É importante conhecer alguns parâmetros, cuja listagem segue abaixo:
-m : quanta memória (em Mbs) o Memcached irá usar. Caso omitido, o valor default é 64 Mb.
-p : qual a porta TCP a ser usada. Caso omitido, o valor default é 11211
-u : qual a porta UDP a ser usada. Como a porta TCP, o valor default é 11211 caso omitido.
-v : Modo verboso: o Memcached irá expor na tela o que está executando. É bacana quando estamos aprendendo a usar o bichinho. Interessante mencionar que há duas outras opções: -vv (mais verboso) e -vvv (ainda mais verboso)
Sendo assim, se eu executar o comando memcached -m 540 -v -p 11000 -u 11000 iniciará o serviço com 540 Mb de memória no modo verboso definindo como portas UDP e TCP a 11000.
Como mencionei, o Memcached é um servidor distribuido, mas como minha experiência até o momento envolveu apenas uma instância ainda não tenho conhecimento suficiente para compartilhar.
O que é e como é armazenado
Pense no Memcached como uma tabela de hash gigante. Toda informação individual armazenada possui basicamente 3 elementos:
Identificador: um texto com tamanho máximo de 250 caracteres que identifica um corpo de informação. Equivale à chave primária com a qual já estamos acostumados a trabalhar no modelo relacional. Não há regras com relação ao seu valor: sendo assim, você é livre para identificar suas informações como quiser.
Tempo de duração: o tempo (em segundos) que o Memcached manterá esta informação na memória. O tempo máximo suportado é 30 dias.
Corpo: a informação em si. No caso do Memcached, esta possui tamanho máximo de 1 Mb. Se for pouco pra você, sempre é possível dividir a sua informação em mais de um bloco, compactá-la ou, se preferir, alterar o código fonte do Memcached (eu o li inteiro, e é BEM fácil de entender (se você souber C)).
Lembre-se: não se trata de um banco de dados. Tudo no Memcached, assim como na vida (sôou poético!) é passageiro. A idéia é evitar que tenhamos de acessar o SGBD, que é um processo MUITO mais caro computacionalmente, e não substitui-lo!
O cliente Memcached
O primeiro passo é escolher qual biblioteca cliente usar para acessar o Memcached. Há diversas, implementadas em tudo o que você imaginar: C, C++, PHP, MySQL, Python, Perl, Ruby… No nosso caso, vou falar do SpyMemcached, que é um cliente para Java. Uma lista com “alguns” dos clientes disponíveis atualmente pode ser acessada neste link.
O SpyMemcached é composto por um único arquivo Jar, o que torna seu deploy muito simples. Basicamente o único pacote que você vai precisar é do net.spy.memcached.
Obtendo uma conexão com o Memcached
Basta criar uma nova instância da classe MemcachedClient, tal como no exemplo abaixo:
MemcachedClient client =new MemcachedClient(AddrUtil.getAddresses("0.0.0.0:11211 10.10.10.69:11211"));
Repare que passei dois servidores distintos. Usando este construtor você poderá adicionar um ou mais servidores aonde serão feitas as suas buscas.
Buscando e inserindo informações
Buscar e inserir informações com o SpyMemcached é simples. O código abaixo é quase que auto-explicativo.
MemcachedClient client =new MemcachedClient(AddrUtil.getAddresses("localhost:11211")); // O que irei armazenar no Memcached Pessoa pessoa = new Pessoa(); pessoa.setNome("Kico"); pessoa.setCidade("BH"); // Incluindo informações client.add("chave_pessoa", 120, pessoa); // Buscando a informação Pessoa noCache = (Pessoa) client.get("chave_pessoa");
Quando incluimos uma informação no Memcached, devemos passar 3 parâmetros: a chave de identificação, o tempo em segundos e o que queremos armazenar. No caso de um objeto, este obrigatóriamente deverá implementar a interface java.io.Serializable. Caso contrário será disparada uma excessão.
Já para obter a informação, basta passar a chave que a identifica e em seguida fazer o type casting para o tipo desejado.
Ah: e como fechar a conexão com o servidor? Simples: execute o método shutdown() da classe MemcachedClient.
Conhecendo os métodos abaixo da classe MemcachedClient você já pode começar a trabalhar (e bem) com o Memcached:
void MemcachedClient.add(String chave, int segundos, Object valor): insere uma informação no servidor Memcached. Se já existir um valor definido para esta chave no servidor, este será mantido pelo Memcached.
Object MemcachedClient.get(String chave): retorna um valor armazenado no Memcached
void MemcachedClient.shutdown(): fecha a conexão com o Memcached
void MemcachedClient.remove(String chave): remove uma informação armazenada no servidor
void MemcachedClient.replace(String chave, int segundos, Object valor): substitui um valor armazenado no servidor.
Dica: aproveite ao máximo suas conexões com o Memcached buscando o maior número possível de registros, mas nunca se esqueça de fechá-las, pois o serviço começa a apresentar problemas quando o número de conexões simultâneas é muito alto.
Minha experiência
Eis a situação: possuimos uma aplicação feita em Grails cuja base é uma biblioteca escrita em Java. Esta biblioteca é também usada por diversas aplicações executadas no ambiente desktop dentro da empresa. Fiz uma imagem que, espero, ilustre a situação.
Em nosso servidor físico aonde já se encontrava instalado o Tomcat aproveitei para colocar em execução o servidor do Memcached.
Como sou o pai da biblioteca legada que mencionei acima, a refatorei para que ao invés de usar a biblioteca de cache anterior, passasse a usar o Memcached.
Em seguida, atualizei tanto a nossa aplicação Grails quanto os clientes desktop (nestas horas você começa a AMAR o Java Webstart) e voilá: resultado imediato.
Como todos acessam o mesmo servidor Memcached, no momento em que uma aplicação desktop ou web alimentam o servidor de cache, automáticamente todas as demais instâncias se beneficiam. Resultado? Nossa performance global aumentou no mínimo 3 vezes, e o número de chamadas ao nosso SGBD diminuiu em aproximadamente 40%.
É importante mencionar que em nosso ambiente é muito comum mais de um usuário concorrentemente necessitar do mesmo conjunto de informações. Isto é fundamental, pois caso contrário não teriamos um ganho de performance, mas sim perda, pois antes de executar uma consulta no SGBD, sempre seria feita uma busca no Memcached.
É fundamental lembrar o seguinte aqui: não temos um cache local, mas remoto. O ganho da performance é obtido em grande parte porque não precisamos popular objetos, visto os mesmos já virem “prontos” do servidor para nós.
Antes do Memcached haviamos pensado sériamente em usar o Terracota. Mas como nosso ambiente é heterogêneo, e há programas escritos em .net, C/C++, VB6 e PHP, o Memcached caiu como uma luva, pois assim podemos aproveitar a mesma estrutura (e dados!) entre estas diferentes plataformas de execução/desenvolvimento (claro, com os devidos cuidados para evitar a bagunça).
Recomendadíssimo portanto o seu uso. Espero que este post seja útil aos que estejam interessados em usar a ferramenta.
Deixe uma resposta