Преамбула
В предыдущей статье «Почему Redis такой быстрый» были представлены инструменты оценки производительности Redis и причины высокой производительности Redis. Подробнее см.: В этой статье мы расскажем о факторах, влияющих на производительность Redis, и о том, как повысить производительность Redis с точки зрения бизнеса.
Анализ процесса запроса от пользователя на Redis
Если взять в качестве примера наиболее распространенный кеш сценариев, процесс передачи трафика от пользователей к Redis Server выглядит следующим образом:
- Пользователь обращается к внутреннему серверу и вызывает соответствующий контроллер.
- Контроллер обращается к записи кеша и вызывает Redis через клиент Redis, чтобы получить запись из кеша. Если для получения объекта Jedis используется пул соединений Jedis, получите экземпляр соединения Jedis из пула соединений Jedis.
- Jedis использует протокол сериализации Redis (RESP) для кодирования команд во входной буфер сервера Redis.
- Redis Server получает команду из входного буфера и выполняет ее.
- После завершения выполнения результат выполнения помещается в выходной буфер.
- Клиент Jedis получает результат выполнения из выходного буфера и возвращает его контроллеру.
- Контроллер выполняет бизнес-логику, соответствующую запросу пользователя.
Как видно из приведенной выше диаграммы последовательности, запрос пользователя поступает на сервер Redis по сети через клиент Redis.
Поэтому при рассмотрении производительности Redis ее необходимо рассматривать с точки зрения клиента и сервера. С точки зрения бизнеса рациональное использование возможностей Redis более работоспособно, чем оптимизация сервера Redis, и получить хорошие результаты проще.
Далее будет представлена оптимизация Redis с двух сторон: оптимизация бизнеса и оптимизация сервера.
оптимизация бизнеса
Задержка запроса локального Redis обычно составляет менее 1 мс, а задержка запроса Redis в том же центре обработки данных обычно составляет менее 5 мс. Другими словами, потери передачи по сети в 5 раз превышают фактическое время работы.
Поэтому, с точки зрения клиента, очень важно, как сократить потребление времени в сети.
Используйте пул соединений, чтобы сократить время, затрачиваемое на установление и удаление соединений.
Jedis — наиболее часто используемый клиент Redis для языка Java. Jedis поддерживает прямое соединение и пул соединений двумя способами.
Метод прямого подключения:
# 1. 生成一个Jedis对象,这个对象负责和指定Redis实例进行通信
Jedis jedis = new Jedis("127.0.0.1", 6379);
# 2. jedis执行set操作
jedis.set("hello", "world");
# 3. jedis执行get操作 value="world"
String value = jedis.get("hello");
Так называемое прямое соединение означает, что Jedis каждый раз будет создавать новое TCP-соединение, а затем отключать его после использования. Все мы знаем, что создание TCP-соединения проходит через три рукопожатия, а освобождение TCP-соединения — через четыре взмаха рук.Это очень трудоемкая операция по созданию и повторному использованию. Очевидно, что это неэффективный способ частого использования Redis.
Jedis также предоставляет метод пула соединений.
Выдержка из: «Разработка и эксплуатация Redis»// common-pool连接池配置,这里使用默认配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // 初始化Jedis连接池
JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
Jedis jedis = null; try {
// 1. 从连接池获取jedis对象
jedis = jedisPool.getResource();
// 2. 执行操作
jedis.get("hello");
} catch (Exception e) {
logger.error(e.getMessage(),e);
} finally {
if (jedis != null) {
// 如果使用JedisPool,close操作不是关闭连接,代表归还连接池
jedis.close();
}
}
Используйте скрипты Pipeline или Lua, чтобы уменьшить количество запросов
Пулы соединений сокращают затраты времени на установление и отключение TCP-соединений. Кроме того, Redis предоставляет еще три способа повысить производительность за счет уменьшения количества запросов. (1) Команды для пакетных операций, такие как mget, mset и т. д. (2) конвейерный метод (3) Lua-скрипт
Метод трубопровода
Используйте redis-benchmark для сравнения конвейера (16 команд за раз) и обычных запросов на процессоре Intel(R) Xeon(R) E5520 @ 2,27 ГГц.
Случай использования трубопровода:
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (without pipelining)
Без трубопровода:
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second
Из результатов тестов видно, что использование конвейерной технологии повышает производительность примерно в 5-10 раз по сравнению с ее отсутствием.
Jedis поддерживает функцию Pipeline. Мы знаем, что Redis предоставляет методы mget и mset, но не предоставляет метод mdel. Если вы хотите реализовать эту функцию, вы можете использовать Pipeline для имитации пакетного удаления. Хотя это не атомарная команда как mget и mset, но может использоваться в большинстве сценариев.
public void mdel(List<String> keys) {
Jedis jedis = new Jedis("127.0.0.1");
// 1)生成pipeline对象 Pipe
line pipeline = jedis.pipelined();
// 2)pipeline执行命令,注意此时命令并未真正执行
for (String key : keys) {
pipeline.del(key);
}
// 3)执行命令
pipeline.sync();
}
Чтобы инкапсулировать команду del в конвейер, вы можете вызвать pipe.del (ключ String), и в это время команда выполняться не будет.
Используйте pipe.sync() для завершения вызова объекта конвейера.
В дополнение к pipe.sync() вы также можете использовать pipe.syncAndReturnAll() для возврата команды конвейера.
Причина, по которой конвейер повышает производительность
Одной из причин повышения производительности конвейера является сокращение общего времени RTT (задержка приема-передачи) команды, а с другой стороны, уменьшение общего количества системных вызовов.
RTT (время приема-передачи): задержка приема-передачи. Это важный показатель производительности в компьютерных сетях, показывающий общую задержку с момента, когда отправитель отправляет данные, до тех пор, пока отправитель не получит подтверждение от получателя (получатель отправляет подтверждение сразу после получения данных). Задержка приема-передачи (RTT) определяется тремя компонентами: временем распространения канала, временем обработки конечных систем и временем постановки в очередь и обработки в кэше маршрутизатора. Среди них значения первых двух частей относительно фиксированы в качестве TCP-соединения, а время постановки в очередь и время обработки в кэше маршрутизатора будет меняться с изменением степени загруженности всей сети. Следовательно, изменение RTT в определенной степени отражает изменение степени загруженности сети. Проще говоря, это время, которое проходит отправитель с момента отправки данных до получения подтверждения от получателя.
Разница между конвейером и скриптом lua
Redis изначально поддерживает язык Lua и предоставляет команды для выполнения сценариев lua через клиент.
Например, мы можем использовать сценарии Lua для реализации распределенных блокировок в более ранних версиях Redis.
local current current = redis.call('incr',KEYS[1])
if tonumber(current) == 1
then
redis.call('expire',KEYS[1], ARGV[1])
end
return current
При вызове команды EVAL могут передаваться неопределенные значения KEY и ARGS, доступ к этим значениям возможен через KEY[i] и ARGV[i] к соответствующим входным параметрам, а результат выполнения возвращается через return.
Другие сценарии Lua будут представлены в других статьях.
Вы можете следить за общедоступной учетной записью WeChat: нетипичный научный мужчина, просматривать список всех статей и читать статьи, связанные со сценариями Lua.
сравнение конвейера и Lua:
(1) Возвращаемые результаты разные: конвейер вернет все результаты выполнения команды, а lua-скрипт возвращает только один результат.
(2) Различные сценарии использования: сценарии lua могут выполнять сложные логические операции и предоставлять функцию кэширования сценариев для повышения производительности, как и собственные команды. Поэтому lua-скрипты можно использовать в сценариях, где логика обработки сложная, и нет необходимости возвращать или только возвращать результат операции. Конвейер используется в сценариях, где команды объединяются, чтобы уменьшить нагрузку на выполнение и перераспределить нагрузку на сервер.
Есть несколько предостережений при использовании конвейеров:
(1) Хотя нет четкого ограничения на количество команд выполнения для команд выполнения конвейера, рекомендуется ограничить количество команд выполнения. Чрезмерное количество выполняемых команд с одной стороны занимает пропускную способность сети, а с другой блокирует работу клиента.
Факторы производительности Redis Server
Производительность Redis Server в основном зависит от оборудования, распределения данных и конфигурации.
аппаратный фактор
Redis любит следующие аппаратные условия:
- Сеть с высокой пропускной способностью и малой задержкой. Пропускная способность сети и задержка обычно являются самыми большими недостатками производительности Redis. Поэтому необходимо выбирать сеть с высокой пропускной способностью и малой задержкой.
- Большой кэш, быстрый процессор: не многоядерный. В этом случае рекомендуется ЦП Intel. Процессоры AMD могут иметь вдвое меньшую производительность, чем процессоры Intel (при сравнении платформ Nehalem EP/Westmere EP/Sandy). При прочих равных условиях CPU становится ограничивающим фактором для redis-benchmark.
- Память и пропускная способность особенно важны при хранении больших объектов (> 10 КБ). Но еще важнее оптимизировать хранение больших объектов.
- Беги Redis на физической машине: redis будет медленно на виртуальной машине. Виртуализация будет иметь дополнительное потребление для обычных операций, а Redis не будет иметь слишком много накладных расходов для системных вызовов и сетевых терминалов. Рекомендуется запустить Redis на физической машине.
Влияние большой ценности
Размер пакета влияет на соответствующую скорость Redis. Когда пакет сетевых данных Ethernet меньше 1500 байт, упаковка нескольких команд в конвейерную обработку может значительно повысить эффективность. На самом деле при обработке запросов на 10 байт, 100 байт и 1000 байт пропускная способность одинакова, подробнее см. рисунок ниже.
Поэтому, когда существует большое значение (> 10k), его следует оптимизировать во времени.
Справочная документация:
Что такое архитектурный дизайн? Архитектурный дизайн достаточно прочитать эту статью
Heavy: интерпретация последнего экологического отчета JVM за 2020 г.
Что вы знаете о новых возможностях JDK8?
Ответьте на «данные» и получите эксклюзивные технические данные, составленные наизусть бесплатно!