Калина Алексей блог программиста

Настраиваем Redis кластер

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

Все настройки Redis перечисляются в конфигурационном файле. Дефолтный вариант redis.conf содержит много комментариев, по которым можно понять, для чего нужны различные настройки. Все параметры, которые мы сегодня будем обсуждать, прописываются в этом файле.

Персистентность

Начнем с понятия, которое имеет смысл не только в контексте кластера, но и для единственного экземпляра базы данных. Redis хранит данные в оперативной памяти, но тем не менее может оставаться персистентным. Персистентность означает сохранение состояния после завершения процесса (например, после отключения питания компьютера). В Redis персистентность обеспечивается сохранением данных на диск. Для этого есть две основные стратегии.

Первый способ — использовать RDB-снапшоты. Вы настраиваете периодичность, с которой происходит сохранение данных на диск. Когда такой момент наступает, Redis делает форк, то есть создает дочерний процесс. Этот процесс начинает записывать состояние базы данных во временный файл в формате RDB. Как только запись завершается, временный файл заменяет старую версию снапшота.

Чтобы настроить периодичность сохранения на диск, нужно прописать в конфигурационный файл запись вида save <time> <count>. Это означает, что сохранение RDB-снапшота будет производится каждые time секунд при условии, что count ключей изменились. Можно указать несколько таких настроек для поддержки разных сценариев.

Второй подход — дозапись в конец файла. Redis будет записывать все изменения, происходящие с базой данных в Append Only File. Для включения этой функции необходимо указать в конфиге appendonly yes. Кроме того можно настроить частоту записи: каждую операцию (appendfsync always) или каждую секунду (appendfsync everysec). Первый вариант крайне медленный, но в случая отказа даже самые свежие изменения будут сохранены на диск.

Сравнение этих подходов:

Кроме того, есть еще две стратегии для работы с персистентностью. Во-первых, вы не обязаны выбирать между RDB и AOF. Ни что не мешает использовать эти подходы вместе. Так вы не потеряете даже самые последние данные и получите преимущества быстрого развертывания бэкапа RDB. Также есть сценарии, когда персистентность не нужна вовсе. Например при кэшировании нужна максимальная производительность, а потеря данных ничего не стоит. Для этого нужно убрать из конфига все записи save и установить appendonly no.

Шардирование

Чтобы увеличить размер базы данных нужно распределить данные по нескольким серверам (узлам). Такой принцип хранения называется шардированием. Он позволяет горизонтально масштабировать базу данных, используя память и мощность нескольких физических машин. Стандартный подход для распределения записей между серверам: хэширование. Для каждого ключа вычисляется хэш-функция, полученное значение берется по модулю числа узлов. Результат — номер сервера, на котором будет хранится запись.

Распределение между узлами может осуществляться на разных уровнях программного стэка:

  1. Клиент. Redis клиент сам определяет, на какой узел писать и с какого узла читать данные.
  2. Прокси. Клиенты отправляют запросы к прокси, который определяет необходимый узел и перенаправляет запрос на него. Получив ответ, прокси отправляет его клиенту.
  3. Маршрутизация запроса. Клиент может отправлять запросы на любой узел, а он определит правильный и перенаправит запрос. Redis Cluster — пример такой реализации с тем условием, что сервер не перенаправляет запрос, а возвращает редирект клиенту.

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

Отказоустойчивость

Отказоустойчивость осуществляется в Redis с помощью репликации. Репликацией называется копирование данных с одного сервера на другой. В Redis стандартный вариант для репликации — создание мастер-слейвов. Основные узлы, между которыми распределены все данные и с которыми взаимодействует клиент, называются мастер-узлами. Мастер-слейв — полная копия некоторого мастера. Если основной узел упал, то его слейв становится мастером и начинает принимать запросы.

Мастер-слейв придерживается следующей стратегии:

Благодаря репликации после падения одного из узлов слейв автоматически заменит его и кластер сможет по-прежнему принимать запросы. Однако, в то время пока будет происходить подмена кластер будет лежать. Это может быть существенной проблемой. На этот случай в конфигурационном файле есть настройка cluster-require-full-coverage. Если установить для нее значение no, то кластер будет продолжать обрабатывать запросы, даже если часть данных недоступна. Например, эта настройка будет очень полезна, если вы используете Redis в качестве кэша.

Запуск кластера

Мы запустим кластер локально на разных портах одной машины. Точно так же кластер разворачивается и на нескольких серверах. Прежде всего необходимо установить Ruby и пакет Redis: gem install redis. Управление кластером осуществляется с помощью Ruby-скрипта redis-trib.rb. Скачать его можно с официального репозитория на Github.

Перед запуском кластера необходимо прописать соответствующие настройки в конфигурационные файлы на всех узлах:

После того, как все конфиги сформированы, можно запускать отдельные экземпляры Redis. Для случая одной машины проще всего сделать это на нескольких вкладках терминала. Учтите, что Redis Cluster может запуститься только при наличии как минимум трех мастер-узлов. Чтобы запустить кластер, выполните команду: redis-trib.rb create -replicas N <host1>:<port1> … <hostK>:<portK>

После команды create нужно указать сколько слейвов (N) будет создано для каждого мастер-узла и перечислить все сервера кластера. Скрипт автоматически определит конфигурацию: какие узлы будут использоваться как реплики, а какие как мастера. Каждому мастер-узлу соответствует ровно N реплик. Если число узлов не делится на N + 1, скрипт не позволит собрать кластер. Так выглядит сообщение об успешно развернутом кластере:

OK