Banco de Dados

6 fev, 2015

MySQL e NoSQL – Memcached Plugin

Publicidade

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!