Понимать механизм перезапуска памяти Redis и стратегию истечения срока действия.

Redis

Я уже видел вопрос из интервью: каковы стратегии истечения срока действия Redis? Каковы механизмы устранения памяти? Запишите реализацию кода LRU? Автор объединяет проблемы, возникающие на работе, с изучением и анализом, и надеется, что чтение этой статьи может быть полезно для всех.

От неописуемой неудачи

Описание проблемы: Сгенерированный интерфейсный список данных, который зависит от задачи таймера, иногда есть, иногда нет.

Подозревается, что срок действия политики удаления Redis истек

Процесс устранения неполадок долгий, т. к. таймер выполняется вручную, а установленные данные не сообщают об ошибке, но установленные данные не вступают в силу после установленных данных.

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

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

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

Зачем нужна рекультивация памяти?

  • 1. В Redis инструкция set может указывать время истечения срока действия ключа, когда срок действия наступит, ключ станет недействительным;

  • 2. Redis основан на операциях с памятью.Все данные хранятся в памяти.Память машины ограничена и ценна.

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

Механизм рециркуляции памяти Redis

Утилизация памяти Redis в основном делится на две части: стратегия удаления с истекшим сроком действия и стратегия устранения памяти.

Политика удаления с истекшим сроком действия

Удалить ключи, срок действия которых истек.

1. Удаление по времени

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

2. Ленивое удаление

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

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

3. Периодически удалять

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

В Redis используются как периодическое удаление, так и отложенное удаление.

Принцип просроченной стратегии удаления

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

определение структуры redisDb

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

typedef struct redisDb {
        dict *dict;                 /* 数据库的键空间,保存数据库中的所有键值对 */
        dict *expires;              /* 保存所有过期的键 */
        dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
        dict *ready_keys;           /* Blocked keys that received a PUSH */
        dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
        int id;                     /* 数据库ID字段,代表不同的数据库 */
        long long avg_ttl;          /* Average TTL, just for stats */
} redisDb;

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

dict struct

Выше приведена основная структура данных, используемая при реализации стратегии истечения срока действия. Программа = структура данных + алгоритм, после введения структуры данных давайте продолжим смотреть, как устроен алгоритм обработки.

имущество с истекающим сроком действия

Второй атрибут, определенный redisDb, — expires, и его тип — также словарь, Redis добавит все пары ключ-значение с истекшим сроком действия в expires, а затем периодически удалит значения в expires. Сценарии добавления истечения срока действия:

1. set указывает время истечения срока действия

Если при установке ключа указано время истечения срока действия, Redis напрямую добавит ключ в словарь expires и установит время ожидания для элемента словаря.

2. Вызовите команду expire

Явно указать срок действия ключа

3. Восстановление или изменение данных

Восстановите файл или измените ключ из постоянного файла Redis. Если для ключа в данных установлено время истечения срока действия, добавьте ключ в словарь expires.

Все вышеперечисленные операции сохранят ключ с истекшим сроком действия в expires. Redis периодически очищает просроченные ключи из словаря expires.

Когда Redis очищает ключи с истекшим сроком действия

1. Когда Redis запускается, он регистрирует два типа событий: одно — событие времени, а другое — событие файла. (Ссылаться наЧто делает Redis при запуске Redis) События времени — это в основном тип событий для Redis для обработки фоновых операций, таких как тайм-аут клиента и удаление ключей с истекшим сроком действия; события файлов — это обработка запросов.

В событии времени функция обратного вызова, зарегистрированная Redis, — это serverCron.В функции обратного вызова задачи по времени некоторые ключи с истекшим сроком действия очищаются путем вызова databasesCron. (Это реализация, которая периодически удаляется.)

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData)
{
    …
    /* Handle background operations on Redis databases. */
    databasesCron();
    ...
}

2. При каждом доступе к ключу будет вызываться функция expireIfNeeded, чтобы определить, истек ли срок действия ключа, и если да, то ключ будет очищен. (Это реализация отложенного удаления.)

robj *lookupKeyRead(redisDb *db, robj *key) {
    robj *val;
    expireIfNeeded(db,key);
    val = lookupKey(db,key);
     ...
    return val;
}

3. Активно очищайте некоторые ключи с истекшим сроком действия каждый раз, когда выполняется цикл обработки событий. (Это также реализация отложенного удаления.)

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

void beforeSleep(struct aeEventLoop *eventLoop) {
       ...
       /* Run a fast expire cycle (the called function will return
        - ASAP if a fast cycle is not needed). */
       if (server.active_expire_enabled && server.masterhost == NULL)
           activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
       ...
   }

Реализация политики истечения срока действия

Мы знаем, что Redis работает в одном потоке, и очистка ключей не может занимать слишком много времени и ЦП, необходимо очищать ключи с истекшим сроком действия, максимально не затрагивая нормальные сервисы. Алгоритм очистки просроченных файлов следующий:

1、server.hz配置了serverCron任务的执行周期,默认是10,即CPU空闲时每秒执行十次。
2、每次清理过期key的时间不能超过CPU时间的25%:timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;
    比如,如果hz=1,一次清理的最大时间为250ms,hz=10,一次清理的最大时间为25ms。
3、如果是快速清理模式(在beforeSleep函数调用),则一次清理的最大时间是1ms。
4、依次遍历所有的DB。
5、从db的过期列表中随机取20个key,判断是否过期,如果过期,则清理。
6、如果有5个以上的key过期,则重复步骤5,否则继续处理下一个db
7、在清理过程中,如果达到CPU的25%时间,退出清理过程。

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

удалить ключ

До Redis 4.0 инструкция удаления была del, и del освобождала память объекта напрямую.В большинстве случаев эта инструкция выполняется очень быстро, без ощущения задержки. Однако если удаленный ключ представляет собой очень большой объект, например хэш, содержащий десятки миллионов элементов, операция удаления вызовет однопоточное зависание, а ответ Redis будет медленным. Чтобы решить эту проблему, в версии Redis 4.0 была введена инструкция unlink, которая может «ленить» операцию удаления, передавать операцию удаления фоновому потоку, а фоновый поток асинхронно освобождает память.

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

Если он будет удален немедленно, Redis немедленно освободит пространство памяти, занимаемое ключом и значением, в противном случае Redis освободит пространство, которое необходимо удалить, в другом потоке био.

резюме

В общем, стратегия удаления с истекшим сроком действия Redis заключается в регистрации функции serverCron при запуске, и каждый раз, когда тактовый цикл, некоторые ключи в словаре с истекшим сроком действия будут извлекаться для очистки, чтобы обеспечить регулярное удаление. Кроме того, Redis определит, истек ли срок действия ключа при доступе к ключу. Если срок его действия истек, он будет удален. Каждый раз, когда приходит событие доступа к Redis, beforeSleep будет вызывать функцию activeExpireCycle для активной очистки некоторых ключей в течение 1 мс. реализация ленивого удаления.

Redis сочетает в себе обычное удаление и ленивое удаление, что в принципе неплохо справляется с очисткой просроченных данных, но на самом деле все еще немного проблематично: если просроченных ключей много, то при обычном удалении часть пропускается, и она не проверяется со временем, то есть без ленивого удаления, в памяти будет накапливаться большое количество ключей с истекшим сроком действия, что приведет к исчерпанию памяти redis.Когда память исчерпана, что произойдет, когда прибудет новый ключ? Это полный отказ или другие меры? Есть ли способ принять больше ключей?

Политика изъятия памяти

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

Механизм устранения памяти Redis

  • noeviction: когда памяти недостаточно для размещения вновь записанных данных, новая операция записи сообщит об ошибке.
  • allkeys-lru: Когда памяти недостаточно для размещения вновь записанных данных, в ключевом пространстве (server.db[i].dict), удалите последний использованный ключ (это наиболее часто используемый).
  • allkeys-random: когда памяти недостаточно для размещения вновь записанных данных, в ключевом пространстве (server.db[i].dict), удалить ключ наугад.
  • volatile-lru: Когда памяти недостаточно для размещения вновь записанных данных, в ключевое пространство со сроком действия (server.db[i].expires), удалите последний использованный ключ.
  • volatile-random: когда памяти недостаточно для размещения вновь записанных данных, в ключевом пространстве со временем истечения (server.db[i].expires), удалить ключ наугад.
  • volatile-ttl: Когда памяти недостаточно для размещения вновь записанных данных, в ключевом пространстве со временем истечения (server.db[i].expires), сначала удаляются ключи с более ранним сроком действия.

В конфигурационном файле можно указать, какой механизм вытеснения использовать через maxmemory-policy.

Когда будет ликвидация?

Redis будет оценивать, достиг ли текущий redis максимальный предел памяти каждый раз, когда он обрабатывает команду (функция processCommand вызывает freeMemoryIfNeeded), Если предел достигнут, он будет использовать соответствующий алгоритм для обработки ключа, который необходимо удалить. Псевдокод выглядит следующим образом:

int processCommand(client *c)
{
    ...
    if (server.maxmemory) {
        int retval = freeMemoryIfNeeded();  
    }
    ...
}

Принцип реализации LRU

При удалении ключей Redis по умолчанию использует наиболее часто используемый алгоритм LRU (последние недавно использованные). Redis сохраняет последнее время доступа к ключу, сохраняя атрибут lru в каждом объекте redisObject, и напрямую считывает атрибут lru ключа при реализации алгоритма LRU.

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

keys = getSomeKeys(dict, sample)
key = findSmallestIdle(keys)
remove(key)

3 Это число является полем maxmeory-samples в конфигурационном файле, а так же можно установить размер выборки, если установить 10, то эффект будет лучше, но это также будет потреблять больше ресурсов процессора.

Вышеизложенное является введением в принцип механизма восстановления памяти Redis.После понимания вышеизложенного принципа вернитесь к исходному вопросу.Если вы подозреваете механизм восстановления памяти Redis, можете ли вы определить, вызвана ли ошибка восстановлением памяти Redis механизм?

вернуться к истокам проблемы

Как доказать, что сбой не вызван механизмом восстановления памяти?

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

  • 1. Установлено слишком короткое время истечения, например, 1с?
  • 2. Память превышает максимальный лимит, а параметр noeviction или allkeys-random.

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

Если нет проблем со временем истечения срока действия, вам необходимо проверить использование памяти Redis, проверить файл конфигурации Redis или использовать команду info в Redis, чтобы проверить состояние Redis, и свойство maxmemory, чтобы проверить максимальный объем памяти. ценность. Если он равен 0, ограничения нет.В это время используется ограничение total_system_memory, а used_memory сравнивается с максимальным объемом памяти Redis для проверки использования памяти.

Если текущее использование памяти большое, нужно посмотреть, есть ли в конфигурации максимальная память, если есть, то память супер, то можно изначально определить, вызывает ли механизм рециркуляции памяти настройки ключа, но также необходимо посмотрите, является ли алгоритм поэтапного отказа от памяти NoEviction или AllKeys-random, если да, вы можете подтвердить, что вызван механизм восстановления памяти Redis. Если память не супер, или алгоритм поэтапного отказа памяти не указан выше, нужно смотреть не просрочен ли ключ, смотреть время выживания ключа через TTL. Если программа запущена, набор не сообщает об ошибке, то следует немедленно обновить TTL, в противном случае произошел сбой набора, если произошел сбой набора, то код программы должен быть просмотрен правильно.

trouble_process

Суммировать

У Redis есть два способа перераспределения памяти: один — утилизировать ключи с истекшим сроком действия, а другой — освободить память после превышения максимального объема памяти Redis.

В первом случае Redis будет:

1. Определите, истек ли срок действия ключа при каждом доступе к нему, и если да, удалите ключ.

2. При запуске redis будет создано событие по времени, и некоторые ключи с истекшим сроком действия будут регулярно очищаться.По умолчанию выполняется десять проверок в секунду, а время очистки каждого просроченного ключа не превышает 25% ЦП. время, то есть, если hz=1, то максимальное время очистки за один раз составляет 250 мс, если hz=10, максимальное время очистки за один раз составляет 25 мс.

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

理解Redis内存回收机制

Прочитав эту статью, можете ли вы ответить на вопросы интервью в начале статьи?

считать

Оставляя вопрос о мысли, мы знаем, что Redis - это однопотоковое, а однопоточное redis также включает в себя так много задач. Каждый поток, который обрабатывает команды, включает в себя: команды обработки, очистки срок действия ключей и переработки памяти. Почему? Может быть быстрый? Какие оптимизации сделаны в нем? Мы исследуем эту проблему в будущем, поэтому оставайтесь на сегодня.

Оригинал статьи, ограниченный стиль написания, недостаток знаний и знаний, если есть неточности в статье, сообщите пожалуйста.

Если эта статья была вам полезна, ставьте лайк, спасибо ^_^

Для более интересного контента, пожалуйста, обратите внимание на личный публичный номер.