- PVSM.RU - https://www.pvsm.ru -
Хотелось бы рассказать о некоторых особенностях Redis [1] при использовании на боевом сервере. Будут рассмотрены альтернативы при сохранении данных на диск, позволяющие достичь различной степени надёжности при сбоях. Так же будут приведены примеры конфигурации для резервного копирования и мониторинга. Используется Redis 2.2.11 на Amazon EC2 с установленной Ubuntu 10.10.
Мы используем Redis для построения пользовательских фидов. Восстановление всех фидов с нуля в случае потери данных занимает достаточно большое количество времени, поэтому мы делаем бекапы. Даже если вы используете Redis в качестве кэширующего сервера, в некоторых случаях прогрев кэша может быть долгим. Поэтому всегда рекомендуется делать резервные копии.
Redis делает RDB-снапшоты на основе следующих параметров в redis.conf:
save 900 100
save 300 1000
save 60 100000
dir /var/redis/
dbfilename dump.rdb
rdbcompression yes
Существует два persistence-режима: RDB и AOF. Стоит отметить, что в обоих режимах используется весьма надёжный способ записи информации на диск, который практически исключает ситуации потери данных при аппаратном сбое. Как много данных вы потеряете зависит лишь от выбора persistence-режима. RDB позволяет регулировать этот параметр гибко, но в среднем, при сбое, может быть потеряно около часа. В этом режиме Redis сначала пишет полный снапшот базы во временный файл и только после окончания записи на диск переименовывает его в рабочий. Это исключает потерю данных благодаря атомарности системного вызова rename().
В случае с AOF, Redis ведёт лог операций, которые выполняют клиенты и записывает их в файл (по умолчанию каждую секунду). AOF это аббревиатура от Append Only File, а это означает то, что Redis не изменяет уже записанные данные, а лишь добавляет новые в конец. Благодаря тому, что при использовании AOF, Redis по умолчанию пишет данные на диск каждую секунду, максимум, что вы теряете в случае сбоя при использовании этого режима — это 1 секунда.
В проекте у нас используется RDB потому что час данных для нас потерять некритично. Кроме того, в худшем случае, данные могут быть восстановлены из основной СУБД.
Подробнее про persistence в Redis:
http://redis.io/topics/persistence [2]
http://antirez.com/post/redis-persistence-demystified.html [3]
Для бэкапов мы используем замечательный backup gem [4], в котором есть поддержка Redis.
# encoding: utf-8
Backup::Model.new(:my_backup, 'My Backup') do
split_into_chunks_of 500
database Redis do |db|
db.name = "dump"
db.path = "/var/redis"
db.host = "localhost"
db.additional_options = []
db.invoke_save = false
end
compress_with Gzip do |compression|
compression.best = true
compression.fast = false
end
notify_by Mail do |mail|
# ...
end
store_with S3 do |s3|
# ...
end
end
Мы специально отключаем invoke_save в конфиге потому что не хотим, чтобы основной поток Redis заблокировался записью на диск при каждом бэкапе.
Для мониторинга используется monit [5], который настроен уведомлять о всех происходящих событиях. Настройки для него достаточно просты:
set mailserver localhost
set mail-format { from: monit-app1@example.com }
set alert support@example.ru but not on { action pid ppid }
check process redis with pidfile /var/run/redis.pid
start program = "/usr/bin/redis-server /etc/redis/redis.conf"
stop program = "/usr/bin/redis-cli -p 6379 shutdown"
group redis
При больших объёмах хранимых данных возможны проблемы в случае использования RDB-снапшотов. Для записи используется команда BGSAVE [6], которая делает форк текущего процесса и в этом форке данные записываются на диск. Таким образом, основной поток не блокируется и запись происходит асинхронно. Проблема в том, что в UNIX-системах при вызове fork(), в дочерний процесс так же копируется содержимое памяти, которую использует родительский процесс. Допустим, если Redis в текущий момент времени занимает 2Gb памяти, а в системе остался только 1Gb свободной памяти, то при выполнении команды BGSAVE возможна следующая ошибка:
[18696] 28 Mar 12:26:54 # Can't save in background: fork: Cannot allocate memory
В современных системах при копировании памяти для форков используется метод Copy on Write [7]. Память копируется только тогда, когда происходит запись в соответствующий участок. Redis делает форк процесса лишь для того, чтобы сохранить данные асинхронно, этот форк их никак не изменяет, а значит мы можем спокойно установить системный параметр vm.overcommit_memory в значение 1. Этот параметр отвечает за возможность выделения большего объёма памяти, чем доступно. Добавляем в /etc/sysctl.conf строчку:
vm.overcommit_memory = 1
И перечитывам конфиг:
# sysctl -p
Подробнее про эту проблему:
http://groups.google.com/group/redis-db/browse_thread/thread/dc4876861b174358 [8]
Автор: akhkharu
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/4397
Ссылки в тексте:
[1] Redis: http://redis.io/
[2] http://redis.io/topics/persistence: http://redis.io/topics/persistence
[3] http://antirez.com/post/redis-persistence-demystified.html: http://antirez.com/post/redis-persistence-demystified.html
[4] backup gem: https://github.com/meskyanichi/backup
[5] monit: http://mmonit.com/monit/
[6] BGSAVE: http://redis.io/commands/bgsave
[7] Copy on Write: http://en.wikipedia.org/wiki/Copy-on-write
[8] http://groups.google.com/group/redis-db/browse_thread/thread/dc4876861b174358: http://groups.google.com/group/redis-db/browse_thread/thread/dc4876861b174358
Нажмите здесь для печати.