Как участник веб-разработки, я считаю, что каждый столкнется с этим вопросом в своем опыте собеседования: как Redis обеспечивает постоянство?
Не торопясь давать ответ, остановитесь и подумайте немного, прежде чем читать введение ниже. Надеюсь, что прочитав эту статью, вы сможете ответить на этот вопрос.
Зачем нужна настойчивость?
Так как Redis является in-memory БД, то есть при работе сервера система выделяет часть памяти под него для хранения данных, при зависании сервера или внезапном выходе из строя данные в БД будут потеряны. Чтобы сделать сервер даже внезапным остановом, можно также сохранить данные, и данные должны быть сохранены из памяти на диск в постоянном режиме.
Для персистентной программы процесс записи данных из программы на диск компьютера выглядит следующим образом:
1. Клиент отправляет команду записи в базу данных (данные в это время находятся в памяти клиента)
2. База данных получает инструкцию записи и данные (данные в это время находятся в памяти сервера)
3. База данных инициирует системный вызов для записи данных на диск (данные в это время находятся в памяти ядра)
4. Операционная система передает данные на контроллер диска (данные теперь находятся в кэше диска)
5. Контроллер диска выполняет операцию, которая фактически записывает данные на физический носитель (например, на диск).
Если вы рассматриваете только уровень базы данных, данные в безопасности после третьего этапа.В это время был инициирован системный вызов.Даже если произойдет сбой процесса базы данных, системный вызов продолжится, и данные могут быть записаны на диск плавно. После этого шага, на шаге 4, ядро будет сохранять данные из кеша ядра в кеш диска, но для эффективности системы это действие не будет выполняться слишком часто по умолчанию, примерно раз в 30 с, что является означает, что в случае сбоя этого шага или внезапного отключения сервера во время этого шага может произойти 30-секундная потеря данных, и эту довольно распространенную катастрофическую проблему также необходимо учитывать.
API POSIX также предоставляет системный вызов, чтобы заставить ядро записать кэшированные данные на диск, наиболее распространенным из которых является системный вызов fsync.
int fsync(int fd);
Функция fsync работает только с файлом, указанным файловым дескриптором fd, и ожидает завершения операции записи на диск перед возвратом. При каждом вызове fsync инициируется операция записи, и данные буфера записываются на диск. Функция fsync() блокирует процесс, когда он завершает операцию записи, и, если другие потоки также выполняют запись в тот же файл, она также блокирует другие потоки до завершения операции записи.
Упорство
Постоянство — это механизм преобразования данных программы между постоянным и переходным состояниями. Для программы данные хранятся в памяти во время работы программы.Если данные не будут записаны на диск синхронно вовремя, то данные будут потеряны при отключении питания или внезапном сбое программы.Только путем синхронизации данные на диск во времени могут данные быть постоянными Сохраните действительность данных изображения без простоя. Постоянство — это процесс действия по синхронизации данных из программы на диск.
Постоянство Redis
В Redis есть два метода сохранения: RDB и AOF. RDB — это метод создания моментальных снимков.Redis выполняет резервное копирование данных, выполняя команду SAVE/BGSAVE, и сохраняет текущие данные redis в*.rdb
файл, файл содержит все наборы данных. AOF заключается в том, что сервер считывает конфигурацию и добавляет команду записи redis к указанному времени.*.aof
В файле это метод инкрементного сохранения.
RDB
Файлы RDB реализуются с помощью команд SAVE или BGSAVE. Команда SAVE блокирует серверный процесс Redis до тех пор, пока не будет создан файл RDB. Команда BGSAVE создает файл RDB, разветвляя дочерний процесс.Родительский процесс и дочерний процесс совместно используют сегмент данных.Родительский процесс продолжает предоставлять услуги чтения и записи, а дочерний процесс реализует функцию резервного копирования. Стадия BGSAVE копируется только тогда, когда необходимо изменить общий сегмент данных, то есть COW (копирование при записи). SAVE создает файл RDB, устанавливая несколько условий сохранения.Пока выполняется одно из условий, операция SAVE может выполняться в фоновом режиме.
Код реализации команд SAVE и BGSAVE выглядит следующим образом:
void saveCommand(client *c) {
// BGSAVE执行时不能执行SAVE
if (server.rdb_child_pid != -1) {
addReplyError(c,"Background save already in progress");
return;
}
rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi);
// 调用rdbSave函数执行备份(阻塞当前客户端)
if (rdbSave(server.rdb_filename,rsiptr) == C_OK) {
addReply(c,shared.ok);
} else {
addReply(c,shared.err);
}
}
/*
* BGSAVE 命令实现 [可选参数"schedule"]
*/
void bgsaveCommand(client *c) {
int schedule = 0;
/* 当AOF正在执行时,SCHEDULE参数修改BGSAVE的效果
* BGSAVE会在之后执行,而不是报错
* 可以理解为:BGSAVE被提上日程
*/
if (c->argc > 1) {
// 参数只能是"schedule"
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) {
schedule = 1;
} else {
addReply(c,shared.syntaxerr);
return;
}
}
// BGSAVE正在执行,不操作
if (server.rdb_child_pid != -1) {
addReplyError(c,"Background save already in progress");
} else if (server.aof_child_pid != -1) {
// aof正在执行,如果schedule==1,BGSAVE被提上日程
if (schedule) {
server.rdb_bgsave_scheduled = 1;
addReplyStatus(c,"Background saving scheduled");
} else {
addReplyError(c,
"An AOF log rewriting in progress: can't BGSAVE right now. "
"Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever "
"possible.");
}
} else if (rdbSaveBackground(server.rdb_filename,NULL) == C_OK) {// 否则调用rdbSaveBackground执行备份操作
addReplyStatus(c,"Background saving started");
} else {
addReply(c,shared.err);
}
}
После того, как у вас есть файл RDB, если сервер выключен или вам нужно добавить новый сервер, после перезапуска сервера базы данных вы можете восстановить ранее зарезервированные данные, загрузив файл RDB. Однако bgsave займет много времени и не будет работать в режиме реального времени, что приведет к большим потерям данных во время простоя.
AOF (Добавить только файл)
Файл RDB сохраняет данные пары ключ-значение базы данных, а AOF сохраняет команды записи, выполняемые базой данных.
Процесс внедрения AOF состоит из трех этапов:
append->write->fsync
append добавляет команду в буфер AOF, write записывает содержимое буфера в программный буфер, а fsync записывает содержимое программного буфера в файл. Когда функция постоянства AOF включена, каждый раз, когда сервер выполняет команду, он будет добавлять команду в буфер aof_buf структуры redisServer в формате протокола. Конкретный протокол здесь не будет объясняться.
Существует параметр конфигурации при сохранении AOF: appendfsync. Эта опция имеет три значения: всегда: все записывается и синхронизируется в файл aof каждую секунду: записывать содержимое буфера aof_buf в файл AOF, если это последняя синхронизация файла AOF. no: записать все содержимое буфера aof_buf в файл AOF, но не синхронизировать файл AOF. Операционная система решает, когда синхронизировать, обычно 30 секунд по умолчанию.
В режиме сохранения AOF каждая команда записи будет добавляться к файлу AOF.По мере того, как сервер продолжает работать, файл AOF будет становиться все больше и больше.Чтобы избежать большого файла, созданного AOF, сервер перезапишет файл AOF. и работают с одной и той же клавишей.Одни и те же команды объединены, что уменьшает размер файла.
Например, чтобы сохранить имя сотрудника, пол и т. д.:
> hset employee_12345 name "hoohack"
> hset employee_12345 good_at "php"
> hset employee_12345 gender "male"
Просто введите состояние этого хэш-ключа, файл AOF должен сохранить три команды.Если есть другие операции, такие как удаление или обновление значения, команд будет больше, а файл будет больше.Размер файла может быть соответствующим образом уменьшенный.
Принцип реализации перезаписи AOF заключается в том, чтобы сначала пройтись по базе данных на сервере, затем пройти по базе данных, найти все ключевые объекты в каждой базе данных, получить ключ и значение пары ключ-значение и переписать пару ключ-значение в соответствии с тип ключа. Например, приведенный выше пример можно объединить в следующую команду:
> hset employee_12345 name "hoohack" good_at "php" gender "male"。
Перезапись AOF будет выполнять большое количество операций записи.Redis является однопоточным, поэтому, если сервер напрямую вызывает перезапись, сервер не может обрабатывать другие команды, поэтому сервер Redis создает новый процесс для выполнения перезаписи AOF.
Redis выполняет процесс перезаписи:
Когда дочерний процесс выполняет перезапись AOF, после получения команды от клиента сервер сначала выполняет команду, отправленную клиентом, затем добавляет выполненную команду записи в буфер AOF и добавляет выполненную команду записи в буфер перезаписи AOF. После того, как дочерний процесс завершит работу по перезаписи, он отправит серверу сигнал завершения, и сервер добавит все содержимое буфера перезаписи AOF в файл AOF, а затем атомарно перезапишет существующий файл AOF.
Преимущества и недостатки RDB и AOF
Метод сохраняемости RDB может загружать файлы из резервной копии в программу только путем чтения данных с сервера, в то время как метод AOF должен создавать псевдоклиент для выполнения.
Файлы RDB имеют небольшой размер и сохраняют данные до определенного момента времени, что подходит для аварийного восстановления и синхронизации master-slave.
Резервное копирование RDB занимает много времени. Если объем данных велик, некоторые данные могут быть потеряны в случае простоя. Кроме того, RDB настроен на выполнение при выполнении определенных условий, и если он выйдет из строя в течение этого периода, эта часть данных также будет потеряна.
Метод AOF, в случае того же набора данных, размер файла будет больше, чем метод RDB.
Режим сохраняемости AOF также отличается конфигурацией.Конфигурация по умолчанию — синхронизация каждую секунду.Самый быстрый режим — синхронизация каждой команды.Худший режим — ждать, пока система выполнит fsync для синхронизации буфера с файлом на диске. Большинство операционных систем 30-х годов. Обычно он настроен на синхронизацию один раз в секунду, поэтому потеря данных будет максимум 1 с.
Какой метод синхронизации лучше?
Комбинация RDB и AOF. Запустите отложенную задачу для резервного копирования копии текущего состояния сервера каждый час, названной в честь даты и часа, и запустите другую отсроченную задачу для регулярного удаления недопустимых файлов резервных копий (например, 48 часов назад). AOF настраивается на 1 с один раз. Таким образом будет потеряно максимум 1 с данных, в то же время, если у redis будет лавина, он может быстро восстановиться до состояния предыдущего дня, не останавливая сервис.
Суммировать
Схема персистентности Redis не статична, и теорию на бумаге необходимо сочетать с практическими результатами, чтобы доказать ее осуществимость.
Оригинал статьи, ограниченный стиль написания, недостаток знаний и знаний, если есть неточности в статье, сообщите пожалуйста.
Для более интересного контента, пожалуйста, обратите внимание на личный публичный номер.
Справочная статья:Блог OL.Anti Keen.com/post/Redis-… blog.HT track.com/blog/2013/1…