PHP + Redis платформа “Ключ=Значение”
![]()
Что такое и зачем нужны базы данных Ключ=Значение мы рассматривали ранее. Преимущества перед РСУБД в своем классе задач очевидные. Технических решений сегодня множество, и сегодня мы поговорим об одном из них - Redis.
Отличительной особенностью этого продукта в том, что он поддерживает атомарные операции работы со списками и наборами объектов. Сегодня опробуем это решение на практике.
PHP Платформа
В качестве библиотеки для работы с redis возьмем платформу php-redis. Это не просто протокольная обертка, а целая платформа для работы с данными. В ее состав входят:
- Класс для работы с redis
- Пул для хранения соединений
- Базовый класс для работы со скалярными сущностями
- Базовый класс для работы со списками
- Тесты
- Примеры
Эта библиотека опирается на функциональность Redis версии 1.0.
Установка
Первое, что нужно поставить это redis, качаем тут: http://code.google.com/p/redis/downloads/list
tar -xvf redis-1.0.tar.gz cd redis-1.0 make
После этого необходимо изменить базовые настройки (необязательно) в файле redis.conf. Единственная опция, которую следует поменять:
daemonize yes
Запускаем redis:
./redis-server redis.conf
И проверяем доступность:
telnet localhost 6379 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. PING +PONG
Теперь необходимо установить php-redis платформу, для этого нужно только скачать ее последнюю версию.
Простой пример
Для начала следует выполнить тесты, входящие в поставку платформы и убедиться, что все они пройдены:
cd php-redis/tests php unit.all.php
На экране будут видны результаты тестов, самая нижняя строчка должна заканчиваться нулем:
... Failed: 0
Теперь напишем простой пример:
require_once 'php-redis/lib/redis.php';
$r = new php_redis('localhost', 6379);
$r->set('test', 'Hi! ' . time());
echo $r->get('test');
Этот пример просто записывает приветствие с юникс временем по ключу test и выводит его на экран.
Поехали!
Предыдущий пример не отражал особенностей платформы php-redis. Самое важное в ней, это набор базового функционала для работы со скалярными сущностями и списками. Рассмотрим на реальном примере. Допустим мы хотим написать систему личной переписки. Это кстати одна из самых нагруженных частей социальных сетей.
Отправные данные:
- Пользователи будут определяться своими ID,пример реализации системы авторизации смотрите на сайте php-redis
- Каждое сообщение определяется только текстом, отправителем и временем отправки
- Каждое сообщение имеет два статуса: новое и прочитанное
Анализ задачи
Исходя из требований, нам понадобится сущность, которая будет описывать одно сообщение. Кадое сообщение будет определяться своим уникальным ID. Для этой задачи хорошо подходит redis_peer класс, реализующий CRUD для простых объектов.
Кроме этого нам понадобится механизм работы со списками сообщений для каждого пользователя. В нашем случае это базовые операции добавления и удаления сообщений, а также получения списка всех сообщений пользователя. Для этого воспользуемся базовым классом redis_list_peer.
Решать задачу будем следующим образом. При написании нового сообщения, будем сохранять его в базе данных, получая его первичный ключ (при сохранении объектов, redis_peer возвращает уникальное число - первичный ключ, по которому затем можно получить этот объект). После этого будем добавлять PK этого сообщения в личный список адресата.
Реализация сущности “сообщение”
Класс redis_peer уже содержит базовые методы insert, delete, update и get. Нам понадобится немного переопределить только метод вставки для более удобного использования:
class message_peer extends redis_peer
{
public function insert( $sender_id, $body )
{
$data = array(
'body' => $body,
'sender_id' => $sender_id,
'ts' => time(),
'status' => 'new'
);
return parent::insert($data);
}
# Метод для установки статуса сообщения в "Прочитанное"
public function mark_as_read( $id )
{
return parent::update($id, array('status' => 'read'));
}
# Метод для установки статуса сообщения в "Новое"
public function mark_as_new( $id )
{
return parent::update($id, array('status' => 'new'));
}
}
Списки сообщений
И так, у каждого пользователя будет свой личный список сообщений. Этот список нам нужно будет получать, добавлять в него сообщения и удалять их:
class messages_list_peer extends redis_list_peer
{
public function insert( $user_id, $message_id )
{
parent::insert($user_id, array('id' => $message_id), false);
}
public function delete( $user_id, $message_id )
{
parent::delete($user_id, array('id' => $message_id));
}
}
Недостяющий кусок
Чтобы было понятно, как и куда все это лепить, рассмотрим пример реализации отправки сообщения:
$current_user_id = $_SESSION['user_id'];
$message_body = trim($_POST['body']);
$receiver_id = (int)$_POST['receiver_id'];
if ( $receiver_id && $message_body )
{
$m = new message_peer();
$id = $m->insert($current_user_id, $message_body);
$ml = new messages_list_peer();
$ml->insert($receiver_id, $id);
}
После этого у адресата в личном списке появится новое сообщение. Реализация страницы личных сообщений будет выглядеть где-то так:
$current_user_id = $_SESSION['user_id'];
$ml = new messages_list_peer();
$list = $ml->get_list($current_user_id);
$m = new message_peer();
foreach ( $list as $row )
{
$message_id = $row['id'];
$message_data = $m->get($message_id);
echo $message_data['sender_id'] . ', ' . date('H:i', $message_data['ts']) . ": ";
echo htmlspecialchars($message_data['body']) . "
";
}
Итог
Базы данных Ключ=Значения представляют очень мощный инструмент. А объем решаемых задач намного увеличивается благодаря таким продуктам, как Redis.
Уважаемые читатели, какие проблемы Вам приходилось встречать (и приходилось ли) при использовании баз данных “Ключ=Значение”?


интересно протестировать множества(sets). загнать 100 тыщ элементов и проверить насколько быстро работает функция http://code.google.com/p/redis/wiki/SismemberCommand
PS вот что выдает wiki. Редис — съедобное растение и выращивается как овощ во многих странах мира.
Только что прогнал редис на 1 мл. С руби апи.
результаты следующие:
- вставка: 69.225462
- чтение: 68.522843
очень даже ничего товарищи.
Уважаемые! А под виндоус есть сборочка? Если есть, подскажите где взять! Плизззз
Другой PHP клиент для редиса: http://rediska.geometria-lab.net
Хотелось бы посмотреть в сравнении с дргуими Ключ=Значения БД (желательно с теми, у кого есть php-либы)
чем SET отличается от LIST?
Какую смысловую нагрузку они несут?
Что лучше хранить в СЕТах а что в ЛИСТах?
@boom
Тут очень хорошо описаны основы Редиса: http://code.google.com/p/redis/wiki/TwitterAlikeExample
Хотелось бы узнать, а существует ли выборка order by в редисе как мускуле? Очень уж интересно как будет работать при высокой нагрузке такая выборка, если она осуществима конечно же.