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

Redis

1 Установите ключ со сроком действия

expire key seconds
时间复杂度:O(1)

настраиватьkeyВремя окончания срока действия. После тайм-аута,key. В терминологии Redis akeyСвязанный тайм-аут является изменчивым.

Только после тайм-аутаkeyОн будет очищен только при выполнении DEL, SET и GETSET. Это означает, что концептуально все измененияkeyВсе операции без замены новым значением сохранят таймаут без изменений. Например, используйтеINCRУвеличить значение ключа, выполнитьLPUSHвставьте новое значение в список или используйтеHSETизменить хэшfieldЭти операции по времени остается без изменений.

  • использоватьPERSISTкоманда может очистить тайм-аут, сделав его постояннымkey
  • подобноkeyодеялоRENAMEЕсли команда изменена, соответствующий тайм-аут будет перенесен на новыйkey
  • подобноkeyодеялоRENAMEМодификация команды, такая как оригинальная существующаяKey_A, а затем позвонитеRENAME Key_B Key_Aкоманда, независимо от исходнойKey_AЯвляется ли он постоянным или настроен на тайм-аут, это будет определятьсяKey_BПереопределение статуса действительности

Обратите внимание, что вызов EXPIRE/PEXPIRE или EXPIREAT/PEXPIREAT с прошедшим временем с неположительным временем ожидания приведет к удалению ключа, а не к истечению срока его действия (поэтому выданное событие ключа будет удалено, а не истекло).

1.1 Срок действия обновления

для просроченныхkeyвоплощать в жизньEXPIREоперация, обновит время ее истечения. Существует множество приложений с такими бизнес-сценариями, например сеансы записи сеансов.

1.2 Отличия от 2.1.3 до Redis

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

EXPIRE вернет 0 и не изменит тайм-аут для ключей с установленным тайм-аутом.

1.3 Возвращаемое значение

  • 1В случае успеха установите время истечения срока действия.
  • 0еслиkeyНе существует или не может установить срок действия.

1.4 Пример

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

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

MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC

Если пользователь бездействует более 60 секунд, ключ будет удален, и будут регистрироваться только последующие просмотры страниц с разницей менее 60 секунд. Этот шаблон можно легко изменить для использования INCR вместо списка с использованием RPUSH.

1.5 ключ со сроком действия

Как правило, ключи Redis создаются без указания срока жизни. Ключ сохраняется до тех пор, пока пользователь не удалит его явным образом (например, с помощью команды DEL). Команды семейства EXPIRE могут связывать элементы с истекшим сроком действия с заданным ключом, но за счет дополнительной памяти, используемой этим ключом. Когда у ключа есть набор с истекшим сроком действия, Redis гарантирует, что ключ будет удален по истечении указанного времени. Критическое время жизни можно обновить или полностью удалить с помощью команд EXPIRE и PERSIST (или других строгих команд).

1.6 Точность истечения срока годности

В Redis 2.4 срок действия может быть неточным и может составлять от 0 до 1 секунды. Начиная с Redis 2.6, ошибка истечения срока действия составляет от 0 до 1 миллисекунды.

1.7 Срок действия и постоянство

Ключи для информации с истекшим сроком хранения хранятся в виде абсолютных временных меток Unix (миллисекунды для Redis версии 2.6 или более поздней версии). Это означает, что время течет, даже когда экземпляр Redis не активен. Чтобы экспирация работала корректно, время компьютера должно быть стабильным. Если вы переместите файл RDB с двух машин с большой рассинхронизацией в их часах, могут произойти интересные вещи (например, загрузка всех устаревших ключей при загрузке). Даже экземпляр среды выполнения всегда проверяет часы компьютера, например, если вы установите ключ на 1000 секунд, а затем установите время компьютера на 2000 секунд в будущем, срок действия ключа истечет немедленно, а не на 1000 секунд.

2 Как у Redis истекает срок действия ключей

Есть два способа истечения срока действия ключей: пассивный - ленивое удаление, активный - периодическое удаление.

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

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

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

2.2 Периодическое удаление

В частности, следующий Redis делает 10 раз в секунду:

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

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

2.3 Как справиться с истечением срока действия в ссылках репликации и файлах AOF

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

Однако хотя ведомые устройства, подключенные к ведущему, не будут самостоятельно истекать ключами (а будут ждать DEL от ведущего), они все равно будут использовать полное состояние существующего срока действия в наборе данных, поэтому, когда ведомое устройство выбрано в качестве ведущего, У него будет возможность истекать сроком действия ключей самостоятельно, полностью выступая в роли мастера.

Однако есть много ключей с истекшим сроком действия, которые вы не проверяете вовремя, и вы пропускаете их, когда регулярно удаляете.Большое количество ключей с истекшим сроком действия накапливает память, а память Redis исчерпывается!

Следовательно, также требуется механизм устранения памяти!

3 устранение памяти

3.1 Стратегия устранения памяти

noeviction (политика Redis по умолчанию)

Запросы на запись больше не будут обслуживаться (запросы DEL могут продолжать обслуживаться), а запросы на чтение могут продолжаться. так Это может гарантировать, что никакие данные не будут потеряны, но это сделает онлайн-бизнес невозможным для продолжения.

  • config.c
createEnumConfig("maxmemory-policy", NULL, 
	MODIFIABLE_CONFIG, maxmemory_policy_enum, 
		server.maxmemory_policy, 
			MAXMEMORY_NO_EVICTION, NULL, NULL),

allkeys-random

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

allkeys-lru(Least Recently Used)

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

allkeys-lfu(Least Frequently Used)

Ключ к LRU - посмотреть на страницуПромежуток времени с момента последнего использования до момента планирования, в то время как ключ LFU должен смотреть наКак часто страница используется в течение определенного периода времени.

volatile-lru

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

volatile-lfu

volatile-random

Устаревший ключ — это случайный ключ в наборе просроченных ключей.

volatile-ttl

Стратегия исключения - не LRU, а значение оставшегося срока жизни ttl ключа, ttl Чем меньше приоритет, который нужно устранить.

Стратегия volatile-xxx удаляет только ключи со сроком действия, а стратегия allkeys-xxx удаляет все ключи.

  • Если вы используете Redis только в качестве кеша, вы должны использовать allkeys-xxx, и клиенту не нужно указывать время истечения срока действия при записи в кеш.
  • Если вы также хотите одновременно использовать функцию сохраняемости Redis, используйте стратегию volatile-xxx, которая может хранить ключи без установленного срока действия, поскольку они являются постоянными ключами и не будут устранены алгоритмом LRU.

3.2 Рукописный LRU

Я иногда об этом спрашиваю, потому что если кто-то из кандидатов действительно преодолел пять барьеров и хорошо ответил на предыдущие вопросы, то на самом деле пусть пишет алгоритм LRU и проверяет навыки кодирования

Самый примитивный LRU-алгоритм можно написать от руки на месте, объем кода слишком велик и нереалистичен

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    
private final int CACHE_SIZE;

    // 这里就是传递进来最多能缓存多少数据
    public LRUCache(int cacheSize) {
    	//  true指linkedhashmap将元素按访问顺序排序
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE_SIZE = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
    	 // 当KV数据量大于指定缓存个数时,就自动删除最老数据
        return size() > CACHE_SIZE;
    }

}

Ссылаться на