Cache mais rápido

Transcrição

Cache mais rápido
Acelere seu servidor web com cache distribuído pelo memcached
CAPA
Cache mais rápido
O prático Memcached pode reduzir em até 90% a
carga de um servidor de banco de dados web.
por Tim Schürmann
B
rad Fitzpatrick estava frustrado: a plataforma de blog
LiveJournal.com, fundada
e mantida principalmente por ele,
tinha como base mais de 70 máquinas poderosas, mas seu desempenho
deixava muito a desejar. Nem mesmo o cache de 8 GB no servidor de
banco de dados parecia ajudar. Algo
precisava ser feito, e rapidamente. As
soluções típicas num cenário como
este são gerar conteúdo previamente
ou manter no cache páginas que já
tenham sido servidas. Logicamente, essas soluções exigem armazenagem redundante dos elementos
que ocorrem em múltiplas páginas
– o melhor caminho para encher o
cache de entulho. Se o sistema ficar
sem memória RAM, tudo pode ser
transferido para a swap em disco,
naturalmente, mas isso seria bem
demorado.
Na opinião de Fitzpatrick, a solução precisava ser um novo tipo de
40
sistema de cache – algo que armazenasse separadamente os objetos de
uma página, evitando assim o lento acesso ao disco. Assim, ele logo
desistiu de procurar uma solução e
decidiu projetar seu próprio cache.
Os servidores que ele usaria para
essa tarefa tinham memória RAM
suficiente livre. Inclusive, todas as
máquinas precisariam acessar o cache simultaneamente e o conteúdo
modificado deveria estar disponível
para qualquer usuário, sem atrasos.
Estas considerações finalmente o levaram ao memcached, que reduziu a
carga do servidor de banco de dados
do LiveJournal em surpreendentes
90% e acelerou a entrega das páginas
aos usuários, melhorando o uso dos
recursos das máquinas individuais.
O memcached [1] é um sistema
de cache distribuído de alta performance. Foi projetado para ser útil a
qualquer aplicação, mas é mais usado como cache dos lentos acessos a
bancos de dados em aplicações web
dinâmicas.
Hoje, muitos sites importantes,
como Slashdot, Fotolog.com e o
próprio LiveJournal.com, contam
com o memcached para melhorar
seu desempenho. Desde o princípio
de seu desenvolvimento, o LiveJournal.com foi comprado e vendido diversas vezes, e o memcached,
disponível sob uma licença BSD de
código aberto, é responsabilidade da
Danga Interactive.
Roupa nova
Configurar um cache distribuído com
o memcached é fácil. Basta iniciar o
daemon em todos os servidores que
possuam algum espaço em RAM para
ser compartilhado. Se necessário, é
possível disponibilizar múltiplas áreas
de cache em uma única máquina.
Esta opção é particularmente útil em
sistemas operacionais que limitam o
acesso dos processos a uma parcela
http://www.linuxmagazine.com.br
Memcached | CAPA
da memória total disponíDaemon 1
vel. Nesses casos, é preciso iniciar vários daemons,
cada um obtendo toda a
memória disponibilizada
Daemon 2
pelo sistema operacional,
para assim usar o máximo
Aplicação
Biblioteca cliente
de memória para o cache.
Daemon 3
Uma biblioteca cliente
especial age como interface
com o servidor. Ela aceita
os dados e os armazena em
um dos servidores existenDaemon n
tes usando palavras-chave
selecionáveis (figura 1). A
biblioteca cliente aplica um Figura 1A biblioteca cliente aceita os dados do aplicativo e seleciona um daemon, que
se encarregará de armazenar os dados.
sofisticado método matemático para escolher qual dos
daemons do memcached receberá seu casaco de volta no fim do espe- # memcached -d -m 2048 \
os dados que serão, então, postos táculo e o aplicativo seria forçado a -l 192.168.1.111 -p 11211 \
em sua RAM.
conversar novamente com o banco -u USERNAME
Podemos comparar esse proce- de dados. O sistema do memcached
dimento com a chapelaria de um não é redundante, mas não há necesEste comando inicia o memcached
teatro: você entrega seu casaco ao sidade de fazer isso, pois, no fim das em modo daemon (-d), instruindoatendente que está atrás do balcão contas, ele se resume a um cache e o a ceder 2048 MB de RAM desta
e recebe um número. O funcionário sua missão é armazenar informações máquina para o cache distribuído
pega seu casaco, acha o lugar certo temporariamente e entregá-las o mais (-m 2048). O daemon escuta as soe o pendura no cabide com o seu rapidamente possível. Seguindo esta licitações do cliente na porta 11211
número. No fim do espetáculo, todo filosofia, é impossível iterar por todos no endereço IP 192.168.1.111. Além
o processo é repetido de trás para os elementos do cache ou despejar disso, ele precisa saber qual conta
frente: você informa ao atendente todo o seu conteúdo no disco.
usar, mas é possível omitir a opção
– ou melhor, à biblioteca cliente –
-u para rodá-lo sob a conta do usuáo seu número, a biblioteca vai até
rio logado.
o daemon correspondente, pega os A Danga Interactive disponibiliza
Os especialistas em segurança
dados no cabide e os entrega ao seu o memcached daemon em seu site devem estar furiosos: por definição,
aplicativo.
para download [1]. As únicas depen- qualquer usuário de um sistema LiEsse modelo lembra muito os ban- dências do programa são a biblioteca nux pode rodar seu próprio daemon
cos de dados e sistemas de arquivos Libevent e seu pacote de desenvolvi- do memcached. Para evitar isso, são
distribuídos. Mas, quando se traba- mento correspondente. O daemon necessários alguns passos, como relha com o memcached, é necessário pode ser facilmente compilado e tirar privilégios de acesso – apenas
lembrar que ele é apenas um cache. instalado com as três etapas padrão: uma das várias questões de seguranEm outras palavras, o atendente da
ça evitadas pelo memcached (mais
chapelaria não é confiável e tem di- $ ./configure
tarde falarei sobre isso).
ficuldade de se lembrar das coisas. $ make
Se não houver espaço suficiente para # sudo make install
novos elementos, um dos daemons
Após alinhar todos os daemons, escodescartará os dados menos acessaAlgumas das principais distribui- lha uma das várias bibliotecas clientes
dos para liberar espaço. O mesmo ções já oferecem pacotes pré-compi- que agora estão disponíveis para váacontece quando um dos daemons lados, mas geralmente tratam-se de rias linguagens de programação. Em
falha – neste caso, qualquer informa- versões já obsoletas. Após terminar alguns casos, é até possível escolher
ção armazenada por ele desaparece. a instalação, o seguinte comando – os pacotes [2]. Se você preferir criar
Em outras palavras, você não teria ou um similar – inicia o daemon:
seu próprio cliente, encontrará uma
Na escuta
Escolha seus parceiros
Linux Magazine #60 | Novembro de 2009
41
CAPA | Memcached
descrição detalhada do protocolo na
wiki do memcached no site do projeto no Google Code [3].
O memcached é usado para acelerar aplicativos web e, por isso, muitas
pessoas optam por um cliente em
PHP. Para mais informações sobre o
uso do memcached com C ou C++,
veja o quadro 1.
A técnica básica é a mesma para
qualquer linguagem: após localizar e
instalar a biblioteca cliente correta,
o desenvolvedor precisa incluí-la no
seu próprio programa. A linha seguinte cria um novo objeto Memcached
no PHP com o cliente memcached do
repositório PECL, incluído no pacote PHP5–memcached do Ubuntu:
$memcached = new Memcached;
Depois disso, uma chamada de
função informa à biblioteca em quais
servidores os daemons do memcached estão escutando:
$memcache->connect (‘192.168.2.1’,
11211) or die (
‘Sem conexao com o servidor’);
Daqui para frente, é possível usar
mais chamadas de funções para preencher o cache com seu próprio conteúdo:
$memcache->set(
‘key’, ‘test’, false, 10);
Esta função grava a string test no
cache, com key como chave, mantendo a entrada por dez segundos. O
tamanho das chaves é restrito a 250
caracteres – restrição imposta pelo
daemon do memcached.
Para recuperar os dados, é preciso
passar a chave para a biblioteca cliente e aceitar os resultados recebidos:
$result = memcache->get(‘key’);
A listagem 1 mostra o script PHP
completo.
Listagem 1: Busca básica no cache em PHP
01 <?php
02 $memcache = new Memcache;
03 $memcache‑>connect(‘localhost’, 11211) or die (‘No connection to
memcached server’);
04
05 $memcache‑>set(‘key’, ‘datum’, false, 10);
06
07 $result = $memcache‑>get(‘key’);
08
09 var_dump($result);
10 ?>
Quadro 1: Libmembached
Até agora, a biblioteca cliente mais popular do memcached para aplicativos
em C e C++ é a Libmemcached [4] – que não deve ser confundida com sua
antecessora já descontinuada Libmemcache (sem o “d” no final). Mesmo que
você não seja um programador C e C++, vale a pena dar uma olhada no pacote. Ele contém ferramentas de diagnóstico muito interessantes para linha
de comando. Por exemplo, o memcat recupera os dados do cache para uma
chave e devolve o resultado no console; o memsat consulta o status atual de
um ou vários servidores. Para montar a Libmemcached, são necessários os
compiladores C e C++ no sistema; fora isso, bastam os comandos normais:
./configure; make; make install.
A listagem 2 mostra uma busca básica no cache.
42
A opção de escrever múltiplos conjuntos de dados no cache enquanto
eles são recuperados é interessante.
A biblioteca cliente paraleliza automaticamente sua requisição aos servidores do memcached. Infelizmente, algumas bibliotecas clientes não
possuem essa função; este exemplo
em PHP só é suportado pelo cliente
memcached (com um “d” no fim):
$multiplo = array(
‘chave1’ => ‘valor1’,
‘chave2’ => ‘valor2’,
‘chave3’ => ‘valor3’
);
$memcache->setMulti($multiplo);
Profiling
Nas aplicações web, sempre há a
questão de saber a melhor forma de
empregar o memcached. O profiling
responde: buscas em bancos de dados
que sobrecarregam o sistema são melhor roteados via cache. As listagens
3 e 4 mostram como isso funciona na
vida real: antes de buscar no banco
de dados, o código confere se a informação desejada está disponível no
memcached. Caso não esteja lá, o
banco de dados é acessado.
Para evitar uma nova busca, os
resultados são armazenados no cache. Para mantê-lo atualizado, a
informação de cada operação de
escrita também vai para o cache. Na
listagem 4, as chaves são feitas ao se
combinar a palavra user com o ID
de sua conta – esta é uma estratégia
comum para gerar chaves únicas.
Essa técnica facilita a integração
do memcached aos seus aplicativos,
mas é necessário tomar cuidado com
as armadilhas, que só se tornam óbvias quando olhamos “sob o capô”.
Dicionário
Os programadores experientes já devem ter notado que o memcached
usa internamente um dicionário; algumas linguagens de programação
http://www.linuxmagazine.com.br
Memcached | CAPA
chamam isso de array associativo,
vetor associativo ou hash. Como em
um dicionário comum, essa estrutura de dados armazena cada valor
sob uma chave (palavra) específica.
O sistema memcached implementa
este dicionário na forma de duas tabelas hash subsequentes [5]. Primeiramente, a biblioteca cliente aceita a
chave e efetua uma sofisticada função
matemática para criar um hash. O
número informa à biblioteca com
qual dos daemons do memcached
ela precisa conversar. Após receber
os dados, o daemon usa sua própria
função hash para atribuir um local
da memória a fim de armazenar os
dados. As funções matemáticas são
desenvolvidas para retornar sempre
o mesmo número exato para uma
chave específica. Este processo garante tempos de busca e resposta extremamente curtos. Para recuperar
informações do cache, o memcached
precisa apenas efetuar as duas funções matemáticas. A transmissão de
dados pela rede é responsável pela
maior parte do tempo de resposta.
Todas as máquinas envolvidas
precisam ter as mesmas versões das
mesmas bibliotecas, pois é a biblioteca
cliente quem decide quais daemons
armazenarão quais dados. Uma mistura de versões pode fazer com que os
clientes utilizem funções hash diferentes, armazenando assim a mesma
informação em diferentes servidores,
o que pode gerar inconsistências e
desorganização dos dados. Se você
usar a biblioteca Libmemcached de
C e C++, é bom prestar bastante
atenção a isso, pois ela oferece várias
funções hash.
Além disso, cada cliente usa um
método de serialização diferente. Por
exemplo, o Java usa o Hibernate, enquanto que o PHP usa o serialize. Em
outras palavras, se, além de strings,
você também estiver armazenando
objetos no cache, o uso compartilhado baseado em diferentes linguagens
é impossível – mesmo que todos os
Linux Magazine #60 | Novembro de 2009
clientes usem a mesma função de
hash. As bibliotecas também têm
permissão de escolher seus métodos
de compressão.
Perda de memória
O cache lida com solicitações paralelas sem perder velocidade. No
exemplo da chapelaria, vários atendentes podem andar pelos corredores ao mesmo tempo, pendurando
casacos ou devolvendo-os aos donos,
sem que estes tenham que esperar na
fila. O mesmo princípio se aplica ao
memcached. Cada cliente determina com qual daemon conversará e,
num mundo ideal, cada atendente
estaria encarregado de um único
corredor: logicamente, nada impede que dois atendentes entrem no
mesmo corredor. Se você recupera
dados do cache, os altera e os devolve, não há garantias de que eles não
tenham sido modificados por outra
Listagem 2: Busca básica no cache
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <memcached.h>
#include <string.h>
#include <stdio.h>
main() {
/* cria a struct memcached_st (que contém todas as informações
básicas para os servidores memcached) */
memcached_st *mcd = memcached_create(NULL);
/* adiciona um servidor: */
memcached_server_add(mcd, “127.0.0.1”, 11211);
/* Envia o objeto para o cache: */
char *key = “chave”;
size_t keylength = strlen(key);
char *value = “informacao”;
size_t valuelength = strlen(value);
time_t expiration = 0;
uint32_t flags = 0;
memcached_add(mcd, key, keylength, value, valuelength,
expiration,flags);
/* Obtem objeto do cache: */
memcached_return errovariable;
char *result = memcached_get(mcd, key, keylength,&valuelength,
&flags, &errovariable);
/* Imprime o objeto: */
printf(“Cache: %s\n”, result);
/* Limpa: */
memcached_free(mcd);
}
Listagem 3: Busca no banco de dados sem memcached...
01 function get_user($userid) {
02 $result = mysql_query (“SELECT * FROM users WHERE userid =
‘%s’”, $userid);
03 return $result;
04 }
43
CAPA | Memcached
Listagem 4: ...e após a introdução do memcached
01 $memcache = new Memcache;
02 $memcache‑>connect(‘servername’, 11211) or die (‘No connection to
memcached server’);
03 ...
04 function get_user($userid) {
05 $result = memcache‑>get(“user” + $userid);
06 if(!$result) {
07 $result = mysql_query(“SELECT * FROM users WHERE userid =
‘%s’”, $userid);
08 memcache‑>add(“user” + $userid, $result);
09 }
10 return $result;
11 }
instância neste meio tempo. Os comandos gets e cas introduzidos na
versão 1.2.5 do memcached oferecem
a solução: os usuários utilizam o comando gets para recuperar dados e
recebem um identificador único, o
qual pode ser devolvido ao servidor
juntamente com os dados modificados pelo comando cas. O daemon
confere então o ID para verificar se
os dados foram alterados desde a última busca e sobrescreve-os usando
o novo valor, se for o caso.
O modo como o memcached
lida com falhas do servidor também
depende do cliente. O padrão é simplesmente agir como se a informação
solicitada não se encontrasse no cache.
Por isso, é uma boa ideia monitorar
permanentemente os servidores de
cache. Graças ao design modular
do memcached, cada daemon pode
ser facilmente substituído. Para isso,
basta apagar o registro anterior dos
IPs e registrar os novos endereços
IP dos clientes. Mas note que, neste
caso, algumas bibliotecas acabarão
considerando todo o cache inválido.
Queijo suíço
Para prevenir a fragmentação da RAM,
o daemon usa um alocador slab [6]
para gerenciar a memória. Esse método
reserva e libera pequenos pedaços da
memória. No caso do memcached,
esses pedaços são de 1 MB – o daemon
não aceita nada maior que isso. Para
armazenar mais, é preciso distribuir os
44
dados em múltiplas chaves ou usar um
sistema de caching diferente.
Anarquia
O memcached não se preocupa com
segurança. O daemon não necessita
de autenticação dos clientes. Qualquer um que acesse a rede também
pode acessar o cache sem reservas.
Um invasor que saiba os nomes dos
usuários por trás das chaves pode sistematicamente solicitar esses nomes
aos daemons. Chaves criptografadas
podem garantir uma proteção rudimentar. Para gerá-las, é necessário
aplicar um hash aos nomes dos
usuários no escopo do aplicativo e
então usar os resultados como chaves. Todos os dados da conta têm
que ser deletados do cache após o
uso. Além disso, é bom definir uma
duração para os dados e incluir mais
camadas de segurança, começando
por um firewall para proteger o servidor de ataques externos.
Conclusões
O memcached é fácil de configurar
e de integrar a aplicativos existentes.
Porém, essa conveniência implica
diversos problemas de vulnerabilidade. Se você conseguir resolver essas
questões, terá um cache distribuído
extremamente rápido que não o deixará na mão – mesmo em condições
extremas. Esse sistema prova seu
valor diariamente no LiveJournal e
no Slashdot. Ao mesmo tempo, é
extremamente frugal. A capacidade
da CPU não é comprometida, pois o
memcached praticamente gera apenas
hashes. Como resultado, é possível
usar até computadores mais velhos
como provedores de cache. n
Mais informações
[1]Memcached: http://www.danga.com/memcached
[2]Bibliotecas clientes:
http://code.google.com/p/memcached/wiki/Clients
[3]Protocolo do memcached:
http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
[4]Libmemcached: http://tangent.org/552/libmemcached.html
[5]Funcionamento de tabelas hash:
http://pt.wikipedia.org/wiki/Tabela_de_dispers%C3%A3o
[6]Funcionamento de alocadores slab (em inglês):
http://en.wikipedia.org/wiki/Slab_allocator
Gostou do artigo?
Queremos ouvir sua opinião. Fale conosco em
[email protected]
Este artigo no nosso site:
http://lnm.com.br/article/3114
http://www.linuxmagazine.com.br

Documentos relacionados