Это пятый день моего участия в августовском испытании обновлений, подробности о мероприятии:Испытание августовского обновления
проблема
Большой ключ redis - головная боль. Если в Online Redis есть большой ключ, он не может быть выполнен немедленно.del
, так как удаление больших ключей вызовет блокировку. В течение периода блокировки все запросы могут вызывать тайм-ауты.Когда происходит все больше и больше тайм-аутов, продолжают поступать новые запросы, что приведет к исчерпанию пула соединений Redis и вызовет ненормальную работу различных онлайн-сервисов, которые полагаются на Redis.
сделать простой тест
Сначала запишите большой объем данных в redis через скрипт:
127.0.0.1:6379> hlen hset_test
(integer) 3784945
Здесь мы видим, что данных более 3 миллионов, выполняемdel
Взгляни:
127.0.0.1:6379> del hset_test
(integer) 1
(3.90s)
Можно обнаружить, что затрата времени4s
.
Мы знаем, что ядро Redis работает в одном потоке, поэтому в этот период блокировки Redis не может обрабатывать другие запросы.
Удалить в низкий пиковый период
Самый простой способ — удалить его в низкий пиковый период бизнеса.Например, большинство сценариев относительно низкопиковые около 4:00 утра, и удаление выполняется в это время, и влияние относительно невелико. . Конечно, этот метод не может избежать запросов в период блокировки и, как правило, применим к сервисам с очень маленьким qps во время выполнения.
сканировать в пакетном режиме
Так как большой ключ нельзя удалить сразу, то удаляем его пачками.
hset
Для hset мы можем удалять пакеты.
# 伪代码
HSCAN key 0 COUNT 100
HDEL key fields
Каждый берет 100, затем удаляет
set
Для набора мы можем каждый раз случайным образом брать пакет данных, а затем удалять
# 伪代码
SRANDMEMBER key 10
SREM key fields
zset
Для zset вы можете каждый раз напрямую удалять пакет данных
伪代码
ZREMRANGEBYRANK key 0 10
list
Для списка, поп прямо
伪代码
i:=0
for {
lpop key
i++
if i%100 == 0 {
sleep(1ms)
}
}
Асинхронное удаление
Стратегия удаления просроченного ключа
Некоторые люди говорят, что, поскольку удаление большого ключа онлайн приведет к блокированию, установить TTL для этого ключа и оставить его на Redis, чтобы удалить его. Позвольте мне сначала посмотреть на стратегию удаления ключа истекших ключей Redis:
Периодически удалять:
Мы знаем, что ключи redis делятся на просроченные и постоянные ключи.Для ключей со сроком действия redis будет помещен в отдельную таблицу словарей.Отдельное преимущество заключается в том, что redis знает, что ключи в этом словаре могут истечь в любой момент. , так что я буду регулярно После обработки периодические задачи передаются serveCron, который по умолчанию выполняется каждые 100 мс. При каждом запуске serveCron случайным образом выбирает часть ключей из ключа с ttl для проверки, если срок действия пакета ключей действительно просрочен, то будет выполняться синхронное удаление. Причины выборочных проверок:
- Невозможно все проверить, заблокируйте тему.
- Случайные слова отражают определенную справедливость
ленивое удаление
Путем периодического удаления мы можем каждый раз удалять партию ключей с истекшим сроком действия, но если срок действия ключа истек, а периодическое удаление не было очищено, то если пользователь прочитает ключ, он не должен возвращаться напрямую. Срок действия ключа истек, если он истекает, удалите его напрямую и верните значение null.
стратегия устранения
- NOEVICTION: когда память использует больше, чем конфигурация, она вернет ошибку и не удалит ключ.
- Allkeys-LRU: ключей выселения, которые не использовались в течение более длинного времени через алгоритм LRU
- volatile-lru: удалить самый старый неиспользуемый ключ из набора ключей со сроком действия, установленным алгоритмом LRU.
- allkeys-random: случайным образом удалить все ключи
- volatile-random: случайное исключение из набора просроченных ключей
- volatile-ttl: удалить ключи, срок действия которых истекает, из ключей с настроенным временем истечения срока действия.
- Volatile-LFU: Высените наименее часто используемый ключ от всех ключей, настроенных с временем истечения
- allkeys-lfu: удалить наименее часто используемый ключ из всех ключей
Стратегия ликвидации является гибким вариантом.Как правило, подходящая стратегия ликвидации выбирается в соответствии с бизнесом.Когда запускается индивидуальная стратегия ликвидации? Конечно, когда мы добавляем ключи или обновляем ключ большего размера. Таким образом, его удаление также синхронно.Если большой ключ будет удален, к сожалению, он также будет заблокирован в настоящее время.
Резюме: Независимо от того, какой из трех вышеперечисленных триггеров удаляет, он является синхронным. Таким образом, даже если будет добавлен TTL, Redis удаляется синхронно, а большие ключи все равно будут вызывать блокировку.
Асинхронное удаление
Во времена redis 4.0 автор также рассматривал проблему блокировки, вызванной удалением большого ключа, поэтому появилось асинхронное удаление, причем асинхронное удаление также было разделено на пользовательское активное и программно-пассивное.
Активно удалить
unlink
Для инициативы по удалению предоставляется redisdel
Альтернативаunlink
, когда мы находимся в unlink, redis сначала проверит количество удаляемых элементов (например, коллекций), если элементы коллекции меньше или равны 64, синхронное удаление будет выполнено напрямую, потому что это не большой ключ, Это не будет тратить много накладных расходов, но когда их больше 64, Redis будет думать, что вероятность большого ключа относительно высока. В это время Redis сначала удалит ключ в словаре, а реальное значение будет передано асинхронному потоку для работы, таким образом, оно не окажет никакого влияния на основной поток.
флешолл, флешдб
При выполнении flushhall или flushdb добавляется опция ASYNCFLUSHALL [ASYNC]
, когда пользователь не устанавливает ASYNC, операция сброса в это время блокируется.Когда установлен ASYNC, будет создан новый пустой словарь, а затем указать на него, а старый словарь будет передан асинхронному потоку для удаляйте медленно.
пассивное удаление
стратегия распределения Redis
- lazyfree-lazy-eviction: Когда для redis существует стратегия устранения, чтобы установить память на maxmemory, в это время будет запущено асинхронное удаление.Недостаток асинхронного удаления в этом сценарии заключается в том, что если удаление несвоевременное, память не может быть освобождена вовремя.
- lazyfree-lazy-expire: Для ключей с ttl при их очистке redis синхронное удаление не производится, а для их удаления добавляется асинхронный поток.
- replica-lazy-flush: Когда подключается подчиненный узел, он выполняет сброс для очистки своих данных. Если сброс занимает много времени, тем больше данных будет накапливаться в буфере репликации, и более поздний подчиненный узел будет синхронизировать данные относительно медленно. lazy-flush, сброс слейва можно обрабатывать асинхронным реди-мейдом, тем самым повышая скорость синхронизации.
-
lazyfree-lazy-server-del: этот параметр предназначен для некоторых инструкций, например, при переименовании поля.
RENAME key newkey
, Если новый ключ существует в это время, он удалит значение нового ключа для переименования. Если новый ключ является большим, это вызовет блокировку. Когда этот параметр включен, он также будет передан асинхронному потоку для переименования. операция. , чтобы основной поток не блокировался.
Не по теме: переименовать
Давайте сделаем тест первым:
127.0.0.1:6379> set A 1
OK
127.0.0.1:6379> eval "for i=1,10000000,1 do redis.call('hset','B', i,1) end" 0
(15.89s)
- установить А на 1
- Добавьте данные 1000 Вт в B
B должен быть большим ключом. В настоящее время я хочу переименовать A в B и выполнитьrename A B
127.0.0.1:6379> rename A B
OK
(11.07s)
Обнаружено, что блокировка вызвана повторным удалением B. Если есть сценарий переименования, вы должны обратить внимание на то, существует ли уже новый ключ и является ли новый ключ большим.