Memcached: установка, примеры

By | 05/30/2018
 

Memcached – ещё одна key:value система кеширования, аналогичная Redis.

Основное ограничение и отличие – memcached не хранит данные постоянно, т.е. при рестарте сервера данные из памяти будут утеряны.

Кратко её установка и примеры использования.

Установка

pacman

На Arch Linux можно установить из репозитория с помощью pacman:

sudo pacman -S memcached

Debian/Ubuntu – с помощью apt, заодно PHP и NGINX для примеров:

apt install -y memcached php nginx mariadb-server php-mysql php-memcached

Docker

Либо запустить из Docker образа:

docker run --name memcached -p 11211:12111 memcached

Файл настроек – /etc/memcached.conf.

Подключение, команды

memcached сервер принимает подключения на порт 11211, и подключиться к нему можно даже просто telnet (или передавать команды через netcat – см. примеры ниже)

root@ip-172-31-12-178:~# telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

После чего можно добавлять/получать данные.

Аттрибуты

Основные аттрибуты, которые задаются данным в кеше:

Аттрибут Описание
key имя ключа, максимальная длина 250 байт
flag 32-х битная целочисленное, обычно можн оустановить в 0
exptime время жизни объекта в кеше в секундах – 0 хранить всегда=
bytes кол-во байт, которые необходимо выделить для хранения значения
noreply опциональный параметр, что бы сервер не оптравлял ответа после выполнения запроса
value значение, которое необюходимо доабвить в кеш

set

Добавить значение можно с помощью set.

Синтаксис:

set key flags exptime bytes [noreply] (ENTER)
value

Добавляем ключ с имнем key_name, без флага, таймаут хранения 100 секунд, резервируем 5 байт:

set key_name 0 100 5
value
STORED

get

Получаем его с помощью get:

get key_name
VALUE key_name 0 5
value
END

add

Добавит ключ:значение, только если для ключа ещё нет значения в кеше.

Добавляем ключ:

set key_name 0 1000 6
qwerty
STORED

Пробуем добавить значение:

add key_name 0 1000 6
ytrewq
NOT_STORED

И в новый ключ:

add key_name2 0 1000 6
ytrewq
STORED

delete

Что бы удалить ключ:значение – вызываем delete:

delete key_name2
DELETED

Теперь get вернёт пустой объект:

get key_name2
END

Больше примеров тут>>> и тут>>>.

Memcached и PHP

Настраиваем NGINX – редиректим запросы к PHP на PHP-FPM, в файле /etc/nginx/sites-enabled/default задаём:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.php;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }

}

FPM уже принимает подключения через сокет:

root@ip-172-31-12-178:~# cat /etc/php/7.0/fpm/pool.d/www.conf | grep ^listen
listen = /run/php/php7.0-fpm.sock

Перезагружаем конфиги NGINX:

root@ip-172-31-12-178:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@ip-172-31-12-178:~# service nginx reload

Создаём страницу с phpinfo():

root@ip-172-31-12-178:~# cat /var/www/html/index.php
<?php
phpinfo();
?>

Проверяем:

Создадим страницу, файл /var/www/html/cache_tests.php, с которой будем запрашивать и добавлять данные из кеша:

<?php
$mem = new Memcached();
$mem->addServer("127.0.0.1", 11211);
?>

Тут создаётся PHP Memcached объект, который сохраняется в переменной $mem, и подключается к локальному серверу на порт 11211.

Далее – пробуем получить ключ с именем key_name из кеша:

...
$result = $mem->get("key_name");
...

И добавляем проверку: если значение получено – то выводим его в браузер, если ключа в кеше нет – добавляем его туда:

<?php

$mem = new Memcached();
$mem->addServer("127.0.0.1", 11211);

$result = $mem->get("key_name");

if ($result) {
    echo $result;
} else {
    echo "No key found. Adding key to cache.";
    $mem->set("key_name", "Key_name's value from memcached!") or die ("Couldn't save anything to memcached...");
}

?>

Проверяем:

root@ip-172-31-12-178:~# curl localhost/cache_tests.php
No key found. Adding key to cache.

Повторяем запрос:

root@ip-172-31-12-178:~# curl localhost/cache_tests.php
Key_name's value from memcached!

И напрямую из memcached:

root@ip-172-31-12-178:~# echo "get key_name" | nc localhost 11211
VALUE key_name 0 32
Key_name's value from memcached!
END

Кеширование запросов из MySQL

В следующем примере – сохраним в memcached результат запроса из MariaDB базы.

MySQL база

Подключаемся к серверу БД:

root@ip-172-31-12-178:~# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 50
...
MariaDB [(none)]>

Создаём базу:

MariaDB [(none)]> CREATE DATABASE memcached_test;

Переключаемся на неё:

MariaDB [(none)]> use memcached_test;
Database changed

Создаём пользователя с правами на эту базу:

MariaDB [memcached_test]> GRANT ALL ON memcached_test.* TO memcached_test@localhost IDENTIFIED BY 'password';

Создаём таблицу:

MariaDB [memcached_test]> CREATE TABLE db_data (id int, name varchar(30));

Добавляем в неё запись:

MariaDB [memcached_test]> INSERT INTO db_data VALUES (1, "some_data");

Проверяем:

MariaDB [memcached_test]> select * from db_data;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | some_data |
+------+-----------+

PHP скрипт

Скрипт /var/www/html/db_test.php будет пробовать получить данные из memcahed, если их нет – то выполнит запрос напряую к БД, и добавит данные в memcached.

Обновляем /etc/php/7.0/fpm/php.ini, убираем комментарий ; перед php_mysqli.dll:

...
extension=php_mysqli.dll
...

Добавляем подключение к memcached, аналогично первому примеру, и второе подключение – к MySQL:

<?php

$mem = new Memcached();
$mem->addServer("127.0.0.1", 11211);

$connection = mysqli_connect("localhost", "memcached_test", "password");
mysqli_select_db($connection, "memcached_test");

?>

Добавляем переменную $query, в которой будет сам запрос к БД, и переменную $querykey, в которой сгенерируем ключ, который будет использоваться в memchached для получения данных:

...
$query = "SELECT ID FROM db_data WHERE name = 'some_data'" or die(mysqli_error($connection));
$querykey = "KEY" . md5($query) or die(mysqli_error($connection));
...

Добавляем переменную $result, в которой будет результат, который мы получаем из memcached:

...
$result = $mem->get($querykey);
...

Далее добавляем логику: если $result пустой – то обращаемся напрямую к MySQL, получаем данные, и записываем их в memchaced с помощью set($querykey, $result, 10), если данные найдены – то выводим их в браузер:

<?php

$mem = new Memcached();
$mem->addServer("127.0.0.1", 11211);


$connection = mysqli_connect("localhost", "memcached_test", "password");
mysqli_select_db($connection, "memcached_test");


$query = "SELECT ID FROM db_data WHERE name = 'some_data'" or die(mysqli_error($connection));
$querykey = "KEY" . md5($query) or die(mysqli_error($connection));


$result = $mem->get($querykey);


if ($result) {
    print "<p>Data retrieved from memcached: " . $result[0] . "</p>";
} else {
    $result = mysqli_fetch_array(mysqli_query($connection, $query)) or die(mysqli_error($connection));
    $mem->set($querykey, $result, 10);
    print "<p>Data retrieved from MySQL: " . $result[0] . "</p>";
    print "<p>Data not found in memcached.</p><p>Stored in memcached for next time.</p>";
}

?>

Проверяем:

Обновляем страницу:

Теперь данные в memcached.

Проверяем напрямую из него – добавим вывод ключа:

...
} else {
    $result = mysqli_fetch_array(mysqli_query($connection, $query)) or die(mysqli_error($connection));
    $mem->set($querykey, $result, 10);
    print "<p>Data retrieved from MySQL: " . $result[0] . "</p>";
    print "<p>Data not found in memcached.</p><p>Stored in memcached for next time.</p>";
    print "<p>Memcached key: $querykey.</p>";
}
...

Обновляем страницу, копируем ключ:

Запрашиваем его из memcached (помним, что данные хранятся только 10 секунд):

root@ip-172-31-12-178:~# echo "get KEY18c26b3d9c726e12f7257b600ec91b20" | nc localhost 11211
VALUE KEY18c26b3d9c726e12f7257b600ec91b20 4 53
a:2:{i:0;s:9:"some_data";s:4:"name";s:9:"some_data";}
END

Готово.