предисловие
В последнее время я изучаю знания, связанные с Redis, и я прочитал спецификацию разработки Redis Али и книгу «Разработка, эксплуатация и обслуживание Redis». Он разделен на четыре направления: спецификации использования, командные команды, проект реальных боевых действий и конфигурация эксплуатации и обслуживания. Разобрал 21 пункт внимания по использованию Redis, надеюсь будет всем полезен, давайте учиться вместе
публика:маленький мальчик собирает улиток
1. Спецификация использования Redis
1.1, ключевые моменты спецификации
Когда мы разрабатываем ключ Redis, мы должны обратить внимание на следующие моменты:
- Добавьте префикс ключа с названием компании и разделите его двоеточием, чтобы предотвратить перезапись конфликтов ключей. Например, live:rank:1
- Чтобы семантика ключа была понятной, длина ключа должна быть как можно меньше 30 символов.
- Ключу запрещено содержать специальные символы, такие как пробелы, символы новой строки, одинарные и двойные кавычки и другие escape-символы.
- Максимально устанавливайте ttl для ключей Redis, чтобы неиспользуемые ключи можно было вовремя очистить или удалить.
1.2, спецификация точек стоимости
Значение Redis не может быть установлено произвольно.
Первая точка, если хранится большое количество bigKeys, возникнут проблемы, которые приведут к медленным запросам, чрезмерному росту памяти и так далее.
- Если это тип String, размер одного значения контролируется в пределах 10 КБ.
- Если это тип hash, list, set или zset, количество элементов обычно не превышает 5000.
Второй момент, чтобы выбрать соответствующий тип данных. Многие небольшие партнеры используют только тип Redis типа String, который устанавливается и получает. На самом деле Redis предоставляетБогатые типы структур данных, некоторые бизнес-сценарии больше подходятhash、zset
Дождитесь других результатов данных.
Пример счетчика:
set user:666:name jay
set user:666:age 18
Положительный пример
hmset user:666 name jay age 18
1.3 Установите срок действия ключа, и обратите внимание на ключи разных сервисов, и постарайтесь максимально раздвинуть время истечения
- Поскольку данные Redis хранятся в памяти, а ресурсы памяти очень ценны.
- Обычно мы используем Redis в качестве кеша, ине база данных, поэтому жизненный цикл ключа не должен быть слишком длинным.
- Поэтому ваш ключ, как правило, рекомендуется использоватьexpire устанавливает время истечения срока действия.
Если срок действия большого количества ключей истекает в определенный момент времени, Redis может зависнуть в этот момент времени или даже появитьсяКэш ЛавинаПоэтому время истечения ключей разных сервисов должно быть разбросано. Иногда для одного и того же бизнеса вы также можете добавить случайное значение ко времени, чтобы распределить время истечения срока действия.
1.4. Для повышения эффективности рекомендуется использовать пакетные операции.
Когда мы ежедневно пишем SQL, мы все знаем, что пакетные операции будут более эффективными.Обновление 50 элементов за раз более эффективно, чем цикл 50 раз и обновление одного элемента за раз. На самом деле то же самое верно и для операционных команд Redis.
Выполнение команды клиентом Redis можно разделить на 4 процесса: 1. Отправка команды -> 2. Постановка команды в очередь -> 3. Выполнение команды -> 4. Возврат результата. 1 и 4 называются RRT (время прохождения команды туда и обратно). Redis предоставляетКоманды пакетных операций, такие как mget, msetи т. д., может эффективно сохранить RRT. Однако большинство команд не поддерживают пакетные операции, например hgetall, а mhgetall отсутствует.Pipelineможет решить эту проблему.
Что такое Pipeline?Он может собирать набор команд Redis, передавать их в Redis через RTT, а затем последовательно возвращать результаты выполнения этого набора команд Redis клиенту.
Давайте сначала посмотрим на модель, которая выполняет n команд без использования Pipeline:
Используя Pipeline для выполнения n команд, весь процесс требует 1 RTT Модель выглядит следующим образом:
2. Те команды, которые у Redis есть ямки
2.1. Используйте с осторожностьюO(n)
команды сложности, такие какhgetall
,smember
,lrange
Ждать
Потому что Redis выполняет команды в одном потоке. Временная сложность таких команд, как hgetall и smember, равна O(n).Когда n продолжает увеличиваться, ЦП Redis продолжает увеличиваться и блокировать выполнение других команд.
Такие команды, как hgetall, smember и lrange, не обязательно недоступны, необходимо всесторонне оценить количество данных, уточнить значение n и только потом принимать решение. Например, hgetall, если элементов хэша n много, его можно использовать первымhscan.
2.2 Используйте команду монитора Redis с осторожностью
Команда Redis Monitor используется для распечатки команд, полученных сервером Redis в режиме реального времени.Если мы хотим знать, какие командные операции клиент выполнил на сервере redis, мы можем использовать команду Monitor для ее просмотра, но это в целомотладкаПросто используйте его, постарайтесь не использовать его в продакшене! так какКоманда монитора может привести к тому, что память Redis продолжит расти.
Модель монитора фиолетового цвета, и он выводит все команды, выполненные на сервере Redis.Вообще говоря, QPS сервера Redis очень высок, то есть, если команда монитора выполняется, сервер Redis выводит буфер мониторить клиент, будет много «инвентаря», который займет много памяти Redis.
2.3, производственная среда не может использовать команду ключей
Команда Redis Keys используется для поиска всех ключей, соответствующих заданному шаблону. Если вы хотите проверить количество ключей определенного типа в Redis, многие мелкие партнеры думают об использовании команды keys следующим образом:
keys key前缀*
Тем не менее, редисkeys
является обходным сопоставлением, сложностьO(n)
, чем больше данных в базе, тем медленнее будет. Мы знаем, что Redis является однопоточным. Если данных много, инструкция keys приведет к блокировке потока Redis, а также остановится онлайн-сервис. Сервис не возобновится, пока инструкция не будет выполнена. следовательно,Как правило, в производственной среде не используйте команду ключей.. В официальной документации также говорится:
Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using sets.
На самом деле вы можете использовать команду сканирования, которая обеспечивает ту же функциональность сопоставления с образцом, что и команда ключей. Его сложность также O(n), но он проходит через курсор,Не блокирует поток Redis; но будет определеннаяВероятность повторения, должен быть вКлиент выполняет дедупликацию.
scan поддерживает команды инкрементной итерации, которые также имеют недостатки: например, с помощью команды SMEMBERS можно вернуть все элементы, содержащиеся в данный момент в заданном ключе, но для команд инкрементной итерации, таких как SCAN, поскольку в Keys могут быть изменены во время инкрементной итерации ключи , поэтому команды инкрементной итерации могут предоставлять только ограниченные гарантии в отношении возвращаемых элементов.
2.4 Запретить использование flushhall и flushdb
- Команда Flushall используется для очистки данных всего сервера Redis (удаление всех ключей всех баз данных).
- Команда Flushdb используется для очистки всех ключей в текущей базе данных.
Эти две команды являются атомарными и не прерывают выполнение. После выполнения он не подведет.
2.5 Обратите внимание на использование команды del
Какую команду вы обычно используете для удаления ключа? Это прямой дел? Если вы удалите ключ, вы, конечно, можете использовать команду del напрямую. Однако задумывались ли вы о временной сложности del? Давайте обсудим каждый случай:
- Если вы удалите ключ типа String, временная сложность составит
O(1)
,может быть напрямую удален. - Если вы удалите тип List/Hash/Set/ZSet, его сложность
O(n)
, n представляет количество элементов.
Поэтому если удалить ключ типа List/Hash/Set/ZSet, то чем больше элементов, тем медленнее будет.Когда n очень велико, следует обратить особое внимание на, который заблокирует основной поток. Итак, если мы не используем del, как нам его удалить?
- Если это тип списка, вы можете выполнить
lpop或者rpop
, пока не будут удалены все элементы.- Если это тип Hash/Set/ZSet, вы можете сначала выполнить
hscan/sscan/scan
запросить, выполнитьhdel/srem/zrem
Удаляйте каждый элемент по очереди.
2.6 Избегайте использования SORT, SINTER и других чрезмерно сложных команд.
Выполнение команд с более высокой сложностью потребляет больше ресурсов ЦП и блокирует основной поток. Итак, вы хотите избежать таких вещей, какSORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE
В ожидании команды агрегации обычно рекомендуется поставить ее на клиентскую сторону для выполнения.
3. Спроектировать фактическую операцию по предотвращению боевых ям.
3.1 Замечания по использованию распределенных блокировок
Распределенная блокировка на самом деле является реализацией блокировки, которая контролирует общий доступ различных процессов в распределенной системе к общим ресурсам. Распределенные блокировки необходимы для бизнес-сценариев, таких как размещение заказов за секунды, захват красных конвертов и т. д. Мы часто используем Redis в качестве распределенной блокировки, в основном с учетом следующих моментов:
3.1.1 Две команды SETNX + EXPIRE записываются отдельно (типовой пример реализации ошибки)
if(jedis.setnx(key_resource_id,lock_value) == 1){ //加锁
expire(key_resource_id,100); //设置过期时间
try {
do something //业务请求
}catch(){
}
finally {
jedis.del(key_resource_id); //释放锁
}
}
Если законченоsetnx
Когда блокировка вот-вот истечет, чтобы установить время истечения срока действия, происходит сбой процесса или его необходимо перезапустить для обслуживания, тогда блокировка будет «бессмертной».Никакой другой поток никогда не сможет получить блокировкуИтак, общие распределенные блокировки не могут быть реализованы таким образом.
3.1.2 Значение SETNX + value - это время истечения (некоторые мелкие партнеры реализуют этот способ, есть ямы)
long expires = System.currentTimeMillis() + expireTime; //系统时间+设置的过期时间
String expiresStr = String.valueOf(expires);
// 如果当前锁不存在,返回加锁成功
if (jedis.setnx(key_resource_id, expiresStr) == 1) {
return true;
}
// 如果锁已经存在,获取锁的过期时间
String currentValueStr = jedis.get(key_resource_id);
// 如果获取到的过期时间,小于系统当前时间,表示已经过期
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
// 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间(不了解redis的getSet命令的小伙伴,可以去官网看下哈)
String oldValueStr = jedis.getSet(key_resource_id, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
// 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁
return true;
}
}
//其他情况,均返回加锁失败
return false;
}
этой схемынедостаток:
- Время истечения генерируется самим клиентом, в распределенной среде время каждого клиента должно быть синхронизировано.
- Не сохраняет уникальную личность владельца и может быть разблокирован/разблокирован другими клиентами.
- Когда срок действия блокировки истекает, несколько одновременных клиентов запрашивают одновременно, и все они выполняются.
jedis.getSet()
, в конце концов, только один клиент может успешно заблокироваться, но время истечения срока действия блокировки клиента может быть перезаписано другими клиентами.
3.1.3: Расширенная команда для SET (SET EX PX NX) (обратите внимание на возможные проблемы)
if(jedis.set(key_resource_id, lock_value, "NX", "EX", 100s) == 1){ //加锁
try {
do something //业务处理
}catch(){
}
finally {
jedis.del(key_resource_id); //释放锁
}
}
С этим решением все еще могут быть проблемы:
- Блокировка просрочена и снята, а дело не выполнено.
- Блокировка была случайно удалена другим потоком.
3.1.4 SET EX PX NX + Проверяем уникальное рандомное значение, а затем удаляем его (решили проблему ошибочного удаления, но осталась проблема, что блокировка истекает и дело не завершено)
if(jedis.set(key_resource_id, uni_request_id, "NX", "EX", 100s) == 1){ //加锁
try {
do something //业务处理
}catch(){
}
finally {
//判断是不是当前线程加的锁,是才释放
if (uni_request_id.equals(jedis.get(key_resource_id))) {
jedis.del(lockKey); //释放锁
}
}
}
Здесь оценка того, добавлена ли блокировка текущим потоком, и снятие блокировки не является атомарной операцией. Если вы вызываете jedis.del() для снятия блокировки, блокировка может больше не принадлежать текущему клиенту, и блокировка, добавленная другими, будет снята.
Обычно он заменяется lua-скриптом. Lua-скрипт выглядит следующим образом:
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end;
3.1.5 Redisson Framework + алгоритм Redlock Решение проблемы просроченного выпуска блокировки и незавершенного бизнес-процесса + проблема с одной машиной
Редиссон используетWatch dog
Решите проблему, что срок действия блокировки истекает, а бизнес не завершен.Схема Redisson выглядит следующим образом:
Вышеупомянутые распределенные блокировки по-прежнему имеют проблемы с одной машиной:
Если поток получает блокировку на главном узле Redis, но заблокированный ключ не был синхронизирован с подчиненным узлом. В это время главный узел выходит из строя, и подчиненный узел будет обновлен до главного узла. Второй поток может получить блокировку того же ключа, но первый поток уже получил блокировку, и безопасность блокировки будет потеряна.
Для задач с одной машиной можно использовать алгоритм Redlock. Заинтересованные друзья могут прочитать мою статью,Семь вариантов! Обсудить правильное использование распределенной блокировки Redis.
3.2 Примечания о когерентности кэша
- Если это запрос на чтение, сначала прочитайте кеш, а затем прочитайте базу данных.
- Если сделан запрос на запись, сначала обновите базу данных, а затем запишите кеш
- После каждого обновления данных кэш нужно очищать
- Кэш обычно должен установить определенную дату истечения срока действия
- Если требования к согласованности высоки, вы можете использовать biglog+MQ для обеспечения этого.
Если вам интересно, вы можете прочитать мою статью:В параллельной среде вы должны сначала работать с базой данных или с кешем?
3.3 Разумно оценивать емкость Redis, чтобы избежать аннулирования ранее установленного времени истечения срока действия из-за частого охвата наборов.
Мы знаем, что все типы структур данных Redis могут устанавливать время истечения срока действия. Предположим, что для строки установлено время истечения срока действия, и если вы сбросите его, предыдущее время истечения срока действия будет недействительным.
Redis setKey
Исходный код выглядит следующим образом:
void setKey(redisDb *db,robj *key,robj *val) {
if(lookupKeyWrite(db,key)==NULL) {
dbAdd(db,key,val);
}else{
dbOverwrite(db,key,val);
}
incrRefCount(val);
removeExpire(db,key); //去掉过期时间
signalModifiedKey(db,key);
}
При этом в реальном развитии бизнеса нам необходимо разумно оценивать возможности Redis, чтобы избежать частого охвата наборов, что приведет к аннулированию ключей с просроченным временем. Новички склонны совершать эту ошибку.
3.4 Проблема проникновения в кэш
Давайте сначала рассмотрим распространенный метод использования кеша: когда приходит запрос на чтение, сначала проверяем кеш, если значение кеша попадает, то возвращаемся напрямую, если кеш промахивается, идем в базу данных, затем обновляем значение базы данных до кэш, а затем вернуться.
проникновение в кеш: Относится к запросу определенных данных, которые не существуют. Поскольку кеш не попал, его необходимо запросить из базы данных. Если данные не могут быть найдены, они не будут записаны в кеш. Это приведет к не- существующие данные должны запрашиваться в базе данных каждый раз, когда они запрашиваются, а затем оказывать давление на базу данных.
С точки зрения непрофессионала, при доступе к запросу на чтение ни кеш, ни база данных не имеют определенного значения, что приведет к тому, что каждый запрос на это значение будет проникать в базу данных, что является проникновением в кеш.
Проникновение в кэш обычно вызывается следующими ситуациями:
- бизнес необоснованный дизайн, например, у большинства пользователей нет опекуна, но каждый ваш запрос кэшируется, и для проверки наличия опекуна запрашивается идентификатор пользователя.
- Ошибки ведения бизнеса/эксплуатации и обслуживания/развития, такие как кэш и данные базы данных, были удалены по ошибке.
- Хакерская атака с незаконным запросом, например, хакеры намеренно фабрикуют большое количество незаконных запросов на чтение несуществующих бизнес-данных.
Как избежать проникновения в кеш?Обычно есть три метода.
-
- Если это недопустимый запрос, мы проверяем параметры на входе в API и отфильтровываем недопустимые значения.
-
- Если база данных запросов пуста, мы можем установить пустое значение для кеша или значение по умолчанию. Однако, если приходит запрос на запись, кеш необходимо обновить, чтобы обеспечить согласованность кеша, при этом для кеша в конце устанавливается соответствующий срок действия. (Обычно используется в бизнесе, прост и эффективен)
-
- Используйте фильтр Блума, чтобы быстро определить, существуют ли данные. То есть, когда приходит запрос-запрос, он сначала рассудит, существует ли значение через фильтр Блума, а затем продолжит проверку, существует ли оно.
Принцип фильтра Блума: он состоит из массива растровых изображений с начальным значением 0 и N хеш-функций. Один выполняет N хеш-алгоритмов для ключа, чтобы получить N значений, хэширует N значений в битовом массиве и устанавливает их в 1, а затем проверяет, все ли эти конкретные позиции равны 1, затем фильтрация Блума Устройство определяет, что ключ существует .
3.5 Проблема запуска кеша на снегу
Кэш Сюэбэнь:Относится к большому объему данных в кеше до истечения срока действия и большому объему данных запроса, запрос напрямую обращается к базе данных, вызывая чрезмерное давление на базу данных или даже отключение.
- Кэш Xueben обычно вызывается одновременным истечением срока действия большого количества данных, поэтому его можно решить, установив время истечения равномерно, то есть сделав время истечения относительно дискретным. Например, используется большее фиксированное значение + меньшее случайное значение, 5 часов + от 0 до 1800 секунд.
- Время простоя Redis из-за сбоя также может привести к запуску кэша. Для этого требуется создание кластера высокой доступности Redis.
3.6 Проблема с поломкой кеша
Разбивка кеша:Это относится ко времени, когда срок действия горячего ключа истекает в определенный момент времени, и в этот момент времени существует большое количество одновременных запросов на этот ключ, поэтому большое количество запросов попадает в базу данных.
Разбивка кеша выглядит немного похоже. На самом деле разница между ними заключается в том, что запуск кеша в снегу означает, что нагрузка на базу данных слишком высока или даже выключает машину. Разбивка кеша — это просто большое количество одновременных запросов к уровню базы данных БД. . Можно считать, что разбивка является подмножеством кэша Xueben. В некоторых статьях считается, что разница между ними заключается в том, что разница заключается в поломке кеша горячих клавиш, тогда как Сюэ Бен — это много ключей.
Есть два решения:
- 1. Используйте схему блокировки мьютекса. В случае сбоя кеша вместо немедленной загрузки данных базы данных используйте некоторые команды атомарных операций с успешным возвратом, например (setnx Redis), для работы, а в случае успеха загрузите данные базы данных базы данных и установите кеш. В противном случае повторите попытку получения кеша.
- 2. «Никогда не истекает», что означает, что время истечения срока действия не установлено, но когда срок действия данных точки доступа подходит к концу, асинхронный поток обновляет и устанавливает время истечения срока действия.
3.7. Проблема с горячими клавишами кэша
В Redis мы называем ключи с высокой частотой доступа ключами хотспотов. Если запрос на горячую клавишу отправляется на хост-сервер, из-за большого количества запросов хост может пострадать от нехватки ресурсов или даже простоя, что повлияет на нормальные услуги.
А как генерируется горячий ключ? Есть две основные причины:
- Данные, потребляемые пользователями, намного больше, чем производимые данные, такие как всплески, горячие новости и другие сценарии, в которых больше операций чтения и меньше операций записи.
- Осколки запросов сконцентрированы, что превышает производительность одного сервера Redi.Например, если ключ с фиксированным именем и хеш попадают на один и тот же сервер, мгновенный объем доступа будет чрезвычайно большим, превысив узкое место машины, что приведет к горячему ключу. проблема.
Итак, в повседневной разработке, как определить горячие клавиши?
- Определение горячих клавиш на основе опыта;
- отчет о статистике клиентов;
- Отчет уровня сервисного агента
Как решить проблему с горячим ключом?
- Расширение кластера Redis: увеличьте количество реплик шардов, чтобы сбалансировать трафик чтения;
- Хешируйте горячую клавишу, например резервное копирование ключа как key1, key2...keyN, N резервных копий одних и тех же данных, N резервных копий распределяются по разным шардам, и при доступе к одной из N резервных копий может быть получен произвольный доступ, и далее делиться прочитанным трафиком;
- Используйте кеш второго уровня, то есть локальный кеш JVM, чтобы уменьшить количество запросов на чтение Redis.
4. Эксплуатация и обслуживание конфигурации Redis
4.1 Используйте длинные соединения вместо коротких и разумно настройте пул соединений клиента.
- Если вы используете короткое соединение, вам нужно каждый раз проходить трехстороннее рукопожатие TCP и четыре волны, что увеличит время. Однако, если соединение длинное, он устанавливает соединение один раз, а команду redis можно использовать все время.Jiangzi может сократить время установления соединения redis.
- Пул соединений может устанавливать несколько соединений на стороне клиента и не освобождать их.Когда соединение необходимо использовать, ему не нужно каждый раз создавать соединение, что экономит время. Однако параметры должны быть заданы разумно, а ресурсы подключения должны быть освобождены вовремя, когда Redis не используется в течение длительного времени.
4.2 Используйте только db0
Автономная архитектура Redis запрещает использование не-db0 по двум причинам.
- Для подключения Redis выполняет команду select 0 и select 1 для переключения, что будет потреблять новую энергию.
- Redis Cluster поддерживает только db0, миграция которого обходится дорого.
4.3 Установите maxmemory + соответствующую стратегию устранения.
Чтобы память не раздувалась. Например, иногда объем бизнеса увеличился, ключ Redis используется часто, памяти явно недостаточно, а брат по эксплуатации и обслуживанию также забыл увеличить память. Redis так зависает? Следовательно, необходимо выбрать maxmemory-policy (максимальная политика ликвидации памяти) и установить время истечения срока действия в соответствии с фактическим бизнесом. Всего существует 8 стратегий устранения памяти:
- volatile-lru: когда памяти недостаточно для размещения вновь записанных данных, используйте алгоритм LRU (наименее недавно использовавшийся) для исключения из ключа с установленным временем истечения;
- allkeys-lru: используйте алгоритм LRU (наименее недавно использовавшийся) для удаления всех ключей, когда памяти недостаточно для вновь записанных данных.
- volatile-lfu: Добавлено в версии 4.0, когда памяти не хватает для размещения вновь записанных данных, используется алгоритм LFU для удаления ключей в ключах с истекшим сроком действия.
- allkeys-lfu: Добавлено в версии 4.0, когда памяти не хватает для размещения вновь записываемых данных, используется алгоритм LFU для исключения всех ключей;
- volatile-random: когда памяти недостаточно для размещения вновь записанных данных, данные удаляются из ключа случайным образом с установленным временем истечения;
- allkeys-random: случайным образом удалять данные со всех ключей, когда памяти недостаточно для вновь записанных данных.
- volatile-ttl: Когда памяти недостаточно для размещения вновь записанных данных, в ключе с установленным временем истечения оно будет устранено в соответствии со временем истечения срока действия, а ранее истекшее будет устранено первым;
- noeviction: политика по умолчанию, когда памяти недостаточно для размещения вновь записанных данных, новая операция записи сообщит об ошибке.
4.4 Включить механизм бездействия
Версия Redis 4.0+ поддерживает механизм lazy-free, если в вашем Redis все еще есть что-то вроде bigKey, рекомендуется включить lazy-free. Когда он включен, если Redis удаляет большой ключ, трудоемкая операция освобождения памяти будет выполняться в фоновом потоке, уменьшая эффект блокировки в основном потоке.
Ссылка и спасибо
- Redis не должен использовать команду KEYS без разбора, иначе вы будете побеждены.
- Спецификация разработки Alibaba Cloud Redis
- Руководство Redis Best Practice: 7 измерений + 43 спецификации использования
- Проникновение кэша Redis и решение - Bloom Filter BloomFilter
- Практика производительности кеша Redis и краткое изложение