Главная > Теория и практика > PHP + Redis платформа “Ключ=Значение”

PHP + Redis платформа “Ключ=Значение”

php-redis-logo-small

Что такое и зачем нужны базы данных Ключ=Значение мы рассматривали ранее. Преимущества перед РСУБД в своем классе задач очевидные. Технических решений сегодня множество, и сегодня мы поговорим об одном из них - Redis.

Отличительной особенностью этого продукта в том, что он поддерживает атомарные операции работы со списками и наборами объектов. Сегодня опробуем это решение на практике.

PHP Платформа

В качестве библиотеки для работы с redis возьмем платформу php-redis. Это не просто протокольная обертка, а целая платформа для работы с данными. В ее состав входят:

  1. Класс для работы с redis
  2. Пул для хранения соединений
  3. Базовый класс для работы со скалярными сущностями
  4. Базовый класс для работы со списками
  5. Тесты
  6. Примеры

Эта библиотека опирается на функциональность 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

Теперь напишем простой пример:

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.

Уважаемые читатели, какие проблемы Вам приходилось встречать (и приходилось ли) при использовании баз данных “Ключ=Значение”?

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com

Статьи по теме

  1. Stas
    7 Октябрь 2009 в 01:22 | #1

    интересно протестировать множества(sets). загнать 100 тыщ элементов и проверить насколько быстро работает функция http://code.google.com/p/redis/wiki/SismemberCommand

    PS вот что выдает wiki. Редис — съедобное растение и выращивается как овощ во многих странах мира.

  2. 8 Октябрь 2009 в 19:47 | #2

    Только что прогнал редис на 1 мл. С руби апи.
    результаты следующие:
    - вставка: 69.225462
    - чтение: 68.522843
    очень даже ничего товарищи.

  3. Ahiles
    11 Октябрь 2009 в 16:33 | #3

    Уважаемые! А под виндоус есть сборочка? Если есть, подскажите где взять! Плизззз

  4. 25 Ноябрь 2009 в 20:26 | #4

    Другой PHP клиент для редиса: http://rediska.geometria-lab.net

  5. boom
    22 Декабрь 2009 в 15:37 | #5

    Хотелось бы посмотреть в сравнении с дргуими Ключ=Значения БД (желательно с теми, у кого есть php-либы)

  6. boom
    27 Декабрь 2009 в 21:51 | #6

    чем SET отличается от LIST?
    Какую смысловую нагрузку они несут?
    Что лучше хранить в СЕТах а что в ЛИСТах?

  7. 28 Декабрь 2009 в 02:50 | #7

    @boom
    Тут очень хорошо описаны основы Редиса: http://code.google.com/p/redis/wiki/TwitterAlikeExample

  8. 5 Апрель 2010 в 01:34 | #8

    Хотелось бы узнать, а существует ли выборка order by в редисе как мускуле? Очень уж интересно как будет работать при высокой нагрузке такая выборка, если она осуществима конечно же.

  1. Пока что нет уведомлений.