Pull to refresh

Новый Redis 2.0 и Rediska 0.5.0!

PHP *
RediskaДорогие друзья! На прошлой неделе вышел стабильный релиз чудесной key-value базы Redis версии 2.0 с внушающим количеством нововведений. Эта новость особенно нас обрадовала, так как мы уже год используем Redis в наших нагруженных проектах и впечатления только положительные. Мы обновили PHP клиент Rediska, добавив поддержку новых возможностей.




Основные нововведения Redis 2.0


Транзакции (MULTI/EXEC/DISCARD)

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

Первый пользователь изъявляет желание дружить со вторым пользователем:
  1. Мы добавляем ID первого пользователя в множество (Set — неупорядоченное множество уникальных элементов) второго пользователя users:2:requests в котором храним запросы.
Второй пользователь не против:
  1. Удаляем из множества users:2:requests ID первого пользователя.
  2. Добавляем ID первого пользователя в множество users:2:friends с друзьями второго пользователя.
  3. Добавляем ID второго пользователя в множество users:1:friends с друзьями первого, для взаимности.
Если одна из операций не выполнится, или у нас будут конкурентные операции, то коллапса не избежать. Тут нам на помощь приходят транзакции.

<?php

$rediska = new Rediska();

/*
 * Первый пользователь изъявляет желание дружить со вторым пользователем
 */
$rediska->addToSet('users:2:requests', 1);

/*
 * Второй пользователь не против
 */
$rediska->transaction()->deleteFromSet('users:2:requests', 1)
                                    ->addToSet('users:2:friends', 1)
                                    ->addToSet('users:1:friends', 2)
                                    ->execute();
?>

Блокирующая операция BLPOP/BRPOP

Атомарные операции BLPOP и BRPOP получают и удаляют первый или последний элемент из списка (List — упорядоченный список элементов). Причем если список пустой, то операции блокируют соединение клиента, пока другой клиент не положит туда элемент.

Например пользователь заливает mp3-трэк Бритни в 320 Kb/s. Нам нужно сконвертировать его в 192 Kb/s. Для этого мы добавляем в очередь задачу на конвертирование. Демон получает задачу из очереди и конвертирует файл. Для реализации очереди замечательно подходят списки.

<?php

$rediska = new Rediska();

// Добавляем файл в начало очереди
$queue = new Rediska_Key_List('queue');
$queue[] = 'britney_spears__and_then_we_kiss.mp3';

// Демон конвертирует файлы
while(true) {
    // Получаем файл из конца очереди
    // Если очередь пуста, то выполнение скрипта блокируется пока не получим из нее файл
    $file = $queue->popBlocking();
    convertFile($file);
}
?>

Publish/Subscribe

Одно из самых замечательных нововведений — реализация парадигмы очереди сообщений Publish/Subscribe. Операция PUBLISH добавляет сообщение в канал, а не конкретным получателям и ничего о них не знает. Операция SUBSCRIBE подписывает на канал или каналы и получает сообщения.

Самый простой пример который приходит в голову — реализация чатов (хотя у Publish/Subscribe есть гораздо более полезные применения).

<?php

$rediska = new Rediska();

// Выводим сообщения общего канала в вечном цикле
// Можно вторым аргументом передать timeout в секундах
foreach($rediska->subscribe('main') as $nickAndMessage) {
    list($nick, $message) = $nickAndMessage;
    print "$nick: $message";
}
?>
<?php

$rediska = new Rediska();

// Вася пишет сообщение в общий канал
$rediska->publish('main', array('Вася', 'Всем чмоки-чмоки в этом чате!'));

?>

Большое спасибо Юре octave за инициативу и помощь в реализации!

Новый тип ключа Hash

Хэш — это ключ, значение которого по сути ассоциативный массив PHP, но в отличии от хранения в строковом ключе сереализованого массива, предоставляет атомарные операции для работы с полями и их значениями.

В хэшах очень удобно хранить объекты или группировать в них строковые ключи для более эффективного использования.

<?php

$rediska = new Rediska();

class User extends Rediska_Key_Hash
{
    public function __construct($id)
    {
        parent::__construct("users:$id");
    } 
}

// Создаем нового пользователя
$user = new User(1);
$user->id = 1;
$user['name'] = 'Вася'; // Можно обращаться к полям как к ключам массива
$user->friendsCount = 0;

// Увеличиваем счетчик друзей
$user = new User(1);
$user->increment('friendsCount');

// Получаем данные пользователя
foreach($user as $field => $value) {
    print "$field => $value";
}
?>

Virtual Memory

Виртуальная память помогает хранить в Redis больше данных чем позволяет размер оперативной памяти. Если кратко, то Redis вымещает из оперативной памяти на диск значения ключей к которым вы реже всего обращаетесь.

Виртуальная память эффективна в том случае, если вы используете часто только небольшой процент ключей или если у ключей большие значения.

Конфигурация Redis сервера

Новая операция CONFIG позволяет читать и изменять конфигурацию Redis сервера.

<?php

$rediska = new Rediska();

// Получаем объект конфига
$config = $rediska->config();

// Получаем параметр
print $config->maxmemory;

// Вы можете обращаться к параметрам как ключам массива
print $config['maxmemory'];

// Устанавливаем параметр
$config->maxmemory = 10000;

// Получаем список параметров по паттерну (glob)
foreach($config['max*'] as $name => $value) {
    print "$name => $value\n";
}

// Получаем весь список параметров
foreach($config as $name => $value) {
    print "$name => $value\n";
}
?>

Новые операции для работы со строковыми ключами

<?php

$rediska = new Rediska();

// Создаем ключ с строкой 'value'
$rediska->set('key', 'value');

// Добавляем строку '-shmalue' в конец
$rediska->append('key', '-shmalue');

// Получаем часть строки
print $rediska->substring('key', 6); #=> malue

// "Комбо" операция set + expire
$rediska->setAndExpire('key', 'value', 60 * 5);

?>

Еще кое-что из новой Редиски


Instance manager

В вашем приложении могут быть компоненты (кэш, сессии, ...), которым требуются разные инстансы Редиски с разными опциями (нэймспейс, сервера, ...).
Класс мэнеджера занимается тем, что хранит в себе эти инстансы и предоставляет методы для их получения, добавления и удаления.
Мэнеджер также может хранить в себе помимо объектов еще и массивы опций Редиски и создавать объекты при первом запросе к ним (lazy-load).

<?php

// Создаем 'default' инстанс
$rediska = new Rediska();

// Получаем 'default' инстанс из мэнеджера
$rediska = Rediska_Manager::get();
print $rediska->getName(); #=> default

// Создаем 'cache' инстанс
$rediska = new Rediska(array('name' => 'cache', 'namespace' => 'Cache_'));

// Получаем 'cache' инстанс из мэнеджера
$rediska = Rediska_Manager::get('cache');
print $rediska->getName(); #=> cache

// Добавляем опции 'sessions' инстанса
Rediska_Manager::add(array('name' => 'sessions', 'namespace' => 'Sessions_'));

// Объект Редиски создается когда он действительно нужен
$rediska = Rediska_Manager::get('sessions');
print $rediska->getName(); #=> sessions

?>

Новый сериалайзер

В новой версии Редиска сериализует только массивы и объекты, строки и числа сохраняются как есть (проблемы с данными сохраненными предыдущими версиями нету).

С помощью опции serializerAdapter вы можете указать метод сереализации:
  • phpSerialize — стандартный сериалайзер PHP (функция serialize). Этот метод используется по умолчанию
  • json — Без комментариев
  • toString — Приводит значение к строке (string)$value
  • Ваш класс который имплементирует интерфейс Rediska_Serializer_Adapter_Interface
Autoloader

Редиска избавилась от require_once и необходимости добавления пути в include_path.

Монитор операций

Реализована операция MONITOR, позволяющая вам в реальном времени наблюдать операции выполняющиеся на Redis серверах.

<?php

$rediska = new Rediska();

// Получаем объект монитора и устанавливаем таймаут две минуты
$monitor = $rediska->monitor(60 * 2);

// Или к примеру мониторим определенный Redis сервер
$monitor = $rediska->on('server1')->monitor();

// Мониторим операции
foreach($monitor as $timestamp => $command) {
    print "$timestamp => $command";
}

?>

В заключении...

Постараюсь больше не грузить вас, скажу лишь что мы начали переписывать Редиску на C++ в виде PHP экстеншена и будем рады желающим поучаствовать.
Tags: redisnosqlkey-valuerediskaphpdatabase
Hubs: PHP
Total votes 72: ↑66 and ↓6 +60
Comments 51
Comments Comments 51

Popular right now

Top of the last 24 hours