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