Muita gente já deve ter ouvido falar nos bancos de dados NoSQL e uma das suas ferramentas muito utilizada é o Memcached, no qual adicionamos uma camada de cache entre a aplicação e o banco de dados. Desde a versão 5.6 do MySQL, foi disponibilizado um plugin de integração entre o MySQL e o Memcached e neste artigo vamos aprender como instalar no Linux, além de alguns comandos básicos para configurá-lo de modo que atenda as nossas demandas.
Pré-requisitos: instalar libevent
Instalação
Para instalar o suporte ao Memcached, vamos precisar criar algumas tabelas que vão fazer parte da integração entre o MySQL e o Memcached. As distribuições do MySQL já incluem um arquivo innodb_memcached_config.sql que contém essas tabelas no diretório base do MySQL (basedir). Para descobrir qual o basedir na sua instalação:
mysql> SHOW VARIABLES LIKE 'basedir'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | basedir | /usr | +---------------+-------+ 1 row in set (0.00 sec)
Se você instalou o MySQL via o repositório da sua distribuição, o caminho será o seguinte:
$basedir/share/mysql/innodb_memcached_config.sql
Caso esteja utilizando os binários fornecidos pelo MySQL, o caminho será o seguinte:
$basedir/share/innodb_memcached_config.sql
Agora vamos precisar rodar este arquivo .sql. Por default, o plugin cria uma tabela test no banco de dados test, porém neste nosso teste, iremos armazenar os dados do Memcached na tabela dados do banco Memcached:
mysql> CREATE DATABASE IF NOT EXISTS test; Query OK, 1 row affected (0.00 sec) mysql> source /usr/share/mysql/innodb_memcached_config.sql Query OK, 1 row affected (0.00 sec) Database changed Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.03 sec) Query OK, 0 rows affected (0.04 sec) Query OK, 1 row affected (0.00 sec) Query OK, 1 row affected (0.01 sec) Query OK, 1 row affected (0.00 sec) Query OK, 1 row affected (0.02 sec) Database changed Query OK, 0 rows affected (0.03 sec) Query OK, 1 row affected (0.01 sec) mysql> CREATE DATABASE IF NOT EXISTS memcached; Query OK, 1 row affected (0.00 sec) mysql> CREATE TABLE memcached.dados LIKE test.demo_test; Query OK, 0 rows affected (0.02 sec) mysql> UPDATE innodb_memcache.containers SET db_schema = 'memcached', db_table = 'dados' WHERE name = 'aaa' LIMIT 1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> DROP DATABASE test; Query OK, 1 row affected (0.07 sec)
O próximo passo é instalar o plugin do Memcached no MySQL. Para isso, vamos usar o comando INSTALL PLUGIN:
mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so"; Query OK, 0 rows affected (0.01 sec)
Para verificar se o plugin foi instalado com sucesso, digite o comando a seguir e verifique se o processo do MySQL está escutando na porta 11211 (ou a porta que você configurou o Memcached):
mysql> \! netstat -tunap | grep LIST | grep mysql tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 2032/mysqld tcp 0 0 :::11211 :::* LISTEN 2032/mysqld tcp 0 0 :::3306 :::* LISTEN 2032/mysqld mysql>
Utilização e configuração
Agora vamos testar o Memcached via uma linguagem de programação, neste caso o PHP:
[root@localhost memcache]# cat test1.php <?php $m = new Memcached(); $m->addServer('localhost', 11211); $m->set('key1', 'Testando memcached'); echo 'Valor de key1 é:' . $m->get('key1') . "\n"; ?> [root@localhost memcache]# php test1.php Valor de key1 é:Testando memcached [root@localhost memcache]#
Agora vamos ver o que está armazenado no MySQL:
mysql> SELECT * FROM memcached.dados; +------+--------------------+------+------+------+ | c1 | c2 | c3 | c4 | c5 | +------+--------------------+------+------+------+ | key1 | Testando memcached | 0 | 19 | 0 | +------+--------------------+------+------+------+ 1 row in set (0.00 sec) mysql>
E o que acontece se alterarmos um registro diretamente no MySQL?
mysql> UPDATE memcached.dados SET c2 = 'Registro modificado diretamente no MySQL'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 [root@localhost memcache]# cat test2.php <?php $m = new Memcached(); $m->addServer('localhost', 11211); echo 'Valor de key1 é:' . $m->get('key1') . "\n"; ?> [root@localhost memcache]# php test2.php Valor de key1 é:Registro modificado diretamente no MySQL [root@localhost memcache]#
E se quisermos direcionar os registros para diferentes tabelas no MySQL? Basta adicionar um novo container e utilizar o delimiter que está configurado na tabela config_options do banco innodb_memcache:
mysql> SELECT * FROM innodb_memcache.config_options WHERE name = 'table_map_delimiter'; +---------------------+-------+ | name | value | +---------------------+-------+ | table_map_delimiter | . | +---------------------+-------+ 1 row in set (0.00 sec) mysql> CREATE TABLE memcached.dados2 LIKE memcached.dados; Query OK, 0 rows affected (0.04 sec) mysql> INSERT INTO innodb_memcache.containers (name, db_schema, db_table, key_columns, value_columns, flags, cas_column, expire_time_column, unique_idx_name_on_key) VALUES ('bbb', 'memcached', 'dados2', 'c1', 'c2', 'c3','c4','c5','PRIMARY'); Query OK, 1 row affected (0.01 sec)
Criamos uma tabela chamada dados2 e adicionamos uma entrada na tabela containers do banco innodb_memcache com o nome de bbb. Agora basta passar o nome do container na chave do Memcache para distinguir as tabelas:
[root@localhost memcache]# cat test3.php <?php $m = new Memcached(); $m->addServer('localhost', 11211); $m->set('@@bbb.key1', 'Deve ser armazenado na tabela dados2'); echo 'Valor de bbb.key1 é:' . $m->get('@@bbb.key1') . "\n"; ?> [root@localhost memcache]# php test3.php Valor de bbb.key1 é:Deve ser armazenado na tabela dados2 [root@localhost memcache]# mysql> SELECT * FROM memcached.dados2; +------+--------------------------------------+------+------+------+ | c1 | c2 | c3 | c4 | c5 | +------+--------------------------------------+------+------+------+ | key1 | Deve ser armazenado na tabela dados2 | 0 | 22 | 0 | +------+--------------------------------------+------+------+------+ 1 row in set (0.00 sec)
Podemos também mapear uma tabela para que o valor seja separado entre mais de uma coluna. Verifique na tabela config_options do banco innodb_memcache que já temos um separator:
mysql> SELECT * FROM innodb_memcache.config_options WHERE name = 'separator'; +-----------+-------+ | name | value | +-----------+-------+ | separator | | | +-----------+-------+ 1 row in set (0.00 sec)
Este caractere é o que vamos utilizar para armazenar os valores em múltiplas colunas. Crie uma tabela e a adicione no container (nele, basta separar as colunas por vírgula):
mysql> CREATE TABLE produtos (id varchar(128), nome varchar(255), valor varchar(15), c3 int, c4 bigint, c5 int, PRIMARY KEY(id)); Query OK, 0 rows affected (0.03 sec) mysql> INSERT INTO innodb_memcache.containers (name, db_schema, db_table, key_columns, value_columns, flags, cas_column, expire_time_column, unique_idx_name_on_key) VALUES ('produtos', 'memcached', 'produtos', 'id', 'nome,valor', 'c3','c4','c5','PRIMARY'); Query OK, 1 row affected (0.00 sec)
Agora vamos criar um array de produtos e inseri-los via Memcached:
[root@localhost memcache]# cat test4.php <?php $m = new Memcached(); $m->addServer('localhost', 11211); $produtos = array( array('1', 'TV', '1999,00'), array('2', 'Hack', '399,00'), array('3', 'Mesa', '599,00'), array('4', 'Cadeira', '99,00') ); foreach($produtos as $produto) { $key = '@@produtos.' . $produto[0]; $value = $produto[1] . '|' . $produto[2]; $m->set($key, $value); } ?> [root@localhost memcache]# php test4.php mysql> SELECT * FROM memcached.produtos; +----+---------+---------+------+------+------+ | id | nome | valor | c3 | c4 | c5 | +----+---------+---------+------+------+------+ | 1 | TV | 1999,00 | 0 | 23 | 0 | | 2 | Hack | 399,00 | 0 | 24 | 0 | | 3 | Mesa | 599,00 | 0 | 25 | 0 | | 4 | Cadeira | 99,00 | 0 | 26 | 0 | +----+---------+---------+------+------+------+ 4 rows in set (0.00 sec)
SELinux
Em ambientes onde temos o SELinux rodando, ele pode bloquear o Memcached de funcionar, pois o MySQL não está autorizado a utilizar a porta do Memcached – fica aqui uma dica de como solucionar o problema (estou utilizando CentOS como Linux distro):
Procure por entradas contendo as chaves mysqld e denied no arquivo de logs /var/logs/audit/audit.log, caso as encontre, digite os comandos abaixo para criar um novo módulo no SELinux, que ira permitir o MySQL escutar também na porta do Memcached:
type=AVC msg=audit(1421080542.433:31): avc: denied { name_bind } for pid=1360 comm="mysqld" src=11211 scontext=unconfined_u:system_r:mysqld_t:s0 tcontext=system_u:object_r:memcache_port_t:s0 tclass=tcp_socket type=SYSCALL msg=audit(1421080542.433:31): arch=c000003e syscall=49 success=no exit=-13 a0=2d a1=7f5fcc0409a0 a2=10 a3=7f5fe0ee275c items=0 ppid=1123 pid=1360 auid=0 uid=27 gid=27 euid=27 suid=27 fsuid=27 egid=27 sgid=27 fsgid=27 tty=pts0 ses=2 comm="mysqld" exe="/usr/sbin/mysqld" subj=unconfined_u:system_r:mysqld_t:s0 key=(null) audit2why < /var/log/audit/audit.log cd /root/ mkdir selinux-custom cd selinux-custom audit2allow -a -M mysql-memcache semodule -i mysql-memcache.pp
Opções do memcached
Caso queira modificar qualquer configuração do memcached, adicione as configurações no arquivo de configuração do MySQL utilizando a variável daemon_memcached_option. Por exemplo, para alterar a porta padrão:
#no arquivo de configuração (normalmente my.cnf) daemon_memcached_option="-p11222"
É isto aí, pessoal! Espero que tenham aprendido a instalar e configurar o plugin do Memcached.
Até a próxima!