Анатомия типов данных Redis
1.string
Структура данных sds использует предварительное выделение пространства и отложенное освобождение пространства для повышения эффективности, но недостатком является то, что она потребляет память.
struct sdshdr {
int len; //长度
int free; //剩余空间
char buf[]; //字符串数组
};
предварительное выделение пространства: Когда sds преобразуется в более длинный буфер, в дополнение к памяти, необходимой для него самого, он также будет требовать некоторого дополнительного пространства.
ленивое пространство: При модификации sds в более короткий баф лишняя память не возвращается, а сохраняется.
Суммировать: Основная идея этого дизайна заключается в обмене пространства на время, еслиfree
Когда останется достаточно места, в следующий раз, когда строка станет длиннее, она не будет применяться к памяти, как система.
2.list
Связанные списки широко используются для реализации различных функций Redis, таких как ключи списка, публикация и подписка, медленные запросы, мониторы и т. д.
struct listNode {
struct listNode * prev; //前置节点
struct listNode * next; //后置节点
void * value;//节点的值
};
3.hash
Для типа данных хэша используется не только хеш-структура, но и все k и v самого redis — это большой хэш. Например, мы часто используем set key value,key
это хэш-ключ,value
является значением хеша.
struct dict {
...
dictht ht[2]; //哈希表
rehashidx == -1 //rehash使用,没有rehash的时候为-1
}
rehash: Каждый словарь имеет две хэш-таблицы, одну для обычного использования и одну для перефразирования. Перефразирование является прогрессивным и запускается:
- serveCron регулярно обнаруживает миграции.
- Каждый раз при изменении kv (добавлении, обновлении) кстати будет перефразировать.
хэш-коллизия: используйте односвязный список для разрешения конфликтов хэшей, и новые конфликтующие элементы будут помещены в начало связанного списка.
4.zset
Отсортированные наборы можно использовать в некоторых сценариях сортировки, а нижний слой реализуется с помощью списков пропуска.
struct zskiplistNode {
struct zskiplistLevel {
struct zskiplistNode *forward;//前进指针
unsigned int span;//跨度
} level[];
struct zskiplistNode *backward;//后退指针
double score;//分值
robj *obj; // 成员对象
};
Высота этажа: высота слоя каждого узла таблицы пропуска находится в диапазоне от 1 до 32.
Прыжок: переход через узлы через слои для ускорения доступа.
Например, от o1 до o3 нужно только перепрыгнуть через узлы через диапазон уровня L4, равный 2.
5.set
В целях экономии памяти нижний слой набора будет храниться в разных структурах данных в соответствии с типом и количеством наборов.Когда элементы набора являются целыми числами, а число небольшое, будет использоваться набор целых чисел хранить.
struct intset {
uint32_t encoding;//编码方式
uint32_t length;//集合包含的元素数量
int8_t contents[];//保存元素的数组
};
Нижний слой целочисленной коллекции представляет собой массив, при добавлении элементов тип массива будет изменяться по мере необходимости (например, int16 обновляется до int32).
Почему Redis такой быстрый
В крупномасштабных архитектурах приложений Redis — очень распространенное явление в качестве уровня кэширования, одна из причин в том, что он очень быстрый.
1. База данных в памяти
Redis — это база данных в памяти, и большинство операций выполняются в памяти.
2. Специальные структуры данных
Мы знаем, что структура данных Redis специально разработана. Например, тип строки хранится в структуре данных sds. Каждый раз, когда места для строки не хватает, он всегда пытается применить больше памяти. Вернуть лишнее пространство. к системе и таким образом уменьшить приложение памяти для достижения высокой скорости.Таблица переходов, используемая в упорядоченном наборе, может достичь эффекта ускорения доступа к узлам через разные уровни, что также является быстрым проявлением, и прогрессивным rehash также является эффективной и быстрой реализацией.
3. Одинарная нить
Основной режим Redis по-прежнему однопоточный, за исключением некоторых вилок, связанных с сохранением. Преимущество одного потока по сравнению с многопоточным заключается в проблеме блокировки и переключения контекста. Чиновник также пояснил, что производительность Redis не в процессоре, а в памяти.
4. Мультиплексирование ввода-вывода
Мультиплексирование ввода-вывода — это несколько TCP-соединений, мультиплексирующих один поток. Если для запуска нескольких процессов или нескольких потоков используется несколько запросов, это все еще относительно тяжело. В дополнение к рассмотрению переключения процессов или потоков также необходимо неэффективно проходить пользовательский режим, чтобы проверить, наступило ли событие. поддержка Redisselect,poll,epollМультиплексирование режимов по умолчанию выбирает наилучший режим, поддерживаемый системой. Благодаря технологии мультиплексирования ввода-вывода пользовательскому режиму не нужно проходить через коллекцию fds, и он информирует о поступлении события через уведомление ядра, что более эффективно.
В чем преимущества трубопровода
Процесс выполнения клиентом команды примерно такой:
Запрос команды -> очередь команд -> выполнение команды -> возвращенный результат.Мы называем этот процесс RTT (время прохождения туда и обратно). В реальной работе мы можем столкнуться с таким сценарием: нам нужно сохранить incr ключ, но этот ключ не может существовать постоянно, и нужно добавить срок действия, поэтому наша программа выглядит так:
incr key #一次RTT
expire key time #一次RTT
#总共两次RTT
Таким образом, мы обнаруживаем, что для всего процесса требуется два RTT. Как правило, в нашей производственной среде используются пулы соединений. Когда в пуле соединений достаточно соединений, мне может не понадобиться создавать новое соединение, что экономит накладные расходы на трехстороннее рукопожатие TCP. Когда необходимо создать новое соединение, в на этот раз необходимо установить соединение, и все накладные расходы снова возрастают. Для этой пакетной команды, чтобы уменьшить накладные расходы в оба конца, конвейерpipeline
Борн, через конвейер мы можем объединить две команды для отправки:
# 伪代码
pipeline->send(incr key)
pipeline->send(expire key time)
pipeline->execute() #一次RTT
#总共一次RTT
Это уменьшает 2 RTT до 1 RTT.
экономить ресурсы: Конвейер может объединять несколько запросов в один, уменьшая нагрузку на сеть и экономя время. Однако не должно быть слишком много запросов, объединенных через конвейер.Если их слишком много, это может занять большую полосу пропускания и вызвать перегрузку сети.В то же время слишком много команд заставят клиента долго ждать , Рекомендуется разбивать большие пакеты команд на несколько маленьких Пакетный конвейер.
неатомный:pipeline не является атомарным, если вы отправляете его через конвейерincr key
,expire key
две инструкции. Однако, когда redis выполняет expire, он терпит неудачу, что означает, что у вашего ключа не установлено время истечения срока действия, на что нужно обратить внимание.
Что такое протокол Redis
Redis разработал набор протоколов сериализации RESP, который в основном отличается простотой реализации, быстрым синтаксическим анализом и хорошей читабельностью. Каждая часть соглашения является\r\n
В конце тип данных можно отличить по специальным символам:
- Однострочный ответ: с
+
начинается номер. - Ошибка ответа: с
-
начинается номер. - Целочисленный ответ: с
:
начинается номер. - Массовый ответ: с
$
начинается номер. - Несколько массовых ответов: с
*
начинается номер.
Поскольку эффект не виден через клиент Redis, я использую инструмент nc tcp для его имитации.
nc 127.0.0.1 6379 #连接上redis
#发起ping
ping
+PONG
#发送一个不存在的命令
hi
-ERR unknown command 'hi'
#age+1
incr age
:1
#get
$2
go
#mget
mget name1 name2
*2
$2
go
$4
java
Каждая строка выше заканчивается \r\n.Производительность реализации протокола Redis сравнима с производительностью бинарного протокола, и из-за простоты протокола Redis этот протокол может быть реализован на большинстве языков.
Как Redis гарантирует атомарность
Какая атомарность? При выполнении программы либо все они выполняются, либо все не выполняются, невозможно выполнить половину программы и остаться наполовину. Мы знаем, что Redis — это модель мультиплексирования ввода-вывода, то есть один поток обрабатывает несколько TCP-соединений.Преимущество этого в том, что даже если клиент запрашивает одновременно, он должен быть поставлен в очередь для обработки, что решает проблему параллелизма, вызванную несколькими -поточная модель в определенной степени, но однопоточная модель не решает проблему атомарности.
Или возьмите incr и expire в качестве примера:
命令1:incr key
命令2:expire key time
Независимо от того, являетесь ли вы конвейером или неконвейером, вы не можете поддерживать атомарность этих двух операций.Сбой команды 1 не влияет на выполнение команды 2, а выполнение команды 2 не влияет на результат команды 1.
Команды, поддерживающие атомарные операции
Предположим теперь, что есть два клиента, которые хотят изменить определенное значение, процесс их работы заключается в том, чтобы сначала получить исходное значение, а затем обновить его.новое значение = старое значение + 1Но из-за хронологических проблем, возможно, они выполнены так:
# key的value刚开始是10
客户端1:get key #10
客户端2:get key #10
客户端1:set key 11 #11
客户端2:set key 11 #11
Обнаружится, что утеряно обновленное значение клиента 2. Причина в том, что после того, как клиент 1 получает значение ключа, он не приходит и не обновляет его, в это время приходит гет клиента 2, что вызывает клиент 2, чтобы получить старое значение.
Для этого сценария вы можете использовать RedisincrВместо этого incr является атомарной операцией. Она сочетает в себе get и set, а затем использует однопоточную функцию Redis. Когда приходит первый incr, второй incr должен ждать, чтобы не было обновлений. Пропущенный вопрос. Типы атомарных команд такжеdecr,setnx.
Транзакция + Мониторинг
Также может быть решено сочетание наблюдения за наблюдением и транзакциями.Каждый клиент может использовать наблюдение для отслеживания ключа, который он собирается обновить, так что при обновлении транзакции, если он обнаружит, что ключ, который он отслеживает, был изменен, он откажется выполниться, и транзакция не будет выполнена, таким образом, не будет проблем с покрытием обновлений. Суть вахты по-прежнему заключается в оптимистической блокировке.Когда клиент выполняет вахту, ключ вахты фактически будет поддерживать очередь клиента, чтобы он знал, какие клиенты отслеживают ключ. Когда один из клиентов завершает выполнение, он удаляется из очереди иCLIENT_DIRTY_CAS
Флаг включен, чтобы остальные клиенты сами нашлиCLIENT_DIRTY_CAS
был открыт, то он откажется выполняться.
客户端1 > watch key
OK
客户端1 > MULTI
OK
客户端1 > SET key 100
QUEUED
客户端1 > EXEC
1) OK
客户端1 > GET key
"100"
客户端2 > watch key
OK
客户端2 > MULTI
OK
客户端2 > SET key 101
QUEUED
客户端2 > EXEC
(nil)
客户端2 > GET key
"100"
И клиент 1, и клиент 2 пытаются изменить значение ключа, поскольку клиент 1 обновляется первым. Затем клиент 2 обнаружит, что значение было изменено через часы, когда оно будет обновлено, он откажется от выполнения и вернетnil
луа-скрипт
После версии 2.6 Redis начал поддерживать разработчиков для написания lua-скриптов и переноса их в Redis.Преимущества использования lua-скриптов:
- Чтобы уменьшить нагрузку на сеть, несколько запросов можно одновременно объединить в один запрос с помощью сценариев lua.
- Атомарная операция, redis обрабатывает lua-скрипт как единое целое, в процессе выполнения он не будет прерван другими командами, и не будет условий гонки.
- Мультиплексирование, сценарий lua, отправленный клиентом, всегда будет существовать в службе Redis.
Давайте посмотрим, как lua гарантирует атомарность.Предполагая, что есть логика, мы должны сначала определить, что ключ не существует, а затем установить ключ.Если он существует, он не будет установлен.
без луа:
#伪代码
客户端1:if key not exist
客户端2:if key not exist
客户端1:set key 10086
客户端2:set key 10086 #多余的
Поскольку приведенное выше не является атомарным, клиент 2 выполняется еще раз.
использовать луа:
127.0.0.1:6379> eval "if redis.call('get', KEYS[1]) == false then redis.call('set', KEYS[1], ARGV[1]) return 0 else return 1 end" 1 key "10086"
(integer) 0 #执行成功
127.0.0.1:6379> get key1
"10086"
После использования lua, во-первых, сам redis будет обрабатывать весь lua-скрипт как единое целое, и не будет получать помехи от других команд во время работы. После использования lua-скриптов мы можем написать свой собственный сложный бизнес, чтобы обеспечить атомарность. Когда сценарий lua очень длинный, его не очень элегантно выполнять в командной строке.Redis предоставляет команду для загрузки lua и импорта файла сценария lua.После успешного импорта он вернет идентификатор в кодировке sha1, который может быть выполнен повторно через этот идентификатор позже.
Как удалить большой ключ в рабочей среде
Когда производственная среда удаляет большой ключ, это может привести к онлайн-блокировке.Это очень опасная операция.Вы можете выбрать следующие методы в зависимости от реальной ситуации:
- Судя по бизнес-сценарию, удаление в непиковые периоды может эффективно снизить убытки.
- Для hset его можно получать и удалять пакетами через сканирование, для set и zset можно удалять по одному пакету данных за раз, а для list их можно удалять напрямую с помощью pop.
- Redis4.0 поддерживает отключение асинхронного удаления без блокировки основного потока.
Как решить проблему проникновения, поломки и лавины кеша
В высокопроизводительной архитектуре мы обычно добавляем уровень кэша поверх уровня базы данных, потому что данные кэша находятся в памяти, поэтому при доступе к большому объему данных, если частота попаданий в кэш высока, большое количество запросы могут быть заблокированы. Нажмите нашу базу данных, чтобы защитить базу данных и ускорить доступ. Если кеш промахнется, то при чтении данных в БД мы тоже запишем копию в кеш, чтобы данные тоже были получены из кеша при следующем запросе. Что делать, если кеш все время промахивается, или после промаха кеша вдруг приходит большое количество запросов, и кеш дает сбой в большой области в определенный момент?
1. Проникновение в кэш
Когда мы обращаемся к нелегальным данным (данным, которых нет в кеше и базе данных), мы сначала идем в кеш, чтобы получить их, но мы не можем их получить, а затем мы идем в базу данных, чтобы получить их, но мы все еще не можем его получить, например, user_id=-1 (идентификатор пользователя не может быть отрицательным). Когда это происходит, вы должны каждый раз обращаться к базе данных, чтобы запросить несуществующие данные.В это время, поскольку данных нет, они не будут записаны в кеш, и тот же запрос в следующий раз повторит те же ошибки.
решать:
- Проверка внешнего интерфейса: в некоторых случаях, например, когда пользователи выполняют поиск по идентификатору заказа продукта на своей личной центральной странице, внешний интерфейс может определить, что заказы с недопустимыми идентификаторами (например, отрицательными числами) перехватываются напрямую.
- Внутренняя проверка: в начале интерфейса проверьте некоторые обычные положительные и отрицательные числа, такие как отрицательный user_id, и сразу верните ошибку.
- Кэш с нулевым значением: иногда мы также делаем кеш для данных, которые не могут быть найдены в базе данных, и время кэширования может быть короче.
- Перехват хэша: верификация хэша использует некоторые сценарии с небольшим объемом данных, например информацию о товаре магазина.Когда товар ставится на полку, наш товар помечается хеш-меткой (map["product ID"]= 1), так что если запрошенный продукт id отсутствует в хеш-таблице и возвращается напрямую.
- Bitmap Marker: похож на хэш, но использует биты для маркировки.
- Фильтр Блума: когда объем данных, которые нас интересуют, очень велик, насколько велик хэш и растровое изображение, что нереально. В настоящее время мы можем использовать фильтр Блума. Фильтр Блума не так хорош, как хэш и растровое изображение. 100% перехват, но может выполнять большую часть нелегального перехвата. Идея фильтра Блума состоит в том, чтобы найти фрагмент данных с помощью нескольких хеш-функций в ограниченном пространстве.Когда отсутствует только один хеш, он не должен существовать, но когда есть несколько хэшей, его может и не быть. существует, это нужно отметить.
2. Разбивка кеша
Срок действия кэша горячих данных истекает в определенное время, а потом вдруг к БД отправляется большое количество запросов.В это время, если БД не может его нести, он может зависнуть, вызывая цепную онлайн-реакцию.
решать:
- Распределенные блокировки: В распределенных системах первое, что приходит на ум, когда речь заходит о параллельных запросах, — это распределенные блокировки, причем в них ставится только один запрос (можно использовать redis, setnx, zookeeper и т. д.)
- Автономные блокировки: Распределенные блокировки не обязательно требуются. Автономные блокировки также подходят, когда узлов кластера немного (golang может использовать synx.mutex, java может использовать блокировки JVM), гарантируя, что все запросы на машине можно войти. Предположим, у вас есть 10 машин, тогда максимум 10 будут одновременно обращаться к БД, что мало повлияет на базу данных. По сравнению с распределенными блокировками накладные расходы меньше, но если у вас тысячи машин, подумайте внимательно.
- Кэш второго уровня: когда наш кеш первого уровня выходит из строя, мы также можем настроить кеш второго уровня, и кеш второго уровня также может быть перехвачен.Кэш второго уровня может быть кешем памяти или другими базами данных кеша.
- Срок действия данных точки доступа не истекает: в какой-то момент срок действия данных точки доступа не истекает.
3. Лавина кеша
В какой-то момент вдруг большое количество кешей инвалидируется, и все запросы попадают в бд.В отличии от разбивки кеша лавина это большое количество ключей, а разбивка это ключ.В это время давление на бд самоочевидно .
решать:
- Случайное время кеша: для всех кешей постарайтесь сделать время истечения срока действия каждого ключа случайным, чтобы уменьшить вероятность одновременной недействительности.
- Блокировка: блокировка в соответствии со сценой для защиты БД
- Кэш L2: то же, что и разбивка кеша
- Данные точки доступа не имеют срока действия: то же самое, что и разбивка кеша
Каковы схемы персистентности Redis
1.rdb
save: Сохранение сохраняется вручную, что заблокирует процесс Redis до тех пор, пока не будет создан файл RDB, и все команды во время создания не могут быть обработаны.
127.0.0.1:6379> save
OK
27004:M 31 Jul 15:06:11.761 * DB saved on disk
bgsave: В отличие от команды SAVE, это BGSAVE. BGSAVE не может блокировать процесс redis. Через BGSAVE redis разветвляет дочерний процесс для выполнения работы по сохранению rdb, а основной процесс продолжает выполнять команду.
127.0.0.1:6379> BGSAVE
Background saving started
27004:M 31 Jul 15:07:08.665 * Background saving terminated with success
Во время выполнения BGSAVE будет некоторое взаимное исключение с некоторыми другими командами ввода-вывода:
- В течение периода BGSAVE всем командам SAVE будет отказано в выполнении, что предотвратит одновременное выполнение родительского и дочернего процессов, что вызовет некоторые проблемы с конкуренцией.
- В течение периода BGSAVE, если появится новый BGSAVE, он будет отклонен, что также является проблемой конкуренции.
- Во время BGSAVE, если приходит BGREWRITEAOF, BGREWRITEAOF будет отложен до окончания BGSAVE.
- Если выполняется BGREWRITEAOF, команда BGSAVE будет отклонена.
И BGSAVE, и BGREWRITEAOF обрабатываются двумя подпроцессами, а целями также являются разные файлы. Само по себе конфликта нет. Основная причина в том, что оба могут потребовать много операций ввода-вывода, что не очень удобно для самого сервиса.
Пользователи могут настроить запуск bgsave через равные промежутки времени:
save 900 1 #900s内至少修改了1次
save 300 10 #300s内至少修改了10次
save 60 10000 #60s内至少修改了10000次
Пока выполняется одно из вышеуказанных условий, bgsave может быть выполнен.
Здесь задействованы два параметра для записи количества раз и времени соответственно.dirtyсчетчик иlastsave.
- Счетчик грязных данных записывает, сколько раз сервер изменил состояние базы данных (всех баз данных на сервере) с момента последнего успешного выполнения команды SAVE или BGSAVE (включая записи, удаления, обновления и т. д.).
- Атрибут lastsave — это временная метка UNIX, в которой записывается время последнего успешного выполнения сервером команды SAVE или команды BGSAVE.
Вышеуказанные два индикатора основаны на serverCron redis.ServerCron — это программа, которая выполняется регулярно и по умолчанию выполняется каждые 100 мс. Каждый раз, когда serverCron выполняется, он проходит через все условия, а затем проверяет, в порядке ли счетчик и правильно ли время.Если все в порядке, выполните bgsave, запишите время последнего последнего сохранения и сбросьте dirty на 0.
Импортировать: Redis не имеет специальной команды импорта пользователей, при запуске Redis определяет, есть ли файл RDB, и если есть, то он будет импортирован автоматически.
27004:M 31 Jul 14:46:51.793 # Server started, Redis version 3.2.12
27004:M 31 Jul 14:46:51.793 * DB loaded from disk: 0.000 seconds
27004:M 31 Jul 14:46:51.793 * The server is now ready to accept connections on port 6379
DB loaded from
На диске есть описание загрузки rdb, а сервис заблокирован во время загрузки rdb. Конечно, если AOF также включен, AOF будет использоваться первым для восстановления.Только когда AOF не включен на сервере, для восстановления данных будет выбран RDB, а ключи с истекшим сроком действия будут автоматически фильтроваться во время импорта.
2.aof
AOF — это режим добавления команды, предполагающий выполнение:
RPUSH list 1 2 3 4
RPOP list
LPOP list
LPUSH list 1
Наконец, он хранится в протоколе Redis:
*2$6SELECT$10*6$5RPUSH$4list$11$12$13$14*2$4RPOP$4list*2$4LPOP$4list*3$5LPUSH$4list$11
aof сначала записывается в буфер aof_buf, а redis предоставляет три схемы для сброса данных буфера buf на диск.Конечно, serverCron обрабатывает это в соответствии с политикой.
appendfsync always
appendfsync everysec
appendfsync no
- always: Запись и синхронизация всего содержимого буфера aof_buf с файлом AOF.
- everysec: Записать все содержимое буфера aof_buf в файл AOF.Если время последней синхронизации и это время превышают 1с, то выполнить синхронизацию еще раз, и эта синхронизация завершается потоком.
- no: Записать aof_buf в файл AOF, но не выполнять синхронизацию.Когда синхронизировать, определяет операционная система.
В современных операционных системах для повышения эффективности записи файла, когда мы вызываем write для записи части данных, операционная система не сразу записывает на диск, а помещает его в буфер, когда буфер заполнен или Через определенный промежуток времени он действительно будет сброшен на диск. В этом есть определенный риск, то есть до того, как данные в памяти будут сброшены на диск, машина остановится, а данные будут потеряны, поэтому операционная система также предоставляет функцию синхронизации fsync, чтобы пользователи могли решать, когда синхронизировать.
AOF переписать: Чем больше команд, тем больше будет увеличиваться громкость aof, например:
incr num
incr num
incr num
incr num
Выполните 4 incr num, окончательное значение num равно 4, а затем вы можете напрямую заменить его набором num 4, что сэкономит много памяти. Перезапись заключается не в том, чтобы проанализировать существующий aof, а в том, чтобы прочитать существующий ключ из базы данных, а затем попытаться заменить его командой. Не все можно заменить одной командой.Например, sadd может добавить только до 64 штук за раз.Если штук больше 64, то он будет разбит на партии.
Создайте новый aof -> просмотр базы данных -> просмотр всех ключей -> игнорирование просроченных -> запись aof.
fork: Переписывание aof связано с большим количеством операций ввода-вывода. Это определенно нецелесообразно делать в текущем процессе. Конечно, это также делается путем разветвления дочернего процесса. Причина, по которой не используются дочерние потоки, заключается в том, чтобы избежать некоторых проблем с блокировкой . Проблема, которую необходимо учитывать при использовании подпроцессов, заключается в том, что когда подпроцесс записывает, основной процесс все еще непрерывно получает новые запросы, в этом случае Redis устанавливает буфер перезаписи aof, который создается подпроцессом. использоваться, когда приходит новый запрос, помимо записи в буфер aof, также пишется буфер перезаписи aof, и этот процесс не блокируется. Затем, после того, как подпроцесс будет перезаписан, он отправит сигнал основному процессу.После того, как основной процесс получит сигнал, он повторно синхронизирует данные в перезаписанном буфере с новым файлом aof, затем переименует новый aof и атомарно перезапишите старую aof, завершите перезапись, этот процесс блокируется.
Когда выполнять перезапись:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- 100 означает, что текущий файл AOF перезаписывается, когда он в два раза больше, чем при последней перезаписи.
- Минимальный размер файла для перезаписи по умолчанию 64 МБ.
Импортировать: При запуске redis создается псевдоклиент, а затем выполняются команды в файле aof.
Как удалить ключи с истекшим сроком действия в Redis
- Ленивое удаление: Всякий раз, когда мы получаем ключ, мы сначала проверяем, не истек ли срок его действия, и если он истек, удаляем его.
- Периодическое удаление: Redis делит два словаря на ключи со сроком действия и ключи без срока действия.Каждый раз, когда выполняется serverCron, он случайным образом выбирает часть ключа из словаря со сроком действия для проверки и удаляет его, если он истекает.
Как rdb и aof обрабатывают просроченные ключи
rdb: Для режима master-slave, когда главный сервер загружает файл rdb, он автоматически фильтрует ключи с истекшим сроком действия, а когда подчиненный сервер загружает файл rdb, он не будет фильтровать ключи с истекшим сроком действия, поскольку при синхронизации главного и подчиненного данные, ведомое устройство сотрет ваши собственные данные.
aof: Когда сервер работает в режиме сохранения AOF, если срок действия ключа в базе данных истек, но он не удалялся лениво или периодически, то файл AOF не будет иметь никакого эффекта из-за этого ключа с истекшим сроком действия. Когда ключ с истекшим сроком действия удаляется лениво или периодически, программа добавляет команду DEL к файлу AOF, чтобы явно записать, что ключ был удален. Когда aof перезаписывается, он автоматически отфильтровывает ключи с истекшим сроком действия.
Каков срок действия ключа в режиме master-slave?
В обычном режиме ведущий-ведомый главный отвечает за обеспечение записи, а ведомый отвечает за обеспечение чтения. Когда подчиненный сервер выполняет команду чтения, отправленную клиентом, он не удалит ключ с истекшим сроком действия, даже если он встретит ключ с истекшим сроком действия, а продолжит обрабатывать ключ с истекшим сроком действия, как если бы это был неистекший ключ. После того, как главный сервер удалит ключ с истекшим сроком действия, он явным образом отправит команду DEL всем подчиненным серверам, чтобы указать подчиненным серверам удалить ключ с истекшим сроком действия.
Какова стратегия устранения redis
Стратегия исключения является гибким вариантом конфигурации.Как правило, соответствующая стратегия исключения выбирается в соответствии с бизнесом.Конечно, мы добавляем ключ или обновляем ключ большего размера.В это время, если памяти недостаточно, стратегия исключения, которую мы устанавливаем будет запущен.
- noeviction: возвращает ошибку, когда использование памяти превышает конфигурацию, никакие ключи не будут вытеснены
- allkeys-lru: удалить ключи, которые не использовались в течение длительного времени, с помощью алгоритма LRU.
- volatile-lru: удалить самый старый неиспользуемый ключ из набора ключей со сроком действия, установленным алгоритмом LRU.
- allkeys-random: удалить случайным образом из всех ключей
- volatile-random: случайное исключение из набора просроченных ключей
- volatile-ttl: удалить ключи, срок действия которых истекает, из ключей с настроенным временем истечения срока действия.
- volatile-lfu: исключить наименее часто используемый ключ из всех ключей, настроенных со временем истечения срока действия.
- allkeys-lfu: удалить наименее часто используемый ключ из всех ключей
Что делает serverCron
Есть функции, которые периодически выполняются внутри redis.servercron
, он выполняется каждые 100 мс по умолчанию, и его основные функции следующие:
- Обновить кеш времени сервера: Redis имеет много функций, которым необходимо получить текущее время. Каждый раз, когда время получено, требуется системный вызов. Для некоторых сценариев, которые не требуют очень высоких требований к реальному времени, Redis использует кэширование, чтобы уменьшить количество системных звонки. Основными из них с низкими требованиями к реальному времени являются: печать журналов, обновление часов LRU сервера, принятие решения о выполнении постоянных задач и расчет времени в сети сервера. Для установки времени истечения срока действия и добавления журналов медленных запросов системный вызов по-прежнему будет использоваться для получения времени в реальном времени.
-
Обновление часов LRU: в Redis есть один
lruclock
Атрибут используется для сохранения часов LRU сервера.Каждый объект также имеет часы LRU.LRU объекта вычитается через LRU сервера, и можно получить время простоя объекта.ServerCron обновит LRUCLOCK в один раз каждые 10 с, так что это также нечеткое значение. - Сколько раз обновление выполняется в секунду: Это оценочное значение.Каждый раз, когда он выполняется, он будет вычислять интервал между двумя вызовами на основе времени последней выборки и текущего времени сервера, а также количества выполненных команд в последней выборке и текущей количество выполненных команд на сервере. , сколько запросов команд сервер обрабатывает в среднем за миллисекунду, а затем умножение этого среднего значения на 1000 дает оценку того, сколько запросов команд сервер может обработать за одну секунду.
INFO stats
...
instantaneous_ops_per_sec:1
- Обновить пик памяти: Текущее использование памяти будет проверяться при каждом выполнении, а затем сравниваться с предыдущим пиковым значением, чтобы определить, нужно ли обновлять пиковое значение.
INFO stats
...
used_memory_peak:2026832
used_memory_peak_human:1.93M
- Обработка сигнала SIGTERM: При получении сигнала SIGTERM Redis сделает отметку, а затем дождется прихода serverCron и обработает перед выключением некоторую работу в соответствии со статусом отметки, например постоянство.
- Работа с клиентскими ресурсами: Если долгое время нет связи между клиентом и сервисом, то клиент будет освобожден. Если размер входного буфера превышает определенную длину, входной буфер текущего клиента будет освобожден, а затем будет перестроен входной буфер размера по умолчанию, чтобы входной буфер не занимал большой объем памяти. Он также закрывает клиентов, буферы вывода которых превышают лимит.
-
Задержка выполнения перезаписи aof: Когда сервер выполняет BGSAVE, если также поступает BGREWRITEAOF, то BGREWRITEAOF будет отложен до тех пор, пока не будет выполнено BGSAVE, и в это время будет записана отметка.
aof_rewrite_scheduled
, каждый раз, когда выполняется serverCron, он проверяет, выполняется ли в данный момент BGSAVE или BGREWRITEAOF, если нет и отмечен aof_rewrite_scheduled, то будет выполняться BGREWRITEAOF. - Упорство: каждый раз, когда serverCron выполняется, он определяет, сохраняется ли он в данный момент. Если нет, он определяет, отложена ли перезапись aof. Если она отложена, выполняется перезапись aof. Если нет, он проверяет, выполняется ли условие rdb , и если это так, выполните сохранение rdb, в противном случае оцените, выполнено ли условие перезаписи aof, и выполните переписывание aof, если оно выполнено. Когда aof включен, данные из буфера aof будут записаны в файл aof в соответствии с настройками.
- записывать время выполнения: при каждом запуске serverCron будет записывать количество выполнений.
Что происходит, когда ведомое устройство отключается и снова подключается
Когда ведомое устройство выполняет ведомое устройство, оно отправляет команду синхронизации ведущему устройству.После того, как ведущее устройство получает синхронизацию, оно начинает выполнять bgsave в фоновом режиме.В то же время записи за этот период записываются в буфер.Когда bgsave завершается, мастер отправляет rdb в From, ведомый загружает данные в соответствии с rdb, а мастер также отправляет изменения в буфере ведомому, и последующие записи об изменениях ведущего будут переданы ведомому в виде передачи команды. Однако, если ведомое устройство и ведущее устройство в какой-то момент отключены по сетевым причинам, что произойдет, если ведомое устройство будет подключено в это время? А как насчет изменений при отключении?
- До redis2.8, даже если слейв отключается на 1с, до тех пор, пока синхронизация будет отправляться после подключения, мастер бездумно выполнит bgsave, а потом отправит на слейв, а слейв перезагрузит rdb. что весь процесс по-прежнему очень неэффективен, сам Bgsave потребляет много операций ввода-вывода, а отправка данных также потребляет пропускную способность.
- Начиная с redis2.8 поддерживается инкрементная репликация, при разрыве соединения и последующем повторном подключении в некоторых случаях поддерживается синхронизация утерянных при разрыве изменений по отдельности без синхронизации всего rdb-файла. Ключ к достижению частичной синхронизации в основномсмещение репликации master-slave,Буфер невыполненной репликации мастера,а такжеИдентификатор запуска сервера (run_id)три индикатора. Слейв сохранит run_id мастера после первого слейва мастера. Всякий раз, когда мастер синхронизирует команду с ведомым, он записывает смещение синхронизации.После того, как ведомый получает данные, синхронизированные ведущим, он также записывает свое собственное смещение.В то же время, мастер также помещает команду синхронизации на В буфере невыполненной репликации размер этого буфера по умолчанию равен 1M, что соответствует принципу FIFO. Таким образом, когда ведомое устройство отключается и снова подключается, оно будет выполнять:
- Отправьте run_id мастера, который вы сохранили, текущему мастеру.
- Отправьте собственное смещение текущему мастеру.
Как решить проблему разделения мозга Redis
Что такое расщепленный мозг: В кластере Redis, если есть два мастер-узла, это проблема разделения мозга.В это время, к какому мастеру подключен клиент, он записывает данные на какой мастер, что приводит к несогласованности данных.
Как возникают проблемы с расщепленным мозгом: Как правило, может быть проблема с сетью, в которой находится мастер, поэтому мастер и остальные ведомые не могут нормально общаться, но связь между мастером и клиентом в порядке. выберите ведущего из оставшихся ведомых.После восстановления ведущей сети она будет понижена до ведомой.
Последствия расщепленного мозга: В течение периода, когда исходный мастер отключен, клиент, общающийся с ним, будет записывать изменения в исходном мастере.Когда исходная мастер-сеть восстанавливается и становится ведомым новым мастером, он очищает свои собственные данные и синхронизирует данные нового хозяина. Затем в период отключения сети данные, записанные на исходный мастер, теряются.
Как решить: В основном решается двумя параметрами конфигурации:
min-slaves-to-write 1
min-slaves-max-lag 10
- min-slaves-to-write: Этот элемент конфигурации устанавливает минимальное количество подчиненных библиотек, с которыми главная библиотека может выполнять синхронизацию данных;
- min-slaves-max-lag: Этот элемент конфигурации устанавливает максимальную задержку (в секундах) для подчиненной библиотеки для отправки сообщения ACK в главную библиотеку при репликации данных между главной и подчиненной библиотеками.
Если две конфигурации не удовлетворены, то мастер отклоняет запрос клиента, и потерянные данные можно контролировать в течение 10 секунд с помощью вышеуказанной конфигурации.
Что такое кластер Redis
- Во-первых, кластер состоит из нескольких узлов, и узлы присоединяют другие узлы к своему кластеру путем рукопожатия.
- Всего в кластере 16384 слота.
- Каждый узел записывает слот, за который он отвечает, и какой узел обрабатывает оставшиеся слоты.
- Когда узел получает команду, он сначала проверяет, отвечает ли за него ключ.Если нет, он возвращает ошибку MOVED и указывает клиенту обратиться к узлу, ответственному за этот слот, через информацию, переносимую ошибкой MOVED. .
- Если вы хотите переназначить слоты, вы должны использовать инструмент перераспределения.
- В процессе повторного размещения, если узел A переносит слот i на узел B, при запросе на слот i узел A вернет ошибку ASK и направит клиента перейти к слоту B, чтобы найти ее.
- Каждый узел добавляет подчиненные узлы для достижения высокой доступности.
Обязательно ли распределенная блокировка Redis безопасна?
Мы знаем, что Redis однопоточный, и команды обрабатываются одна за другой, так можно ли использовать Redis для распределенных блокировок? Наиболее часто используются:
set key value PX seconds NX
время блокировки: В общих производственных средах мы добавим автоматическое время истечения срока действия блокировки в целях безопасности, чтобы даже в случае аварии, когда замок не был разблокирован, срок действия блокировки автоматически истекал, снижая риск потери. Однако что, если время блокировки истекло, а наш бизнес еще не обработан? Общее решение выглядит следующим образом:
- Предоставьте достаточно времени заранее и постарайтесь убедиться, что блокировка может завершить работу до того, как срок ее действия автоматически истечет.
- Откройте поток для мониторинга. Например, поток проверяет каждую 1/3 срока действия блокировки. Если бизнес не был обработан, время блокировки продлевается.
- Если мы обнаружим, что блокировка была получена другими пользователями, когда мы разблокируем ее, то в настоящее время она считается небезопасной, и выбор отката является хорошим выбором.
В режиме ведущий-ведомый: В режиме master-slave у мастера есть как минимум один слейв, мастер отвечает за запись, а слейв за чтение.Когда ставим блокировку, пишется на мастер, но есть проблема с мастер перед синхронизацией данных с ведомым, что инициирует выборы. Новый ведомый является ведущим, и в это время информация о блокировке на новом ведущем теряется, что приведет к небезопасному параллелизму.
- Что касается этой проблемы, автор Redis предложил метод под названием RedLock. Прежде всего, если вы используете RedLock, вы должны отказаться от режима master-slave, мастер-узлов всего несколько, а официальная рекомендация — 5. Когда мы хотим получить блокировку, мы сначала записываем текущее время, а затем пытаемся получить блокировку по очереди с 5 узлов.При получении блокировки клиент должен установить время истечения срока действия, которое должно быть меньше времени истечения срока действия блокировка для предотвращения блокировки клиента при обмене данными с неработающей службой. Когда получение не удается, вы должны немедленно перейти к следующему узлу, чтобы получить его. Когда блокировка получена от большинства узлов (3), реальное время действия блокировки фактически равно времени, установленному в начале, минус время, когда блокировка была успешно получена. Если блокировка не может быть получена с большинства узлов по другим причинам, то следует по очереди разблокировать замки узлов, и эта блокировка не сработает. Практического применения этой схемы немного, в основном потому, что:
- Высокая стоимость, несколько мастер-узлов.
- Опираясь на системные часы, если блокировка была получена через 3 узла в это время, но системное время экземпляра работает быстро, то блокировка этого экземпляра будет аннулирована заранее, и придет следующий запрос и найдет что еще 3 узла могут быть успешно приобретены.Тогда возникает проблема.
Суммировать: Распределенная блокировка redis может не подходить, когда требуется строгая согласованность, но она подходит в некоторых сценариях, например: даже если блокировка не работает в определенное время, в зону безопасности поступает несколько запросов, несколько запросов могут будет выполнять еще несколько запросов к БД, что не является большой проблемой для бизнеса в целом.
Как решить проблему с горячей клавишей
что такое горячая клавиша: Клавиша, к которой часто обращаются, является горячей клавишей, такой как информация о продукте Double 11 и информация о продукте seckill. Когда параллелизм горячих клавиш очень велик, так что QPS достигает сотен тысяч уровней, если в это время нет защиты, проблема может быть уровня катастрофы.
Как решить:
- Во-первых, хоткей должен быть кеширован, загружать горячие данные в кеш заранее, а считывать кеш напрямую, как только он выходит в онлайн.
- Кэш, по крайней мере, сгруппирован, чтобы обеспечить несколько ведомых устройств, так что даже в случае отказа одного ведомого устройства все равно будет резервная копия.
- Кэш 2-го уровня, используйте память машины для другого перехвата. Например, базовая информация о товарах, таких как шипы, может напрямую использовать память машины.
- Ограничьте ток, оцените поддерживаемое количество запросов в секунду и перехватите избыточные запросы.