Истории успеха наших клиентов — лучшие проекты
Вход/ Регистрация

Как кэшировать приложения Node.JS с помощью Redis

4123
12 минут чтения
Средний рейтинг статьи: 4

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

При разработке Node.js-приложений это актуально — запросы к базе данных могут занимать гораздо больше времени, чем извлечение информации из временного хранилища.

Например, нет никакого смысла загружать HTML-разметку веб-страницы при каждом запросе пользователя к серверу — это добавит несколько (иногда десятков) миллисекунд к времени ответа. Гораздо правильнее разместить страницу (или JSON-данные для вывода на странице SPA-приложения) в кэше.

Проще говоря, кэширование — это про оптимизацию.

В этой статье будет рассмотрен способ кеширования данных приложения Node.js с помощью Redis с использованием фреймворка Express.

Что такое Redis?

Redis (remote dictionary server, удаленный сервер словарей) — это резидентная база данных (in-memory database/store) с открытым исходным кодом (open source), которая работает с простыми структурами «ключ — значение».

Это лишь вопрос терминологии — называть Redis базой данных, инструментом кэширования или как-то еще. Главное, что Redis размещает данные не на жестком диске, а в оперативной памяти — отсюда и более высокая производительность. Собственно, именно поэтому база и называется «резидентной».

Несмотря на то, что данные находятся в оперативной памяти, периодически они сохраняются на жесткий диск в виде снимков.

Установка сервера Redis

Установка Redis под разные операционные системы отличается — на официальном сайте можно найти подробную инструкцию под каждую из них.

В этой статье рассматривается вариант с использованием Ubuntu или Debian. Поэтому, последнюю версию Redis мы возьмем из официального APT (Advanced Packaging Tool) репозитория — packages.redis.io:

    

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

Для Windows необходимо загрузить установщик с официального репозитория GitHub. После установки сервер Redis запускается с помощью CLI-команды:

    

Если же вы используете macOS, то установить Redis можно с помощью пакетного менеджера Homebrew:

    

После установки сервер запускается так:

    

VDS и VPS

Гибкие виртуальные серверы с почасовым
биллингом по всему миру: Россия, Азия и Европа.

Конфигурация проекта Node.js

Прежде чем начать разбираться в принципах взаимодействия с Redis через Node-приложение, давайте сперва создадим отдельный рабочий каталог и перейдем в него:

    

Как и всегда, создадим конфигурационный файл package.json с минимальным набором данных:

    

Обратите внимание на указанные зависимости. Для проекта нам потребуются последние версии популярного сетевого фреймворка Express и официального клиента клиент Redis на NPM — это отдельная библиотека Node.js, содержащая высокоуровневое API (классы и функции) для взаимодействия с сервером Redis.

Модуль Axios поможет парсить JSON-данных, которые будет возвращать удаленный сервер в ответ на API-запросы.

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

    

О том, как установить последнюю версию Node.js в операционной системе Ubuntu, вы можете прочитать в отдельной инструкции. Так как в коде нашего приложения будет использоваться async/await-синтаксис, минимальная версия Node.js — 8.

Теперь, когда все зависимости указаны, их можно установить:

    

Приложение на Express без кэширования

В этом примере приложение будет использовать фейковое API сервиса JSONPlaceholder — он был создан как раз для этих целей. Мы будем отправлять запрос по адресу https://jsonplaceholder.typicode.com/posts/1, получая в ответе импровизированные данные в JSON-формате:

    

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

Однако сперва мы реализуем сам процесс обработки пользовательских запросов без использования кэша — его мы добавим позднее.

Давайте сначала создадим наш index.js-файл и отредактируем его. В скрипте по возможности будет использоваться современный синтаксис JS (ES6) с применением операторов async/await:

    

Теперь можно запустить данный скрипт, открыть localhost в браузере и увидеть на веб-странице вывод полученных JSON-данных:

    

Каждый запрос к локальному серверу будет в свою очередь вызывать запрос к удаленному серверу. Например, если вы 3 раза обновите страницу в браузере, то в терминале приложения Node.js (запущенный сервер) 3 раза выводится указанное в коде сообщение «There was a request to a remote server».

Однако зачем? С рациональной точки зрения в этом нет необходимости.

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

Приложение на Express с использованием кэша

Давайте модифицируем ранее написанный пример, чтобы наше приложение «научилось» кэшировать данные.

Для этого сначала подключим клиент Redis — добавим новую строку в начало index.js:

    

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

    

Обратите внимание, что подключение к серверу Redis происходит в безымяной самовызывающейся асинхронной функции. Это нужно для последовательного выполнения всех предварительных конфигураций нашего приложения. К тому же, функция connect возвращает обещание (promise), которое обрабатывается либо с помощью операторов then/catch, либо внутри асинхронной функции.

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

Давайте модифицируем функцию (middleware) обработки запросов onRequest:

    

Обратите внимание, что функция get возвращает null в том случае, если по данному ключу в Redis нет никаких сохраненных значений. Соответственно, если это так, то выполняется API-запрос к удаленному серверу. А если нет — пользователю отправляются данные из кеша.

При этом функция set непосредственно отвечает за кэширование — она устанавливает указанное значение по названию ключа таким образом, что впоследствии его можно получить через get.

Полный код приложения на данном этапе выглядит так:

    

Установка срока действия кэша

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

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

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

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

Для этого модифицируем вызов этой функции с помощью дополнительной структуры в качестве третьего аргумента. Таким образом строка кода:

    

преобразуется в следующий вид:

    

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

Теперь значение ключа post будет храниться в базе данных 60 секунд — далее оно стирается. Это значит, что в коде нашего приложения переменная cacheData будет получать значение null каждую минуту — это приведет к API-запросу к удаленному серверу и повторному кэшированию полученного результата.

Разверните Redis на своем VDS-сервере

Cloud MSK 15

477 ₽/мес

Процессор
1 x 3.3 ГГц
Память
1 ГБ
NVMe
15 ГБ
Канал
1 Гбит/с
Публичный IP
Cloud MSK 30

657 ₽/мес

Процессор
1 x 3.3 ГГц
Память
2 ГБ
NVMe
30 ГБ
Канал
1 Гбит/с
Публичный IP

Заключение

Эта статья показала, как временное хранилище, размещенное в оперативной памяти, может служить неким «медиатором» между непосредственно обработкой данных и их хранением на твердотельном накопителе.

Все это является разновидностью кеширования, сокращающего лишние вычислительные (и сетевые) операции, тем самым улучшая производительность приложения и снижая нагрузку на сервер.

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

Продемонстрированные примеры — лишь начальный уровень. Больше информации об использовании Redis, как и всегда, можно получить из официальной документации. Впрочем, то же самое касается документации Express и Axios.

4123
12 минут чтения
Средний рейтинг статьи: 4

Читайте также

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server