Новый Redis 2.0 и Rediska 0.5.0!

    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 экстеншена и будем рады желающим поучаствовать.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 51
    • +5
      Я вот не помню это вас люди в чёрных куртках куда-то увозили?..
      • 0
        Было дело, страшно вспомнить :)
        • +2
          O___o Можно линк?
          • 0
            после того как хабровчане начали активно минусовать ту новость она быстро была уехала в черновики, хотя не уверен, что их не было две :)

            Но там были жуткое фото с ребятами в чёрных куртках, и, если память не изменяет, шапках в жару…
        • +1
          Offtop
          Милое название PHP клиента :)
          • 0
            на благо геометрии ))
            • +3
              видимо не довезли =)
              • –1
                слюнки потекли пока читал, побежал ковырять =)
                • –8
                  страшно становится
                  это кому то надо?
                  не тем ли, кто не знает что такое транзакции?
                  • 0
                    Когда админы спросили надо ли нам обновлять редис до 2.0 я сначала хотел спросить зачем нам релиз кандидат. Но потом все же полез посмотреть. Какая радость все-таки.
                    • 0
                      Я трижды извиняюсь за глупый вопрос, но, ребят, а для тех, кто ну вообще не в теме что это за редиска такая и всё пропустил, есть где почитать по-русски? «чудесная key-value база» как-то вообще не о чем не говорит.
                    • 0
                      а у меня неделю-две назад 2 версия отказывалась нормально ставиться, тесты не все проходила
                      наверное я RC тестил
                      • 0
                        Странно, собирается очень просто и почти на всех системах. Лично пробывал на MacOS, Ubuntu и CentOS.
                        • 0
                          раз уж ответили, спрошу в догонку — а чем ваш класс от predis отличается?
                          насколько я понимаю для php только 2 нормальных api сделано — ваш и вышеуказанный
                          интересно ваше мнение
                          • 0
                            Predis более низкоуровневый клиент, который по сути реализует команды редиса как есть. В силу этого, например, он не занимается сереализацией данных, шардинг ключей по серверам ограничен для комманд, которые работают с несколькими ключами («мультигет» к примеру).

                            Редиска же изначально разрабатывали как более высокоуровней и удобный клиент. Поэтому в Редиски в отличии от Predis есть ООП обертки для ключей, интеграция с фреймворками, сериализация данных и т.д.
                      • 0
                        о, так геометрия на редис(ке)?
                        • 0
                          Да, помимо MongoDb и MySQL.
                        • 0
                          интересная штуковина. Конечно было бы круто иметь русские доки для нее, но и анг тоже норм.
                          попробую использовать в сл проекте
                          • 0
                            > Идиж ты лесом, хабробыдло («о себе» автора)

                            Ну так разбавил бы толпу, хули пиздеть. В следующем проекте он заюзает.
                            • 0
                              в лес, чудовище!
                              • 0
                                Слабо, чувак, слабо.
                                • 0
                                  чуваками своих друзей называй, а ко мне не набивайся.
                                  • 0
                                    как только я вижу ваш ник — я вижу ваш BUTTHURT!
                              • 0
                                Выше ссылка.
                                • 0
                                  да-да, уже увидел и почитал. Когда писал комментарии не были обновлены.
                              • 0
                                Спасибо, Ваня.
                                Пора апдейтить продакшн!
                                • 0
                                  На здоровье.
                                  • 0
                                    Юра, большое спасибо за инициативу и помощь в реализации Pub/Sub!
                                    • 0
                                      На здоровье )

                                      Сами пользуемся — работает, как часы.
                                  • 0
                                    Расскажите, какие задачи в ваших проектах решаются с помощью Redis?
                                    • 0
                                      Редис участвует почти во всем функционале сайте в большей или меньшей степени. Его основная роль: счетчики, лимиты, рейтинги, очереди, логирование, хранение сессий, статистика, кеширование и прочее. Есть функционал который использует только Редис: друзья, топы, геном (рейтинг пользователя), голоса за контент, важные обновления…
                                      • 0
                                        Забыл упомянуть, что Редис удобен для хранения настроек и состояний.
                                      • 0
                                        Вопрос — как правильно обновится до новой версии — сохранением данных?
                                        Просто прицепить слейвом новую версию?
                                        Будет ли работать новая версия редиса (2) со старой версии редиски (для 1)?
                                        • 0
                                          Мы обновляли по такому сценарию:
                                          1. Опустили слейв
                                          2. Обновили на нем редис
                                          3. Поменяли роли
                                          4. Опустили бывший мастер
                                          5. Обновили на нем редис
                                          6. Вернули роли как было


                                          Кончено будет работать.
                                        • 0
                                          я правильно понимаю, что в примере чата с Publish/Subscribe происходит приостанавка выполнения скрипта до появления сообщения?
                                          • 0
                                            В примере я разрывом php тэга постарался показать что это два разных скрипта/потока.
                                            • 0
                                              Тфу, не правильно понял вопрос.

                                              Да, конечно, мы ждем сообщение, как только получаем — делаем итерацию и так далее. Можно установить таймаут если вам не требуется вечный цикл.
                                            • 0
                                              А как быть с тем, что настоящих транзакция в редисе нет?
                                              Ну т.е. в мускуле, емнип, при старте транзакции генерится что-то типа снапшота бд и дальше до коммита я работаю с этим снапшотом, могу читать\писать сколько угодно, при этом мои изменения будут изолированными. В редисе же внутри транзакции читать нельзя.

                                              Плюс то, что ошибки во время транзакции игнорируются, а не приводят к откату — это баг или фича? Не мешает?
                                              • 0
                                                Вы можете читать во время транзакции, но данные вы получите после выполнения транзакции.
                                                Ошибки во время транзакции не игнорируются. Ошибка приводит к откату всей транзакции.

                                                «Either all of the commands or none are processed.»
                                              • 0
                                                интересно, когда редис(ка) будет доступна также как и мускул на обычных хостингах, где нету доступа к кносоли…
                                                • 0
                                                  redis 2.1 вообще крут в том плане, что он разрешает менять ключ с EXPIRE.
                                                  • 0
                                                    Без сомнения, только идет речь о версии 2.2.
                                                  • 0
                                                    В документации написано, что если установлен параметр maxmemory, то при достижении этого лимита redis не сможет больше ничего писать в память и выдаст ошибку, а что если при этом включена опция Virtual Memory — будет ли расширен лимит maxmemory до лимита VM или все равно выдаст ошибку?
                                                  • 0
                                                    поставил я редиску и как-то знакомство не пошло, может кто объяснит?
                                                    1. benchmark показывает 30 операций записи и 50 операций чтения в сек. Redis вроде как должен быть чуть лучше, не?
                                                    2. В режиме Socket'ов Rediska вообще не коннектится: «error 10035 Операция на незаблокированном сокете не может быть завершена немедленно»

                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.