Este artigo ensina como utilizar o servidor de cache Memcached com o framework em PHP Zend Framework. O Libmemcached é uma biblioteca em C que faz a comunicação com o servidor de Memcached e para isso é necessário a biblioteca memcached do PECL (PHP Extension Community Library) – esta lib é instanciada através de código PHP na aplicação em Zend Framework. O ambiente utilizado é Linux (tanto para o servidor web quanto para o servidor de cache).
Passo 1: Instalação Memcached
No Ubuntu, para instalar o servidor Memcached usando o apt-get:
sudo apt-get install memcached
Por padrão, o servidor Memcahed irá atender na porta 11211. Caso você tenha problemas com o apt-get, será necessário baixar o Memcached do site oficial (ver link em Referências), descompactar, compilar e instalar.
Passo 2: Instalação Libmemcached
Instale a Libmemcached. Esta library é uma API em C para se comunicar com o servidor Memcached. Depois, baixe e instale diretamente do site oficial (ver link em Referências). Será necessário descompactar, compilar e instalar o arquivo .tar.gz disponibilizado para download no site oficial.
Uma opção mais fácil é usar o apt-get do Linux:
sudo apt-get install libmemcached5
Passo 3: Instalação lib memcached do PECL
Instale a lib cliente que se comunica com a Libmemcached, em nosso caso utilizamos a lib memcached do PECL. Para instalar, foi necessário compilar o arquivo fonte e executar alguns procedimentos:
- Faça o download da lib memcached no site oficial do PECL (ver link em Referencias);
- Faça a instalação e lembre-se de rodar o comando configure informando o diretório da Libmemcached (Passo 2) – geralmente ela é instalada sob o diretorio “/usr/lib”. No meu caso, utilizei o comando configure da seguinte forma: ./configure –with-libmemcached-dir=/usr/lib;
- Copiar o arquivo gerado “memcached.so”. Este arquivo será gerado na pasta “/modules”, para a pasta de libs do PHP, por exemplo: “/usr/lib/php5/20100525+lfs/”;
- Copiar o conteúdo do arquivo memcached.ini para o arquivo php.ini do PHP – geralmente fica em “/etc/php5”.
Opção mais simples, mas que não funcionou comigo, é utilizar o apt-get:
sudo apt-get install php5-memcached
Passo 4: Rode um exemplo PHP simples
Reinicie o servidor web e rode um exemplo em PHP simples para testar. Exemplo a seguir:
Arquivo “memcached.php”
$mc = new Memcached(); $mc->addServer("localhost", 11211); $mc->set("Nome", "Necessario para uma nova tentativa de ação!"); $mc->set("Quem", "Alguem..."); $mc->set("foo", "Hello!"); $mc->set("bar", "Memcached..."); $arr = array( $mc->get("Nome"), $mc->get("Quem") , $mc->get("foo"), $mc->get("bar") ); var_dump($arr);
Rode no browser: http://localhost/memcached.php
Passo 5: Rode um exemplo com Zend_Cache
Exemplo com o Zend_Cache. Instanciando a classe de configuração do Zend_Cache no Bootstrap do Zend Framework e criando a classe que configura a instância do Zend_Cache da sua aplicação.
A classe a seguir, BootstrapCache, configura e instancia a classe Zend_Cache, responsável por inserir, recuperar e apagar dados do servidor de cache. A classe BootstrapCache deve ser chamada de forma estática no bootstrap (/application/Bootstrap.php) do Zend Framework, lembrando que este artigo cobre a versão 1.12 do ZF. Observe:
Arquivo “/application/Bootstrap.php”
/** * Inicializa camada de cache: filesystem ou memcached */ protected function _initCache() { //pattern Command BootstrapCache::execute(); }
A classe BootstrapCache é responsavel pela configuração do cache da aplicação.
Arquivo “/lib/BootstrapCache.php”
class BootstrapCache { /** * host para instancia do server Memcached * * @var string */ protected $hostMemcache; /** * configuracoes para cache Conteudo site */ protected $tipoCacheConteudo; //Libmemcached, File, None protected $lifetimeConteudo; protected $pathCacheConteudo; public function __construct() {} /** * desgin pattern Command */ public static function execute() { //instancia cache: $camadaCache = new BootstrapCache(); //recupera configuracao do Cache no config.ini $camadaCache->setHostMemcache(Zend_Registry::get('config')->cache->host->memcached); $camadaCache->setTipoCacheConteudo(Zend_Registry::get('config')->cache->Conteudo->tipo); $camadaCache->setLifetimeConteudo(Zend_Registry::get('config')->cache->Conteudo->lifetime); $camadaCache->setPathCacheConteudo(Zend_Registry::get('config')->cache->Conteudo->pathcache); $camadaCache->cacheConteudo(); } /** * @return array */ private function configApp() { $hostMemcache = $this->getHostMemcache(); //dir do filesystem $path_cache = $this->getPathCacheConteudo(); switch ($this->getTipoCacheConteudo()) { case 'File': $appfrontendConteudo = array( 'lifetime' => $this->getLifetimeConteudo(), //seconds 'automatic_serialization' => true, //'debug_header' => true, ); $appbackendConteudo = array( 'cache_dir' => $path_cache ); break; case 'Libmemcached': case 'Memcached': $appfrontendConteudo = array( 'lifetime' => $this->getLifetimeConteudo(), //seconds 'automatic_serialization' => true, 'caching' => true, ); $appbackendConteudo = array( 'servers' => array( array( 'host' => $hostMemcache, 'port' => 11211, 'weight' => 1 ) ), 'compression' => false ); break; } //end switch return array ( 'Conteudo' => array( 'frontend' => $appfrontendConteudo, 'backend' => $appbackendConteudo ), ); } /** * faz cache de conteudo site */ public function cacheConteudo() { //seta configuracoes para o cache $arrConfig = $this->configApp(); $appfrontend = $arrConfig['Conteudo']['frontend']; $appbackend = $arrConfig['Conteudo']['backend']; $appcache = Zend_Cache::factory('Core', $this->getTipoCacheConteudo(), $appfrontend, $appbackend ); // adiciona cache no Registry Zend_Registry::set('cache_Conteudo', $appcache); } //codigo omitido //getters e setters }
Passo 6: Classe ConteudoCache
Para gravar e recuperar o conteúdo do Memcached utilize o exemplo da classe a seguir:
Arquivo “/lib/ConteudoCache.php”
/** * Metodos que instanciam Zend_Cache para fazer cache que areas do site * * @author esilva */ class ConteudoCache { /** * @var Zend_Cache_Core */ protected $cache; public function __construct() { //instancia Zend_Cache_Core $this->cache = Zend_Registry::get('cache_Conteudo'); } /** * faz cache de areas de conteudo do site * * @param DbTable_ConteudoRow $dbtableConteudoRow * @return array */ public function recuperaOuGravaConteudoNoCache(DbTable_ConteudoRow $dbtableConteudoRow, $idConteudo) { $nameCache = "conteudo_".$idConteudo; $blocoCacheModel = $this->cache->load($nameCache); $msgCache = "pegou do cache"; if (!$blocoCacheModel) { $blocoCacheModel = $dbtableQuestionnaireRow->getAll($idConteudo); $this->cache->save($blocoCacheModel, $nameCache); $msgCache = "NÂO pegou do cache"; } return $blocoCacheModel; } }
O metodo “recuperaOuGravaConteudoNoCache” da classe “ConteudoCache” recebe como parâmetro uma instância DbTable, que é basicamente um fetchall de uma tabela do banco de dados. O parâmetro $idConteudo é o id único que identifica o conteúdo que está sendo cacheado ou se deseja recuperar do cache.
Informações de configuração, como o host do Memcached, tipo de cache (Libmemcached ou File), tempo de vida do cache e caminho para o filesystem, são armazenados no arquivo “config.ini” da sua aplicação Zend Framework. Se vocês observaram bem, o código também estaápreparado para cachear no filesystem da aplicação, sendo necessário apenas passar a string “FILE” na configuração do parâmetro “cache.conteudo.tipo”, no arquivo “config.ini”.
Passo 7: Arquivo config.ini
Os dados de configuração do cache estão no arquivo “config.ini” (/application/configs/config.ini):
Arquivo “/application/configs/config.ini”
cache.host.memcached = "localhost"; cache.conteudo.tipo = "Libmemcached"; //File //Libmemcached //None cache.conteudo.lifetime = 900; //15min cache.conteudo.pathcache = APPLICATION_PATH_CACHE "/cacheConteudo";
Repare que o método estático “execute” da classe BootstrapCache recupera os dados do arquivo “config.ini”, utilizando o Zend_Registry.
Passo 8: Classe Model_ConteudoQuestoes
Na classe model de conteúdo será necessário instanciar a classe ConteudoCache e informar o Id do conteúdo que deve ser recuperado.
Arquivo “/application/model/ConteudoQuestoes.php”
class Model_ConteudoQuestoes { // // codigo omitido // public function cacheOrModelConteudoId($conteudoId) { $conteudoCache = new ConteudoCache(); $resultado = $conteudoCache->recuperaOuGravaConteudoNoCache($this, $conteudoId) return $resultado; } public function getAll($idConteudo) { // codigo omitido // $fetchAll recupera dados de conteudo do banco de dados //retorno com conteudo do banco dados return $fetchAll; } }
O parâmetro $this informado no metodo “recuperaOuGravaConteudoNoCache” refere-se a própria classe model onde se encontra o método “cacheOrModelConteudoId”. Ele é ‘injetado’ na classe ConteudoCache.
Dentro da classe ConteudoCache, no metodo “recuperaOuGravaConteudoNoCache”, é feita a chamada a “$dbtableQuestionnaireRow->getAll();” caso o conteúdo não seja encontrado no servidor de cache. Essa chamada é o mesmo que $this->getAll() na classe Model_ConteudoQuestoes.
Na action do controller que recebe o array (fetchall) de conteúdo do banco de dados faça uma chamada ao método “cacheOrModelConteudoId” informando o Id de conteúdo que será recuperado e enviado para a view.
Por exemplo:
$conteudoId = 101; //Informacoes das questões para o cliente $this->view->conteudoParaCliente = $this->ModelConteudo->cacheOrModelConteudoId($conteudoId);
Esta chamada na action retorna o conteúdo de questões para a view, porém, este conteúdo poderá ser do banco de dados ou do Memcached. O método “cacheOrModelConteudoId” é responsável apenas por devolver o conteúdo para a action, que então disponibiliza o conteúdo para a view.
Conclusão
Este é um passo a passo para usuários com experiência em Linux e Zend Framework. O objetivo foi informar os passos necessários e o que é preciso para se chegar ao objetivo final, que é obter um servidor de cache Memcached configurado e recebendo requisições de uma aplicação web desenvolvida em Zend Framework.