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

Redis

file

задний план

Чтобы уменьшить занимаемый объем памяти, для ключей, размещенных в Redis, обычно устанавливается срок действия через expire.Как Redis реализует удаление ключей с истекшим сроком действия?

Установить срок действия

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

# 将 key 的过期时间设置为 ttl 秒
expire <key> <ttl> 
# 将 key 的过期时间设置为 ttl 毫秒
pexpire <key> <ttl>
# 将 key 的过期时间设置为 timestamp 指定的秒数时间戳
expire <key> <timestamp>
# 将 key 的过期时间设置为 timestamp 指定的毫秒数时间戳
pexpire <key> <timestamp>

Первые три из которых будут преобразованы в способ достижения окончательного срока годности

file

file

сохранить время истечения срока действия

Давайте посмотрим на структуру redisDb

typedef struct redisDb {
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    ...
}

Видно, что словарь expire (словарь срока действия) структуры redisDb сохраняет время истечения срока действия всех ключей

Ключ словаря с истекшим сроком действия — это указатель на ключевой объект в пространстве ключей.

Значение словаря срока действия содержит время истечения срока действия ключа базы данных, на который указывает ключ.

file

Уведомление

На рисунке поле с истекшим сроком действия и объект ключа в пространстве ключей дублируются.На практике объекта-дубликата нет.Ключ пространства ключей и ключ словаря с истекшим сроком действия указывают на один и тот же объект ключа.

Решение о просроченных ключах

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

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

Политика удаления просроченных ключей

ленивое удаление

Когда ключ удаляется, обнаружена ключ, то есть только кнопка удаляется, а ЦП потрачен на другие клавиши истечения срока действия.

недостаток:Он не дружит с памятью, если срок действия первого ключа истечет, он будет храниться в памяти, если к этому ключу не будет доступа, это приведет к трате памяти и даже утечке памяти в течение длительного времени.

Как добиться?

То есть перед выполнением команд чтения и записи Redis будет вызываться метод expireIfNeeded для проверки истечения срока действия ключа.

Если срок действия ключа истек, метод expireIfNeeded удаляет его.

Если срок действия ключа не истек, метод expireIfNeeded ничего не делает.

file

Соответствующий исходный код DB.c / Expiriyifneeded метод

int expireIfNeeded(redisDb *db, robj *key) {
    // 键未过期返回0
    if (!keyIsExpired(db,key)) return 0;

    // 如果运行在从节点上,直接返回1,因为从节点不执行删除操作,可以看下面的复制部分
    if (server.masterhost != NULL) return 1;

    // 运行到这里,表示键带有过期时间且运行在主节点上
    // 删除过期键个数
    server.stat_expiredkeys++;
    // 向从节点和AOF文件传播过期信息
    propagateExpire(db,key,server.lazyfree_lazy_expire);
    // 发送事件通知
    notifyKeyspaceEvent(NOTIFY_EXPIRED,
        "expired",key,db->id);
    // 根据配置(默认是同步删除)判断是否采用惰性删除(这里的惰性删除是指采用后台线程处理删除操做,这样会减少卡顿)
    return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :
                                         dbSyncDelete(db,key);
}

Пополнить

Обычно мы говорим, что Redis является однопоточным.На самом деле, Redis помещает операции обработки сетевой отправки и получения и выполнения команд в основной поток, но в Redis также работают другие фоновые потоки.Эти фоновые потоки обычно заняты интенсивным вводом-выводом. работы, такие как чистка дисков и т.д.

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

регулярно удалять

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

По умолчанию Redis будет выполнять сканирование срока действия 10 раз в секунду (настраивается через hz в redis.conf).Сканирование не проходит по всем ключам в словаре срока действия, а использует следующий метод.

  1. Случайным образом возьмите 20 ключей из просроченного словаря.
  2. Удалить ключи с истекшим сроком действия из этих 20 ключей
  3. Если процент просроченных ключей превышает 25%, повторите шаги 1 и 2.

Чтобы гарантировать, что сканирование не будет зациклено и не приведет к зависанию потока, верхний предел времени сканирования также увеличен, по умолчанию он составляет 25 миллисекунд (то есть по умолчанию используется медленный режим, если он быстрый режим, верхний предел сканирования 1 миллисекунда)

Соответствующий исходный код метода expire.c/activeExpireCycle

void activeExpireCycle(int type) {
        ...
        do {
           ...
            if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)
                // 选过期键的数量,为 20
                num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;

            while (num--) {
                dictEntry *de;
                long long ttl;
                // 随机选 20 个过期键
                if ((de = dictGetRandomKey(db->expires)) == NULL) break;
                ...
                // 尝试删除过期键    
                if (activeExpireCycleTryExpire(db,de,now)) expired++;
                ...
            }
            ...
           // 只有过期键比例 < 25% 才跳出循环
        } while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);
    }
    ...
}

Пополнить

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

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

Стратегия удаления просроченного ключа Redis

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

Обработка просроченных ключей функциями AOF, RDB и репликации

RDB

Создать RDB-файл

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

Загрузить RDB-файл

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

подчиненный сервер: При загрузке файла RDB загружаются все ключи. Однако база данных подчиненного сервера будет очищена во время синхронизации ведущий-подчиненный, поэтому загрузка просроченного ключа не окажет никакого влияния.

AOF

Запись файла AOF

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

AOF переписать

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

копировать

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

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

Когда подчиненный сервер получает команду чтения, отправленную клиентом, он не удалит ее, даже если обнаружит ключ с истекшим сроком действия.Он будет удален только после получения команды del от главного сервера, так что данные главного и подчиненного серверы могут быть гарантированы.

Вопросы?

  1. Если первичный линк отключен от сервера, что делать?
  2. Что делать, если происходит нестабильность сети, а команда del, отправленная ведущим устройством, не доставляется подчиненному устройству?

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

Сначала посмотрите на пункт 1 вопроса - что, если связь между ведущим и подчиненным сервером отключена?

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

Затем давайте посмотрим на вопрос 2 - что, если произойдет переключение сети, а команда del, отправленная главным сервером, не будет доставлена ​​подчиненному серверу?

На самом деле между главным и подчиненным серверами существует механизм обнаружения сердцебиения.Главный и подчиненный серверы проверяют, нормально ли сетевое соединение между ними, отправляя и получая команды REPLCONF ACK. Когда подчиненный сервер отправляет команду REPLCONF ACK на главный сервер, главный сервер сравнивает свое собственное смещение со смещением, отправленным с подчиненного сервера.Если смещение подчиненного сервера меньше его собственного смещения, главный сервер будет реплицировать из Find недостающие данные с сервера в буфер невыполненной работы и отправить данные на подчиненный сервер, таким образом достигнув согласованности данных

резюме

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

использованная литература

«Проектирование и реализация Redis», второе издание. Хуан Цзяньхун

«Redis Deep Adventure: основные принципы и глубокая практика», Лао Цянь.

Добро пожаловать в официальный аккаунт [Белые зубы каждый день], получайте свежие статьи, давайте общаться и добиваться успехов вместе!