40 http://www.linuxmagazine.com.br
CAPA
Acelere seu servidor web com cache distribuído pelo memcached
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 frus-
trado: a plataforma de blog
LiveJournal.com, fundada
e mantida principalmente por ele,
tinha como base mais de 70 máqui-
nas poderosas, mas seu desempenho
deixava muito a desejar. Nem mes-
mo 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. Logicamen-
te, essas soluções exigem armaze-
nagem 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 so-
lução precisava ser um novo tipo de
sistema de cache – algo que armaze-
nasse separadamente os objetos de
uma página, evitando assim o len-
to 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 ca-
che simultaneamente e o conteúdo
modificado deveria estar disponível
para qualquer usuário, sem atrasos.
Estas considerações finalmente o le-
varam 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 perfor-
mance. Foi projetado para ser útil a
qualquer aplicação, mas é mais usa-
do 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 Live-
Journal.com foi comprado e vendi-
do 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
41
| CAPAMemcached
Linux Magazine #60 | Novembro de 2009
da memória total disponí-
vel. Nesses casos, é preci-
so iniciar vários daemons,
cada um obtendo toda a
memória disponibilizada
pelo sistema operacional,
para assim usar o máximo
de memória para o cache.
Uma biblioteca cliente
especial age como interface
com o servidor. Ela aceita
os dados e os armazena em
um dos servidores existen-
tes usando palavras-chave
selecionáveis (figura 1). A
biblioteca cliente aplica um
sofisticado método matemá-
tico para escolher qual dos
daemons do memcached receberá
os dados que serão, então, postos
em sua RAM.
Podemos comparar esse proce-
dimento com a chapelaria de um
teatro: você entrega seu casaco ao
atendente que está atrás do balcão
e recebe um número. O funcionário
pega seu casaco, acha o lugar certo
e o pendura no cabide com o seu
número. No fim do espetáculo, todo
o processo é repetido de trás para
frente: você informa ao atendente
– ou melhor, à biblioteca cliente –
o seu número, a biblioteca vai até
o daemon correspondente, pega os
dados no cabide e os entrega ao seu
aplicativo.
Esse modelo lembra muito os ban-
cos de dados e sistemas de arquivos
distribuídos. Mas, quando se traba-
lha com o memcached, é necessário
lembrar que ele é apenas um cache.
Em outras palavras, o atendente da
chapelaria não é confiável e tem di-
ficuldade de se lembrar das coisas.
Se não houver espaço suficiente para
novos elementos, um dos daemons
descartará os dados menos acessa-
dos para liberar espaço. O mesmo
acontece quando um dos daemons
falha – neste caso, qualquer informa-
ção armazenada por ele desaparece.
Em outras palavras, você não teria
seu casaco de volta no fim do espe-
táculo e o aplicativo seria forçado a
conversar novamente com o banco
de dados. O sistema do memcached
não é redundante, mas não há neces-
sidade de fazer isso, pois, no fim das
contas, ele se resume a um cache e
sua missão é armazenar informações
temporariamente e entregá-las o mais
rapidamente possível. Seguindo esta
filosofia, é impossível iterar por todos
os elementos do cache ou despejar
todo o seu conteúdo no disco.
Na escuta
A Danga Interactive disponibiliza
o memcached daemon em seu site
para download [1]. As únicas depen-
dências do programa são a biblioteca
Libevent e seu pacote de desenvolvi-
mento correspondente. O daemon
pode ser facilmente compilado e
instalado com as três etapas padrão:
$ ./configure
$ make
# sudo make install
Algumas das principais distribui-
ções já oferecem pacotes pré-compi-
lados, mas geralmente tratam-se de
versões já obsoletas. Após terminar
a instalação, o seguinte comando –
ou um similar – inicia o daemon:
# memcached -d -m 2048 
-l 192.168.1.111 -p 11211 
-u USERNAME
Este comando inicia o memcached
em modo daemon (-d), instruindo-
o a ceder 2048 MB de RAM desta
máquina para o cache distribuído
(-m 2048). O daemon escuta as so-
licitações do cliente na porta 11211
no endereço IP 192.168.1.111. Além
disso, ele precisa saber qual conta
usar, mas é possível omitir a opção
-u para rodá-lo sob a conta do usuá-
rio logado.
Os especialistas em segurança
devem estar furiosos: por definição,
qualquer usuário de um sistema Li-
nux pode rodar seu próprio daemon
do memcached. Para evitar isso, são
necessários alguns passos, como re-
tirar privilégios de acesso – apenas
uma das várias questões de seguran-
ça evitadas pelo memcached (mais
tarde falarei sobre isso).
Escolha seus parceiros
Após alinhar todos os daemons, esco-
lha uma das várias bibliotecas clientes
que agora estão disponíveis para vá-
rias linguagens de programação. Em
alguns casos, é até possível escolher
os pacotes [2]. Se você preferir criar
seu próprio cliente, encontrará uma
Figura 1	A biblioteca cliente aceita os dados do aplicativo e seleciona um daemon, que
se encarregará de armazenar os dados.
Aplicação Biblioteca cliente
Daemon 1
Daemon 2
Daemon 3
Daemon n
42 http://www.linuxmagazine.com.br
CAPA  | Memcached
descrição detalhada do protocolo na
wiki do memcached no site do pro-
jeto no Google Code [3].
O memcached é usado para acele-
rar 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 se-
guinte cria um novo objeto Memcached
no PHP com o cliente memcached do
repositório PECL, incluído no pa-
cote PHP5–memcached do Ubuntu:
$memcached = new Memcached;
Depois disso, uma chamada de
função informa à biblioteca em quais
servidores os daemons do memca-
ched estão escutando:
$memcache-connect (‘192.168.2.1’,
11211) or die (
‘Sem conexao com o servidor’);
Daqui para frente, é possível usar
maischamadasdefunçõesparapreen-
cherocachecomseupróprioconteúdo:
$memcache-set(
‘key’, ‘test’, false, 10);
Esta função grava a string test no
cache, com key como chave, man-
tendo 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 clien-
te e aceitar os resultados recebidos:
$result = memcache-get(‘key’);
A listagem 1 mostra o script PHP
completo.
A opção de escrever múltiplos con-
juntos de dados no cache enquanto
eles são recuperados é interessante.
A biblioteca cliente paraleliza auto-
maticamente sua requisição aos ser-
vidores do memcached. Infelizmen-
te, 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 me-
lhor 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 in-
formaçã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 ca-
che. 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 ób-
vias quando olhamos “sob o capô”.
Dicionário
Os programadores experientes já de-
vem ter notado que o memcached
usa internamente um dicionário; al-
gumas linguagens de programação
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 pa-
cote. 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.
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 ?
43
| CAPAMemcached
Linux Magazine #60 | Novembro de 2009
chamam isso de array associativo,
vetor associativo ou hash. Como em
um dicionário comum, essa estru-
tura de dados armazena cada valor
sob uma chave (palavra) específica.
O sistema memcached implementa
este dicionário na forma de duas ta-
belas hash subsequentes [5]. Primei-
ramente, 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 ga-
rante tempos de busca e resposta ex-
tremamente 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 mis-
tura de versões pode fazer com que os
clientes utilizem funções hash dife-
rentes, 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, en-
quanto que o PHP usa oserialize. Em
outras palavras, se, além de strings,
você também estiver armazenando
objetos no cache, o uso compartilha-
do baseado em diferentes linguagens
é impossível – mesmo que todos os
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 pa-
ralelas sem perder velocidade. No
exemplo da chapelaria, vários aten-
dentes podem andar pelos corredo-
res 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 determi-
na com qual daemon conversará e,
num mundo ideal, cada atendente
estaria encarregado de um único
corredor: logicamente, nada impe-
de que dois atendentes entrem no
mesmo corredor. Se você recupera
dados do cache, os altera e os devol-
ve, não há garantias de que eles não
tenham sido modificados por outra
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 }
Listagem 2: Busca básica no cache
01 #include memcached.h
02 #include string.h
03 #include stdio.h
04
05 main() {
06    /* cria a struct memcached_st (que contém todas as informações
07       básicas para os servidores memcached) */
08    memcached_st *mcd = memcached_create(NULL);
09
10    /* adiciona um servidor: */
11    memcached_server_add(mcd, “127.0.0.1”, 11211);
12
13    /* Envia o objeto para o cache: */
14
15    char *key = “chave”;
16    size_t keylength = strlen(key);
17    char *value = “informacao”;
18    size_t valuelength = strlen(value);
19    time_t expiration = 0;
20    uint32_t flags = 0;
21
22    memcached_add(mcd, key, keylength, value, valuelength,
23       expiration,flags);
24
25    /* Obtem objeto do cache: */
26
27    memcached_return errovariable;
28
29    char *result = memcached_get(mcd, key, keylength,valuelength,
30       flags, errovariable);
31
32    /* Imprime o objeto: */
33    printf(“Cache: %sn”, result);
34
35    /* Limpa: */
36    memcached_free(mcd);
37 }
44 http://www.linuxmagazine.com.br
CAPA  | Memcached
instância neste meio tempo. Os co-
mandos gets e cas introduzidos na
versão 1.2.5 do memcached oferecem
a solução: os usuários utilizam o co-
mando gets para recuperar dados e
recebem um identificador único, o
qual pode ser devolvido ao servidor
juntamente com os dados modifica-
dos pelo comando cas. O daemon
confere então o ID para verificar se
os dados foram alterados desde a úl-
tima 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 é sim-
plesmente agir como se a informação
solicitadanãoseencontrassenocache.
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
ParaprevenirafragmentaçãodaRAM,
o daemon usa um alocador slab [6]
paragerenciaramemória.Essemétodo
reserva e libera pequenos pedaços da
memória. No caso do memcached,
essespedaçossãode1MB–odaemon
não aceita nada maior que isso. Para
armazenarmais,éprecisodistribuiros
dadosemmúltiplaschavesouusarum
sistema de caching diferente.
Anarquia
O memcached não se preocupa com
segurança. O daemon não necessita
de autenticação dos clientes. Qual-
quer 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 sis-
tematicamente solicitar esses nomes
aos daemons. Chaves criptografadas
podem garantir uma proteção rudi-
mentar. Para gerá-las, é necessário
aplicar um hash aos nomes dos
usuários no escopo do aplicativo e
então usar os resultados como cha-
ves. 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 ser-
vidor 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 vulnerabilida-
de. Se você conseguir resolver essas
questões, terá um cache distribuído
extremamente rápido que não o dei-
xará 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
memcachedpraticamentegeraapenas
hashes. Como resultado, é possível
usar até computadores mais velhos
como provedores de cache.  n
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 }
Gostou do artigo?
Queremos ouvir sua opinião. Fale conosco em
cartas@linuxmagazine.com.br
Este artigo no nosso site:
http://lnm.com.br/article/3114
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

Tutorial memcached

  • 1.
    40 http://www.linuxmagazine.com.br CAPA Acelere seuservidor web com cache distribuído pelo memcached 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 frus- trado: a plataforma de blog LiveJournal.com, fundada e mantida principalmente por ele, tinha como base mais de 70 máqui- nas poderosas, mas seu desempenho deixava muito a desejar. Nem mes- mo 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. Logicamen- te, essas soluções exigem armaze- nagem 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 so- lução precisava ser um novo tipo de sistema de cache – algo que armaze- nasse separadamente os objetos de uma página, evitando assim o len- to 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 ca- che simultaneamente e o conteúdo modificado deveria estar disponível para qualquer usuário, sem atrasos. Estas considerações finalmente o le- varam 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 perfor- mance. Foi projetado para ser útil a qualquer aplicação, mas é mais usa- do 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 Live- Journal.com foi comprado e vendi- do 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
  • 2.
    41 | CAPAMemcached Linux Magazine#60 | Novembro de 2009 da memória total disponí- vel. Nesses casos, é preci- so iniciar vários daemons, cada um obtendo toda a memória disponibilizada pelo sistema operacional, para assim usar o máximo de memória para o cache. Uma biblioteca cliente especial age como interface com o servidor. Ela aceita os dados e os armazena em um dos servidores existen- tes usando palavras-chave selecionáveis (figura 1). A biblioteca cliente aplica um sofisticado método matemá- tico para escolher qual dos daemons do memcached receberá os dados que serão, então, postos em sua RAM. Podemos comparar esse proce- dimento com a chapelaria de um teatro: você entrega seu casaco ao atendente que está atrás do balcão e recebe um número. O funcionário pega seu casaco, acha o lugar certo e o pendura no cabide com o seu número. No fim do espetáculo, todo o processo é repetido de trás para frente: você informa ao atendente – ou melhor, à biblioteca cliente – o seu número, a biblioteca vai até o daemon correspondente, pega os dados no cabide e os entrega ao seu aplicativo. Esse modelo lembra muito os ban- cos de dados e sistemas de arquivos distribuídos. Mas, quando se traba- lha com o memcached, é necessário lembrar que ele é apenas um cache. Em outras palavras, o atendente da chapelaria não é confiável e tem di- ficuldade de se lembrar das coisas. Se não houver espaço suficiente para novos elementos, um dos daemons descartará os dados menos acessa- dos para liberar espaço. O mesmo acontece quando um dos daemons falha – neste caso, qualquer informa- ção armazenada por ele desaparece. Em outras palavras, você não teria seu casaco de volta no fim do espe- táculo e o aplicativo seria forçado a conversar novamente com o banco de dados. O sistema do memcached não é redundante, mas não há neces- sidade de fazer isso, pois, no fim das contas, ele se resume a um cache e sua missão é armazenar informações temporariamente e entregá-las o mais rapidamente possível. Seguindo esta filosofia, é impossível iterar por todos os elementos do cache ou despejar todo o seu conteúdo no disco. Na escuta A Danga Interactive disponibiliza o memcached daemon em seu site para download [1]. As únicas depen- dências do programa são a biblioteca Libevent e seu pacote de desenvolvi- mento correspondente. O daemon pode ser facilmente compilado e instalado com as três etapas padrão: $ ./configure $ make # sudo make install Algumas das principais distribui- ções já oferecem pacotes pré-compi- lados, mas geralmente tratam-se de versões já obsoletas. Após terminar a instalação, o seguinte comando – ou um similar – inicia o daemon: # memcached -d -m 2048 -l 192.168.1.111 -p 11211 -u USERNAME Este comando inicia o memcached em modo daemon (-d), instruindo- o a ceder 2048 MB de RAM desta máquina para o cache distribuído (-m 2048). O daemon escuta as so- licitações do cliente na porta 11211 no endereço IP 192.168.1.111. Além disso, ele precisa saber qual conta usar, mas é possível omitir a opção -u para rodá-lo sob a conta do usuá- rio logado. Os especialistas em segurança devem estar furiosos: por definição, qualquer usuário de um sistema Li- nux pode rodar seu próprio daemon do memcached. Para evitar isso, são necessários alguns passos, como re- tirar privilégios de acesso – apenas uma das várias questões de seguran- ça evitadas pelo memcached (mais tarde falarei sobre isso). Escolha seus parceiros Após alinhar todos os daemons, esco- lha uma das várias bibliotecas clientes que agora estão disponíveis para vá- rias linguagens de programação. Em alguns casos, é até possível escolher os pacotes [2]. Se você preferir criar seu próprio cliente, encontrará uma Figura 1 A biblioteca cliente aceita os dados do aplicativo e seleciona um daemon, que se encarregará de armazenar os dados. Aplicação Biblioteca cliente Daemon 1 Daemon 2 Daemon 3 Daemon n
  • 3.
    42 http://www.linuxmagazine.com.br CAPA  |Memcached descrição detalhada do protocolo na wiki do memcached no site do pro- jeto no Google Code [3]. O memcached é usado para acele- rar 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 se- guinte cria um novo objeto Memcached no PHP com o cliente memcached do repositório PECL, incluído no pa- cote PHP5–memcached do Ubuntu: $memcached = new Memcached; Depois disso, uma chamada de função informa à biblioteca em quais servidores os daemons do memca- ched estão escutando: $memcache-connect (‘192.168.2.1’, 11211) or die ( ‘Sem conexao com o servidor’); Daqui para frente, é possível usar maischamadasdefunçõesparapreen- cherocachecomseupróprioconteúdo: $memcache-set( ‘key’, ‘test’, false, 10); Esta função grava a string test no cache, com key como chave, man- tendo 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 clien- te e aceitar os resultados recebidos: $result = memcache-get(‘key’); A listagem 1 mostra o script PHP completo. A opção de escrever múltiplos con- juntos de dados no cache enquanto eles são recuperados é interessante. A biblioteca cliente paraleliza auto- maticamente sua requisição aos ser- vidores do memcached. Infelizmen- te, 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 me- lhor 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 in- formaçã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 ca- che. 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 ób- vias quando olhamos “sob o capô”. Dicionário Os programadores experientes já de- vem ter notado que o memcached usa internamente um dicionário; al- gumas linguagens de programação 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 pa- cote. 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. 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 ?
  • 4.
    43 | CAPAMemcached Linux Magazine#60 | Novembro de 2009 chamam isso de array associativo, vetor associativo ou hash. Como em um dicionário comum, essa estru- tura de dados armazena cada valor sob uma chave (palavra) específica. O sistema memcached implementa este dicionário na forma de duas ta- belas hash subsequentes [5]. Primei- ramente, 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 ga- rante tempos de busca e resposta ex- tremamente 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 mis- tura de versões pode fazer com que os clientes utilizem funções hash dife- rentes, 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, en- quanto que o PHP usa oserialize. Em outras palavras, se, além de strings, você também estiver armazenando objetos no cache, o uso compartilha- do baseado em diferentes linguagens é impossível – mesmo que todos os 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 pa- ralelas sem perder velocidade. No exemplo da chapelaria, vários aten- dentes podem andar pelos corredo- res 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 determi- na com qual daemon conversará e, num mundo ideal, cada atendente estaria encarregado de um único corredor: logicamente, nada impe- de que dois atendentes entrem no mesmo corredor. Se você recupera dados do cache, os altera e os devol- ve, não há garantias de que eles não tenham sido modificados por outra 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 } Listagem 2: Busca básica no cache 01 #include memcached.h 02 #include string.h 03 #include stdio.h 04 05 main() { 06    /* cria a struct memcached_st (que contém todas as informações 07       básicas para os servidores memcached) */ 08    memcached_st *mcd = memcached_create(NULL); 09 10    /* adiciona um servidor: */ 11    memcached_server_add(mcd, “127.0.0.1”, 11211); 12 13    /* Envia o objeto para o cache: */ 14 15    char *key = “chave”; 16    size_t keylength = strlen(key); 17    char *value = “informacao”; 18    size_t valuelength = strlen(value); 19    time_t expiration = 0; 20    uint32_t flags = 0; 21 22    memcached_add(mcd, key, keylength, value, valuelength, 23       expiration,flags); 24 25    /* Obtem objeto do cache: */ 26 27    memcached_return errovariable; 28 29    char *result = memcached_get(mcd, key, keylength,valuelength, 30       flags, errovariable); 31 32    /* Imprime o objeto: */ 33    printf(“Cache: %sn”, result); 34 35    /* Limpa: */ 36    memcached_free(mcd); 37 }
  • 5.
    44 http://www.linuxmagazine.com.br CAPA  |Memcached instância neste meio tempo. Os co- mandos gets e cas introduzidos na versão 1.2.5 do memcached oferecem a solução: os usuários utilizam o co- mando gets para recuperar dados e recebem um identificador único, o qual pode ser devolvido ao servidor juntamente com os dados modifica- dos pelo comando cas. O daemon confere então o ID para verificar se os dados foram alterados desde a úl- tima 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 é sim- plesmente agir como se a informação solicitadanãoseencontrassenocache. 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 ParaprevenirafragmentaçãodaRAM, o daemon usa um alocador slab [6] paragerenciaramemória.Essemétodo reserva e libera pequenos pedaços da memória. No caso do memcached, essespedaçossãode1MB–odaemon não aceita nada maior que isso. Para armazenarmais,éprecisodistribuiros dadosemmúltiplaschavesouusarum sistema de caching diferente. Anarquia O memcached não se preocupa com segurança. O daemon não necessita de autenticação dos clientes. Qual- quer 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 sis- tematicamente solicitar esses nomes aos daemons. Chaves criptografadas podem garantir uma proteção rudi- mentar. Para gerá-las, é necessário aplicar um hash aos nomes dos usuários no escopo do aplicativo e então usar os resultados como cha- ves. 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 ser- vidor 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 vulnerabilida- de. Se você conseguir resolver essas questões, terá um cache distribuído extremamente rápido que não o dei- xará 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 memcachedpraticamentegeraapenas hashes. Como resultado, é possível usar até computadores mais velhos como provedores de cache.  n 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 } Gostou do artigo? Queremos ouvir sua opinião. Fale conosco em cartas@linuxmagazine.com.br Este artigo no nosso site: http://lnm.com.br/article/3114 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