Skip to main content
Posted in

Помимо sql баз данных, вроде использованного ранее MySQL, Postgres, Oracle и т.д. есть целый класс хранилищ данных, которые не поддерживают парадигму SQL. Они хранят данные в виде ключ-значение. Примеры таких баз - memcached, redis. Обе базы хранят данные в памяти, поэтому доступ к ним очень быстрый. Memcached сам по себе не умеет сохранять данные на диск, а вот Redis умеет, что делает его хорошим кандидатом для хранилища данных. Еще есть memcachedb - распределенное ключ-значение хранилище, которое сохраняет данные на диске, но оно не обновлялось уже почти три года.

В чем же суть ключ-значение хранилища? Фактически вы работаете с ним как с ассоциативным массивом - обращаясь каждый раз к отдельным ключам массива. Давайте поработаем в Редисом из пхп. С установкой Редиса разберитесь сами,

Возьмем в качестве клиента библиотеку predis. Вот простой тестовый скрипт, комментарии добавляю прямо в код:

<?php

require_once(__DIR__ . '/../lib/Predis.php');// подключили библиотеку
require_once(__DIR__ . '/../lib/Predis_Compatibility.php');

$single_server = array( // задали параметры подключения
    'host'     => '127.0.0.1', 
    'port'     => 6379
);

$redis = new Predis_Client($single_server);// объект для работы с Редисом

$redis->set('library', 'predis');// установили ключ 'library' в значение 'predis'
$retval = $redis->get('library');// получили значение ключа 'library'

var_dump($retval);// посмотрели что получилось

var_dump($redis->expire('library', 100));// установили время жизни ключа 10 сек и посмотрели удачно ли

Хранение данных пользователя

Итак, как же Редис может хранить наши данные о пользователях? Прежде всего, он может хранить строки, как мы уже убедились на примере. А в строку можно сериализовать массив - ряд из БД. Что нибудь вроде такого

$user_id = 101;
$key_user = 'user_'.$user_id;
$user_data = array(
'login' => 'vasyap',
'password' => 'dzenaum',
'fio' => 'Вася Пупкин',
);

$redis->set($key_user, serialize($user_data));// записали сериализованные данные

$out = $redis->get($key_user);// получили значение ключа

var_dump(unserialize($out)); // получили данные из Редиса

Попробуйте, должно работать.

Можно для каждого поля в $user_data использовать свой ключ, например так

$user_id = 101;
$user_data = array(
'login' => 'vasyap',
'password' => 'dzenaum',
'fio' => 'Вася Пупкин',
);

$redis->set('user:login:'.$user_id, $user_data['login']);
$redis->set('user:password:'.$user_id, $user_data['password']);
$redis->set('user:fio:'.$user_id, $user_data['fio']);

Мне такой подход не очень нравится, так как плодится очень много ключей, которые сложнее обслуживать.

Для хранения данных пользователя можно использовать хеш

$user_id = 101;
$key_user = 'user_'.$user_id;
$user_data = array(
'login' => 'vasyap',
'password' => 'dzenaum',
'fio' => 'Вася Пупкин',
);

$redis->hmset($key_user, $user_data);

$ret = $redis->hgetall($key_user);

var_dump($ret);

причем в хеше можно обращаться к отдельным ключам. Наверно так удобнее всего.

Уникальность

Как мы можем в Редисе проверить уникальность логина или е-мейла? Перебирать все данные пользователя для ответа на этот вопрос - плохая идея. Решение такое: на каждого пользователя заведем ключ 'user_login_'.$login , где $login реальное значение логина. Для проверки на уникальность будем просто проверять наличие данных с таким ключом.

$redis->set('user_login_'.'ivan', 1);
$redis->set('user_login_'.'olga', 1);

function is_login_exist($login) { // проверка на уникальность
    global $redis;
    $key_login = 'user_login_'.$login;
    $ret = $redis->get($key_login);
    return $ret != Null;
}

var_dump(is_login_exist('ivan')); // return true
var_dump(is_login_exist('olga')); // return true
var_dump(is_login_exist('vasyap')); // return false

Уникальный ид

Обеспечить уникальный ид можно с помощью дополнительного ключа и комаyды incr, которая атомарна (на каждое обращение вернет уникальное значение).

function next_user_id() {
    global $redis;
    $next_user_id_key = 'next_user_id_key';
    return $redis->incr($next_user_id_key);
}

echo next_user_id()."\n"; // 1
echo next_user_id()."\n"; // 2
echo next_user_id()."\n"; // 3