Redis (ioredis) для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Redis (ioredis) для JavaScript (Node.js): Полное руководство

Redis (Remote Dictionary Server) — это высокопроизводительное хранилище данных типа «ключ-значение» в оперативной памяти, которое часто используется в качестве базы данных, кэша и брокера сообщений. Для работы с Redis из Node.js существует несколько клиентов, и ioredis является одним из самых мощных, производительных и популярных. Эта библиотека предоставляет полный набор функций для взаимодействия с Redis, включая поддержку кластеров, Pub/Sub, конвейерной обработки (pipelining), транзакций и Lua-скриптов.

Зачем нужна эта библиотека? В современной веб-разработке Node.js часто сталкивается с необходимостью быстрого доступа к данным. Redis, работая в памяти, обеспечивает скорость чтения/записи, недостижимую для традиционных реляционных баз данных. ioredis позволяет разработчикам легко интегрировать эту мощь в свои приложения: кэшировать результаты сложных запросов, управлять сессиями пользователей, реализовывать очереди задач, системы рейтингов и многое другое. Библиотека спроектирована с учетом асинхронной природы Node.js, полностью поддерживая Promises и async/await, что делает код чистым и предсказуемым.

Ключевое преимущество ioredis перед другими клиентами (например, устаревшим node_redis) — это встроенная поддержка кластеров Redis и Sentinel, а также автоматическое восстановление соединения. Библиотека активно поддерживается сообществом, имеет подробную документацию и используется в production тысячами компаний по всему миру. Она подходит как для простых скриптов, так и для высоконагруженных распределенных систем.

Установка

Установка библиотеки ioredis производится через менеджер пакетов npm (Node Package Manager). Убедитесь, что у вас установлен Node.js (версии 12 или выше) и npm.

npm install ioredis

Если вы используете yarn, команда будет следующей:

yarn add ioredis

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

docker run -d --name redis-stack -p 6379:6379 redis/redis-stack-server:latest

Быстрый старт

Создайте файл app.js и напишите следующий минимальный код, который подключается к Redis, сохраняет значение и читает его.

// Подключаем библиотеку ioredis
const Redis = require('ioredis');

// Создаем нового клиента. По умолчанию подключается к localhost:6379
const redis = new Redis();

// Асинхронная функция для демонстрации работы
async function quickStart() {
  try {
    // Устанавливаем ключ 'name' со значением 'PythonLib User'
    await redis.set('name', 'PythonLib User');
    console.log('Ключ "name" установлен.');

    // Получаем значение по ключу 'name'
    const result = await redis.get('name');
    console.log(`Значение ключа "name": ${result}`);

    // Проверяем, существует ли ключ
    const exists = await redis.exists('name');
    console.log(`Ключ "name" существует: ${exists === 1}`);

    // Закрываем соединение
    redis.quit();
  } catch (error) {
    console.error('Ошибка:', error);
    redis.quit();
  }
}

quickStart();

Запустите скрипт: node app.js. Вы должны увидеть в консоли сообщения об успешной установке и чтении ключа. Это базовый пример, который демонстрирует, насколько просто начать работу с ioredis.

Основные методы и классы

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

1. set(key, value, ...args)

Сигнатура: redis.set(key: string, value: string | number | Buffer, ...args: any[]): Promise<'OK'>

Что делает: Устанавливает значение для указанного ключа. Если ключ уже существует, его значение перезаписывается (за исключением случаев использования опций NX или XX). Можно передавать дополнительные аргументы для установки времени жизни (EX, PX) или условий (NX, XX).

const Redis = require('ioredis');
const redis = new Redis();

async function exampleSet() {
  // Простая установка
  await redis.set('user:1:name', 'Alice');
  
  // Установка с временем жизни 10 секунд
  await redis.set('session:token', 'abc123', 'EX', 10);
  
  // Установка только если ключ не существует (NX)
  const result = await redis.set('lock:resource', 'locked', 'NX', 'EX', 5);
  console.log(result); // 'OK' если установлен, null если ключ уже существует
  
  redis.quit();
}
exampleSet();

2. get(key)

Сигнатура: redis.get(key: string): Promise<string | null>

Что делает: Получает значение по ключу. Если ключ не существует, возвращает null. Значение возвращается в виде строки.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleGet() {
  await redis.set('greeting', 'Hello, World!');
  
  const value = await redis.get('greeting');
  console.log(value); // 'Hello, World!'
  
  const missing = await redis.get('nonexistent');
  console.log(missing); // null
  
  redis.quit();
}
exampleGet();

3. del(...keys)

Сигнатура: redis.del(...keys: string[]): Promise<number>

Что делает: Удаляет один или несколько ключей. Возвращает количество удаленных ключей.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleDel() {
  await redis.set('key1', 'value1');
  await redis.set('key2', 'value2');
  await redis.set('key3', 'value3');
  
  // Удаляем один ключ
  const deletedCount = await redis.del('key1');
  console.log(`Удалено ключей: ${deletedCount}`); // 1
  
  // Удаляем несколько ключей
  const deletedMultiple = await redis.del('key2', 'key3');
  console.log(`Удалено ключей: ${deletedMultiple}`); // 2
  
  redis.quit();
}
exampleDel();

4. hset(key, field, value) и hget(key, field)

Сигнатура: redis.hset(key: string, field: string, value: string | number): Promise<number>
Сигнатура: redis.hget(key: string, field: string): Promise<string | null>

Что делает: hset устанавливает значение поля в хеше. hget получает значение поля из хеша. Хеши Redis идеально подходят для хранения объектов.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleHash() {
  // Устанавливаем поля хеша "user:100"
  await redis.hset('user:100', 'name', 'Bob');
  await redis.hset('user:100', 'age', '30');
  await redis.hset('user:100', 'city', 'Moscow');
  
  // Получаем одно поле
  const name = await redis.hget('user:100', 'name');
  console.log(`Имя: ${name}`); // 'Bob'
  
  // Получаем все поля и значения хеша
  const allFields = await redis.hgetall('user:100');
  console.log(allFields); // { name: 'Bob', age: '30', city: 'Moscow' }
  
  redis.quit();
}
exampleHash();

5. lpush(key, ...values) и rpop(key)

Сигнатура: redis.lpush(key: string, ...values: any[]): Promise<number>
Сигнатура: redis.rpop(key: string): Promise<string | null>

Что делает: lpush добавляет один или несколько элементов в начало списка (слева). rpop удаляет и возвращает последний элемент списка (справа). Списки Redis можно использовать как очереди или стеки.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleList() {
  // Создаем очередь задач
  await redis.lpush('task_queue', 'task1', 'task2', 'task3');
  
  // Получаем длину списка
  const length = await redis.llen('task_queue');
  console.log(`Длина очереди: ${length}`); // 3
  
  // Извлекаем задачу (FIFO - первый пришел, первый вышел)
  const task = await redis.rpop('task_queue');
  console.log(`Обработана задача: ${task}`); // 'task1'
  
  redis.quit();
}
exampleList();

6. sadd(key, ...members) и smembers(key)

Сигнатура: redis.sadd(key: string, ...members: any[]): Promise<number>
Сигнатура: redis.smembers(key: string): Promise<string[]>

Что делает: sadd добавляет один или несколько элементов в множество (set). smembers возвращает все элементы множества. Множества хранят только уникальные значения.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleSet() {
  // Добавляем теги для статьи
  await redis.sadd('article:42:tags', 'javascript', 'redis', 'nodejs', 'javascript');
  
  // Получаем все теги (дубликаты автоматически игнорируются)
  const tags = await redis.smembers('article:42:tags');
  console.log(tags); // ['javascript', 'redis', 'nodejs']
  
  // Проверяем, есть ли элемент в множестве
  const isMember = await redis.sismember('article:42:tags', 'redis');
  console.log(`Redis в тегах: ${isMember === 1}`); // true
  
  redis.quit();
}
exampleSet();

7. zadd(key, score, member) и zrangebyscore(key, min, max)

Сигнатура: redis.zadd(key: string, score: number, member: string): Promise<number>
Сигнатура: redis.zrangebyscore(key: string, min: number | string, max: number | string): Promise<string[]>

Что делает: zadd добавляет элемент в сортированное множество с указанным весом (score). zrangebyscore возвращает элементы, вес которых находится в заданном диапазоне. Идеально подходит для рейтингов и лидербордов.

const Redis = require('ioredis');
const redis = new Redis();

async function exampleSortedSet() {
  // Создаем рейтинг игроков
  await redis.zadd('leaderboard', 100, 'Player1');
  await redis.zadd('leaderboard', 200, 'Player2');
  await redis.zadd('leaderboard', 150, 'Player3');
  
  // Получаем топ-2 игроков (с наибольшим весом)
  const topPlayers = await redis.zrevrange('leaderboard', 0, 1, 'WITHSCORES');
  console.log('Топ игроков:', topPlayers); // [ 'Player2', '200', 'Player3', '150' ]
  
  // Получаем игроков с весом от 100 до 160
  const midRange = await redis.zrangebyscore('leaderboard', 100, 160);
  console.log('Игроки в диапазоне:', midRange); // [ 'Player1', 'Player3' ]
  
  redis.quit();
}
exampleSortedSet();

8. pipeline()

Сигнатура: redis.pipeline(): Pipeline

Что делает: Создает конвейер (pipeline), который позволяет отправить несколько команд Redis за один раз, без ожидания ответа на каждую из них. Это значительно повышает производительность при пакетной обработке данных. Конвейер возвращает объект, который можно использовать для добавления команд.

const Redis = require('ioredis');
const redis = new Redis();

async function examplePipeline() {
  const pipeline = redis.pipeline();
  
  // Добавляем команды в конвейер
  pipeline.set('key1', 'value1');
  pipeline.set('key2', 'value2');
  pipeline.get('key1');
  pipeline.get('key2');
  
  // Выполняем все команды и получаем результаты
  const results = await pipeline.exec();
  console.log('Результаты конвейера:', results);
  // Вывод: [ [null, 'OK'], [null, 'OK'], [null, 'value1'], [null, 'value2'] ]
  // Каждый результат - это массив [ошибка, значение]
  
  redis.quit();
}
examplePipeline();

Реальный практический пример: Кэширование API с инвалидацией

Рассмотрим реальный сценарий: у нас есть Node.js сервер на Express, который отдает данные о пользователях из медленной базы данных (например, PostgreSQL). Мы будем кэшировать результаты запросов в Redis, чтобы ускорить ответы. Также реализуем механизм принудительной инвалидации кэша при изменении данных.

const express = require('express');
const Redis = require('ioredis');
const crypto = require('crypto');

const app = express();
const redis = new Redis({
  host: 'localhost',
  port: 6379,
  retryStrategy: (times) => Math.min(times * 50, 2000) // Стратегия повторного подключения
});

// Имитация медленной базы данных
const database = {
  users: {
    1: { id: 1, name: 'Alice', email: 'alice@example.com'                    

Рекомендаций