Redis реализован на основе однопоточной модели, то есть Redis использует один поток для обработки всех клиентских запросов, хотя Redis использует неблокирующий ввод-вывод и оптимизирует различные команды (большинство командных операций сложны по времени) Степень O(1 )), но поскольку Redis характеризуется однопоточным выполнением, к нему предъявляются более строгие требования к производительности.В этой статье мы воспользуемся некоторыми методами оптимизации, чтобы сделать Redis более эффективным.
В этой статье мы будем использовать следующие средства для повышения скорости Redis:
- Сократите длину хранения пар ключ-значение;
- Используйте ленивую бесплатную функцию;
- Установить срок действия значения ключа;
- Отключите длительные команды запросов;
- Используйте slowlog для оптимизации трудоемких команд;
- Используйте Pipeline для пакетной обработки данных;
- Избегайте большого количества сбоев данных одновременно;
- Оптимизация использования клиента;
- ограничение размера памяти Redis;
- Установите службу Redis, используя физическую машину вместо виртуальной;
- Проверьте стратегию сохранения данных;
- Отключите функцию THP;
- Используйте распределенную архитектуру для увеличения скорости чтения и записи.
1. Сократите длину хранения пар ключ-значение
Длина пары ключевых значений обратно пропорциональна производительности. Например, давайте сделаем набор тестов производительности для записи данных. Результаты выполнения следующие:
Из приведенных выше данных видно, что когда ключ остается неизменным, чем больше значение, тем медленнее эффективность работы, потому что Redis использует разные внутренние кодировки для одного и того же типа данных для хранения.Например, существует три внутренних кодировки для строк : int (целочисленное кодирование), raw (кодирование строк, оптимизированное для выделения памяти), embstr (кодирование динамических строк), это потому, что автор Redis хочет достичь баланса между эффективностью и пространством за счет разных кодировок, но чем больше объем используемые данные Чем сложнее внутренний код и чем сложнее внутренний код хранится, тем ниже производительность.
Это только скорость записи, когда содержимое пары ключ-значение большое, это принесет несколько других проблем:
- Чем больше содержимое, тем дольше время сохранения, дольше время приостановки и ниже производительность Redis;
- Чем больше контент, тем больше контента передается по сети, тем дольше это происходит и тем ниже общая скорость работы;
- Чем больше содержимое, тем больше памяти оно занимает, и механизм исключения памяти будет срабатывать чаще, что приведет к увеличению операционной нагрузки на Redis.
Поэтому, обеспечивая полную семантику, мы должны максимально сократить длину хранения пар ключ-значение, а также сериализовать и сжать данные для хранения, если это необходимо.На примере Java мы можем использовать protostuff или kryo для сериализации, и для сжатия мы можем использовать snappy.
2. Используйте ленивую бесплатную функцию
Ленивая бесплатная функция — очень полезная функция, добавленная в Redis 4.0, которую можно понимать как ленивое удаление или отложенное удаление. Имеется в виду обеспечение функции асинхронной задержки выпуска значений ключа при удалении и помещение операции выпуска значения ключа в отдельный подпоток обработки BIO (Background I/O) для уменьшения блокировки удаления и удаления на основной поток Redis, который может быть эффективным, чтобы избежать проблем с производительностью и доступностью при удалении больших ключей.
Lazy free соответствует 4 сценариям, которые по умолчанию отключены:
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
Они представляют собой следующее:
- lazyfree-lazy-eviction: указывает, следует ли включить механизм отложенного освобождения для удаления, когда рабочая память Redis превышает maxmeory;
- lazyfree-lazy-expire: указывает, что установлено значение ключа со временем истечения срока действия, и следует ли включить механизм отложенного бесплатного удаления после истечения срока действия;
- lazyfree-lazy-server-del: некоторые команды будут иметь неявную операцию ключа del при работе с существующими ключами, например команда переименования.Когда целевой ключ уже существует, Redis сначала удалит целевой ключ, если эти цели Ключ большой ключ, который вызовет проблему блокировки удаления.Эта конфигурация указывает, следует ли включить ленивый свободный механизм для удаления в этом сценарии;
- slave-lazy-flush: для синхронизации данных подчиненного устройства (подчиненного устройства) подчиненное устройство запустит flushall, чтобы очистить свои собственные данные перед загрузкой файла RDB главного устройства, что указывает, следует ли включить в это время механизм отложенного свободного удаления.
Рекомендуется включить такие конфигурации, как lazyfree-lazy-eviction, lazyfree-lazy-expire и lazyfree-lazy-server-del, которые могут эффективно повысить эффективность выполнения основного потока.
3. Установите срок действия значения ключа
Мы должны установить разумное время истечения срока действия для значения ключа в соответствии с реальной деловой ситуацией, чтобы Redis автоматически очищал пару ключ-значение с истекшим сроком действия, чтобы вы могли сэкономить использование памяти, избежать чрезмерного накопления значения ключа и часто запускать стратегию устранения памяти. .
4. Отключите команды запросов, отнимающие много времени.
Временная сложность большинства команд чтения и записи Redis находится между O (1) и O (N).В официальном документе есть описание временной сложности для каждой команды, адрес:redis.io/commands следующим образом...
Среди них O (1) означает, что его можно использовать безопасно, а O (N) следует быть осторожным, N означает неопределенность, а скорость запроса может быть ниже при больших объемах данных. Поскольку Redis использует только один поток для запроса данных, если эти инструкции занимают много времени, это заблокирует Redis и вызовет большую задержку.Чтобы избежать влияния команд O(N) на Redis, вы можете начать со следующих аспектов:
- Решено запретить использование клавиш команды;
- Чтобы избежать одновременного запроса всех элементов, используйте команду сканирования для выполнения пакетного обхода в стиле курсора;
- Строго контролировать размер данных Hash, Set, Sorted Set и других структур с помощью механизмов;
- Выполнять такие операции, как сортировка, объединение и пересечение на клиенте, чтобы снизить нагрузку на сервер Redis;
- Удаление (удаление) больших данных может занять много времени, поэтому рекомендуется использовать метод асинхронного удаления для разъединения, который запустит новый поток для удаления целевых данных без блокировки основного потока Redis.
5. Используйте slowlog для оптимизации трудоемких команд
Мы можем использовать функцию SLOWLLOG, чтобы определить самые трудоемкие команды Redis, связанные с оптимизациями, чтобы улучшить скорость работы Redis, медленный запрос Существует два важных элемента конфигурации:
-
slowlog-log-slower-than
: используется для установки времени оценки медленного запроса, то есть команды, превышающие этот элемент конфигурации, будут записываться как медленные операции в журнал медленных запросов, а его единица выполнения — микросекунды (1 секунда равна 1000000 микросекунд); -
slowlog-max-len
: используется для настройки максимального количества записей в журнале медленных запросов.
Мы можем настроить его в соответствии с реальной бизнес-ситуацией.Журнал медленных запросов хранится в журнале медленных запросов в порядке, обратном порядку вставки.Мы можем использоватьslowlog get n
чтобы получить соответствующие журналы медленных запросов, а затем найти службы, соответствующие этим медленным запросам, для соответствующей оптимизации.
6. Используйте Pipeline для пакетной обработки данных
Трубопровод (технология трубопровода) - это пакетная технология, предоставляемая клиентом для обработки нескольких команд REDIS одновременно, тем самым улучшая производительность всего взаимодействия.
Мы используем код Java для тестирования сравнения производительности между Pipeline и обычными операциями.Тестовый код Pipeline выглядит следующим образом:
public class PipelineExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 记录执行开始时间
long beginTime = System.currentTimeMillis();
// 获取 Pipeline 对象
Pipeline pipe = jedis.pipelined();
// 设置多个 Redis 命令
for (int i = 0; i < 100; i++) {
pipe.set("key" + i, "val" + i);
pipe.del("key"+i);
}
// 执行命令
pipe.sync();
// 记录执行结束时间
long endTime = System.currentTimeMillis();
System.out.println("执行耗时:" + (endTime - beginTime) + "毫秒");
}
}
Результат выполнения вышеуказанной программы:
Время выполнения: 297 мс
Код нормальной работы выглядит следующим образом:
public class PipelineExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 记录执行开始时间
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
jedis.set("key" + i, "val" + i);
jedis.del("key"+i);
}
// 记录执行结束时间
long endTime = System.currentTimeMillis();
System.out.println("执行耗时:" + (endTime - beginTime) + "毫秒");
}
}
Результат выполнения вышеуказанной программы:
Время выполнения: 17276 миллисекунд
Из приведенных выше результатов можно увидеть, что время выполнения трубопровода составляет 297 миллисекунд, в то время как обычное время выполнения команды составляет 17276 миллисекунд. Технология трубопровода составляет около 58 раз быстрее, чем обычное исполнение.
7. Избегайте одновременной аннулирования больших объемов данных
Удаление значения ключа Redis с истекшим сроком действия использует жадную стратегию, которая выполняет 10 проверок срока действия в секунду.Эта конфигурация может быть настроена в redis.conf.Значение по умолчанию:hz 10
, Redis случайным образом извлечет значения 20 и удалит ключи с истекшим сроком действия среди ключей 20. Если доля ключей с истекшим сроком действия превышает 25%, повторите этот процесс, как показано на следующем рисунке:
Если срок действия большого количества кешей истекает одновременно в большой системе, это приведет к тому, что цикл Redis будет непрерывно сканировать и удалять словарь с истекшим сроком действия много раз, пока значения ключей с истекшим сроком действия в словаре с истекшим сроком не будут удалены редко, а весь процесс выполнения вызовет Redis Существует очевидная задержка при чтении и записи Другая причина задержки заключается в том, что диспетчеру памяти необходимо часто перерабатывать страницы памяти, поэтому он также потребляет определенное количество ресурсов ЦП.
Чтобы избежать такого явления зависания, нам нужно предотвратить одновременное истечение срока действия большого количества кешей.Простое решение — добавить случайное число из указанного диапазона на основе времени истечения срока действия.
8. Оптимизация использования клиента
При использовании клиента, помимо максимально возможного использования технологии Pipeline, нам также необходимо уделять внимание максимально возможному использованию пула соединений Redis вместо частого создания и уничтожения соединений Redis, что может уменьшить количество сетевых переводов и ненужных инструкций по вызову.
9. Ограничьте размер памяти Redis
Ограничения на объем памяти Redis в 64-битной операционной системе нет, то есть пункт конфигурацииmaxmemory <bytes>
закомментирован, что приведет к использованию пространства подкачки и пространства подкачки при нехватке физической памяти, а когда обеспокоенная система переместит подкачку памяти, используемую Redis, в пространство подкачки, процесс Redis будет заблокирован, что приведет к задержка в Redis, что влияет на общую производительность Redis. Поэтому нам нужно ограничить размер памяти Redis фиксированным значением.Когда операция Redis достигнет этого значения, будет запущена стратегия ликвидации памяти.Существует 8 стратегий устранения памяти после Redis 4.0:
- noeviction: данные не удаляются. Если памяти недостаточно, новая операция сообщит об ошибке. Redis по умолчанию использует стратегию устранения памяти;
- allkeys-lru: исключить самое длинное неиспользуемое значение ключа из всего значения ключа;
- allkeys-random: случайным образом исключить любое значение ключа;
- volatile-lru: исключить самое старое неиспользуемое значение ключа среди всех значений ключа с установленным сроком действия;
- volatile-random: случайным образом исключить любое значение ключа с установленным сроком действия;
- volatile-ttl: приоритет значений ключей, срок действия которых истекает раньше.
В Redis 4.0 добавлены две новые стратегии исключения:
- volatile-lfu: исключить наименее используемое значение ключа среди всех значений ключа с установленным сроком действия;
- allkeys-lfu: исключить наименее используемое значение ключа из всего значения ключа.
где allkeys-xxx означает вытеснение данных из всех значений ключей, а volatile-xxx означает вытеснение данных из значений ключей с ключами с истекшим сроком действия.
Мы можем установить его в соответствии с реальной деловой ситуацией.Стратегия исключения по умолчанию не удаляет данные, и при добавлении будет сообщено об ошибке.
10. Используйте физические машины вместо виртуальных машин
Запуск сервера Redis на виртуальной машине, поскольку он использует физический сетевой порт совместно с физической машиной, а на физической машине может быть запущено несколько виртуальных машин, поэтому у него будет плохая производительность с точки зрения использования памяти и сетевой задержки, мы можем пройти через./redis-cli --intrinsic-latency 100
Команда для проверки времени задержки.Если у вас высокие требования к производительности Redis, вам следует максимально развернуть сервер Redis непосредственно на физической машине.
11. Проверьте стратегию сохранения данных
Стратегия redis redis состоит в том, чтобы скопировать данные памяти на жесткий диск, чтобы вызвать аварийное восстановление или миграцию данных, но поддержание этой функции настойчивости требует большого количества производительности.
После Redis 4.0 у Redis есть 3 способа сохранения:
- RDB (Redis DataBase, snapshot mode) записывает данные памяти в определенный момент на диск в бинарном режиме;
- AOF (Append Only File), который записывает все рабочие команды и добавляет их в файл в виде текста;
- Гибридный метод персистентности, новый метод после Redis 4.0, гибридная персистентность сочетает в себе преимущества RDB и AOF.При записи сначала записывать текущие данные в начало файла в виде RDB, а потом последующие данные записывать в начало Команды операций хранятся в файлах в формате AOF, что позволяет не только обеспечить скорость перезапуска Redis, но и снизить риск потери данных.
Сохранение RDB и AOF имеет свои преимущества и недостатки. RDB может привести к потере данных в течение определенного периода времени, в то время как AOF повлияет на скорость запуска Redis из-за большого размера файла. Чтобы иметь преимущества RDB и AOF в В то же время Redis 4.0 добавил новую функцию — метод гибридного сохранения, поэтому, когда мы должны выполнять постоянные операции, мы должны выбрать метод гибридного сохранения.
Запрос, можно ли использовать гибридное сохранениеconfig get aof-use-rdb-preamble
команда, результат выполнения показан на следующем рисунке:
- Открыть через командную строку
- Откройте, изменив файл конфигурации Redis
① Открыть через командную строку
использовать командуconfig set aof-use-rdb-preamble yes
Результат выполнения показан на рисунке ниже:
② Откройте, изменив файл конфигурации Redis.
Найдите файл redis.conf в корневом каталоге Redis и поместитеaof-use-rdb-preamble no
изменить наaof-use-rdb-preamble yes
Как показано ниже:
Следует отметить, что в бизнесе, который не должен быть постоянным, постоянство можно отключить, что может эффективно повысить скорость работы Redis без проблем с периодическими задержками.
12. Отключите функцию THP
Ядро Linux добавило функцию Transparent Huge Pages (THP) в ядре 2.6.38 для поддержки выделения 2 МБ для больших страниц памяти, которая включена по умолчанию.
При включении THP скорость форка будет меньше, после форка каждая страница памяти будет изменена с 4Кб на 2Мб, что сильно увеличит потребление памяти родительским процессом при перезаписи. В то же время единица копируемой страницы памяти, вызванная каждой командой записи, увеличивается в 512 раз, что замедляет время выполнения операции записи, приводя к медленным запросам для большого количества операций записи. Например, простые команды incr также могут появляться в медленных запросах, поэтому Redis рекомендует отключить эту функцию, способ ее отключения следующий:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
Чтобы конфигурация THP по-прежнему действовала после перезапуска машины, вы можете добавить в /etc/rc.localecho never > /sys/kernel/mm/transparent_hugepage/enabled
.
13. Используйте распределенную архитектуру для увеличения скорости чтения и записи
Распределенная архитектура Redis имеет три важных средства:
- синхронизация ведущий-ведомый
- Режим стража
- Кластерный кластер Redis
Используя функцию синхронизации master-slave, мы можем выполнять запись в основную библиотеку и передавать функцию чтения подчиненному сервису, чтобы в единицу времени можно было обрабатывать больше запросов, тем самым повышая общую скорость работы Redis.
Режим Sentinel представляет собой обновление функции master-slave, но при сбое главного узла нормальное использование Redis может быть автоматически восстановлено без ручного вмешательства.
Redis Cluster официально запущен в Redis 3.0.Redis Cluster уравновешивает давление нагрузки каждого узла, распределяя базу данных по нескольким узлам.
Redis Cluster использует раздел виртуального хеш-слота, все ключи сопоставляются с целочисленными слотами от 0 до 16383 в соответствии с хеш-функцией, формула расчета: слот = CRC16 (ключ) и 16383, каждый узел отвечает за поддержание части слота и ключ сопоставляется с данными значения слота. Таким образом, Redis может распределять давление чтения и записи с одного сервера на несколько серверов, поэтому производительность будет значительно улучшена.
Среди этих трех функций нам нужно использовать только одну.Нет никаких сомнений в том, что Redis Cluster должен быть предпочтительным решением для реализации.Он может автоматически распределять давление чтения и записи на большее количество серверов и имеет возможность автоматического аварийного восстановления.
Следуйте QR-коду ниже, чтобы подписаться на более интересный контент.