Статьи

Ускорение существующих приложений с помощью Redis Cache

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

art6ver1-01

Вы можете легко следовать клонированию версии 0.6 приложения .

Проблема

Прежде чем применять решение, мы должны иметь четкое определение проблемы.

Рассматриваемое приложение при выполнении запроса запускается в API Diffbot и заставляет его запросить набор данных. Подмножество затем возвращается и отображается. Это может занять около 5 секунд, в зависимости от загруженности серверов Diffbot. Хотя ситуация, несомненно, улучшится по мере того, как они расширят свои вычислительные возможности, было бы неплохо, если бы запрос, выполненный один раз, запоминался и использовался повторно в течение 24 часов, поскольку коллекция в любом случае обновляется только так часто.

«Но что хорошего в кешировании одного запроса?» — может возникнуть вопрос. Не то чтобы большинство людей часто искали одно и то же.

Ну … на самом деле, не только исследования показали, что они часто будут искать одну и ту же вещь (React имеет тенденцию? Внезапный поток «реагирующих» запросов), они также будут очень надежно искать плодовитых авторов (или самих себя). ). Учитывая тот факт, что внедрение этого кэша в буквальном смысле ничего не стоит нам (и на самом деле снижает затраты за счет снижения нагрузки на серверы), добавить его легко, даже если бы он использовался не так часто, как хотелось бы. Нет причин не добавлять его — это может только принести пользу нам.

С четко определенной проблемой, давайте справимся с предварительными условиями.

Установка

Перво-наперво, нам нужно установить Redis как в среду разработки, так и в производственную среду (обратите внимание, что если вы используете Homestead для локальной разработки, Redis уже установлен, хотя v 3.0.1 на момент написания статьи).

Мы можем сделать это через менеджер пакетов операционной системы следующим образом:

sudo apt-get install redis-server

Это самый простой и рекомендуемый подход, но мы также можем установить его с нуля и настроить вручную. Согласно инструкциям на их сайте , это делается через:

 sudo apt-get install gcc make build-essential tcl
wget http://download.redis.io/releases/redis-3.0.2.tar.gz
tar xzf redis-3.0.2.tar.gz
cd redis-3.0.2
make
make test
sudo make install

Если вы столкнулись с фатальной ошибкой упоминания jemalloc.hmakemake distcleanmake Команда make test

Примечание. Если вы читаете это и версия 3.0.2 больше не является новейшей, просто адаптируйте команды к новому номеру версии.

Чтобы предотвратить некоторые распространенные предупреждения (по крайней мере, в Ubuntu), мы также предупредительно запускаем следующие команды:

 sudo sh -c 'echo "vm.overcommit_memory=1" >> /etc/sysctl.conf'
sudo sh -c 'echo "net.core.somaxconn=65535" >> /etc/sysctl.conf'
sudo sh -c 'echo "never" > /sys/kernel/mm/transparent_hugepage/enabled'

Мы также следим за тем, чтобы последняя команда добавлялась в /etc/rc.localexit 0 Наконец, мы можем перезагрузить сервер с помощью sudo rebootsudo redis-server

Наконец, нам нужно убедиться, что Redis запускается после перезапуска сервера , поэтому мы следуем их официальным инструкциям, чтобы добиться этого.

Predis

Ранее мы рассмотрели основы Predis , и мы будем использовать его и в этом случае. Давайте установим это с:

 composer require predis/predis

В дальнейшем мы предполагаем, что мы усвоили знания из вышеупомянутого введения в Predis.

С тех пор как этот пост был опубликован, были внесены незначительные различия (например, переход к пространствам имен), но API, который нам нужен, более или менее такой же.

Реализация

Чтобы использовать Redis в нашем приложении, нам нужно выполнить следующую процедуру:

  • посмотреть, есть ли результаты для текущего запроса в кеше
  • если да, возьмите их
  • если нет, извлеките их, сохраните их, перешлите их остальной части приложения

Таким образом, реализация очень проста: под проверкой «форма отправлена» (которая ищет параметр «поиск») мы создаем экземпляр клиента Predis, вычисляем хэш md5 выполненного поискового запроса, а затем проверяем, если результаты ибо это уже кешируется. Если false, предыдущий поток продолжается, только вместо окончания:

 $result = ...
$info = ...

мы сериализуем и сохраняем результаты прямо в кеш. Затем, сразу за пределами блока, мы берем их из кэша, и поток приложения продолжается как обычно. Таким образом, измененная часть файла index.php

 // Check if the search form was submitted
if (isset($queryParams['search'])) {

    $redis = new Client();
    $hash = md5($_SERVER['QUERY_STRING']);
    if (!$redis->get($hash . '-results')) {

        $diffbot = new Diffbot(DIFFBOT_TOKEN);

        // Building the search string
        $searchHelper = new SearchHelper();
        $string = (isset($queryParams['q']) && !empty($queryParams['q']))
            ? $queryParams['q']
            : $searchHelper->stringFromParams($queryParams);

        // Basics
        $search = $diffbot
            ->search($string)
            ->setCol('sp_search')
            ->setStart(($queryParams['page'] - 1) * $resultsPerPage)
            ->setNum($resultsPerPage);

        $redis->set($hash . '-results', serialize($search->call()));
        $redis->expire($hash . '-results', 86400);
        $redis->set($hash . '-info', serialize($search->call(true)));
        $redis->expire($hash . '-info', 86400);
    }

    $results = unserialize($redis->get($hash . '-results'));
    $info = unserialize($redis->get($hash . '-info'));

После тестирования мы видим, что он работает как чудо — запрос, который выполняется один раз, мгновенен, если мы обновим страницу или выполним другой запрос, а затем вернемся к предыдущему. Наконец, мы можем добавить, зафиксировать и нажать для развертывания:

 git add -A
git commit -m "Added Redis cache [deploy:production]"
git push origin master

Это оно! Новая версия нашего приложения уже запущена, и Redis обслуживает кэшированные данные. Проверьте это здесь !

Примечание. Если вам интересно, как мы перешли от режима разработки к производственному развертыванию за один коммит, вам следует прочитать это .

Тонкая настройка

Для дополнительного повышения производительности Predis рекомендует установить phpiredis , расширение PHP, чтобы « снизить накладные расходы на сериализацию и анализ протокола Redis ». Учитывая, что мы полностью контролируем сервер, почему бы и нет?

 cd ~
git clone https://github.com/redis/hiredis
cd hiredis
make
sudo make install
cd ~
git clone https://github.com/nrk/phpiredis
cd phpiredis
phpize && ./configure --enable-phpiredis
make
sudo make install

sudo touch /etc/php5/mods-available/phpiredis.ini
sudo sh -c 'echo "extension=phpiredis.so" > /etc/php5/mods-available/phpiredis.ini'
sudo php5enmod phpiredis
sudo service php5-fpm restart

Это установило предварительные условия и включило расширение. Теперь все, что нам нужно сделать, это настроить клиент Predis для использования соединения phpiredis. Нам нужно заменить:

 $redis = new Client();

с

 $redis = new Client('tcp://127.0.0.1', [
        'connections' => [
            'tcp'  => 'Predis\Connection\PhpiredisStreamConnection',
            'unix' => 'Predis\Connection\PhpiredisSocketConnection',
        ],
    ]);

Это оно! Наша установка Redis теперь еще быстрее!

Вывод

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

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

Любой дополнительный совет? Подсказки? Комментарии? Оставь их ниже!