Thank you for reading this post, don't forget to subscribe!
Рассмотрим основные параметры конфигурации Redis, их значения, как они и на что они влияют, и на какие из них стоит обратить внимание.
Местами совсем кратко, но везде со ссылками.
Начать, пожалуй, стоит с утилиты redis-benchmark
https://github.com/maxux/redis-benchmark .
Устанавливается вместе с сами Redis, можно сразу использовать:
Кроме того — можно выполнить проверку количества операций с помощью redis-cli
и опции --latency
или --latency-dist
:
Redis server-level config
timeout
Отключать соединение при неактивности клиента заданное количество секунд.
Ноль для отключения возможности (IDLE-клиенты будут висеть до перезагрузки, или пока не отключатся сами):
В целом — есть смысл оставить дефолтные 300 секунд, что бы не оставались зависшие клиенты.
tcp-keepalive
Не влияет при PUBLISH/SUBSCRIBE (real-time operations), см. Redis Pub/Sub: Intro Guide и Redis Pub/Sub… How Does it Work?
Сервер отправляет ACK-запросы (Acknowledgment) через указанный промежуток времени в секундах, поддерживая сессию:
Значение по-умолчанию — 300 секунд (но зависит от версии).
Если клиент не отвечает на запрос — соединение закрывается.
Если и timeout
, и tcp-keepalive
на стороне сервера будут заданы в 0 (отключены) — то «мёртвые» подключения будут висеть до перезагрузки сервера.
См. Things that you may want to know about TCP Keepalives.
Проверяем с включенным tcp-keepalive
(-k
== 1):
И без:
Снова-таки — не вижу смысла в отключении проверки вообще, потому — оставляем дефолтные 300 секунд.
RDB Persistence
Создаёт полную копию базы. См. Redis Persistence.
Поведение определяется параметром save
(см. также Redis save, SAVE и BGSAVE).
Проверяем:
Удаляем:
Сохраняем:
В случае, если Redis используется просто для кеширования — можно отключить: убираем save
из конфига вообще.
При этом сам механизм RDB будет использоваться для синхронизации мастер-слейв при использовании репликации (см. Redis: репликация, часть 1 — обзор. Replication vs Sharding. Sentinel vs Cluster. Топология Redis).
AOF persistence
Append Only File — сохраняет в лог каждую операцию.
Аналогично RDB, если Redis используем просто, как кеш — лог не нужен.
Для отключения — меняем параметр appendonly
, и задаём его в no:
maxmemory
maxmemory
задаёт максимальный размер памяти сервера, который будет доступен Redis-у для хранения данных.
См. Using Redis as an LRU cache.
Может быть задан в виде %:
Или мегабайт/гигабайт:
Или в 0 для отключения лимита вообще и является значением по-умолчанию для 64-х битных систем. Для 32-х битных — 3 ГБ.
При достижении лимита — будут выбрано решение об удалении данных, основываясь на политиках, см. maxmemory-policy.
Учитывая, что у нас на каждом хосте кроме самого Redis крутятся PHP-процессы и memcached
— под Redis можно отдать не более 50% памяти.
maxmemory-policy
Определяет политику, которая будет использовать Redis при достижении maxmemory
.
Note: LRU — Less Recently Used
Может иметь одно из значений:
volatile-lru
: будут удалены наименее используемые ключи, у которых заданexpire
allkeys-lru
: будут удалены наименее используемые ключи независимо отexpire
volatile-random
: удалить случайный ключ с заданнымexpire
allkeys-random
: удалить случайный ключ независимо отexpire
volatile-ttl
: удалить ключ с наименьшим оставшимся TTLnoeviction
: не выполнять очистку вообще, просто возвращать ошибку при операциях записи
Для проверки значение expire
— используйте TTL
/PTTL
:
В нашем случае — девелоперы не уверены, что expire
задаётся для всех ключей, а учитывая, что снова-таки — это просто сервис кеширования, данные из которого потерять не страшно — то задаём maxmemory-policy allkeys-lru
.
unixsocket
Если приложение и Redis работают на одном хосте — попробуйте использование сокета вместо TCP-порта.
Задаём:
Может дать хороший прирост производительности, см. Tuning Redis for extra Magento performance.
Проверим с redis-benchmark
.
Создаём тестовый конфиг:
Запускаем с сокетом:
И через TCP-порт:
loglevel
Уровень детализации лога. При debug — наиболее подробный, следовательно — отнимает больше ресурсов.
Может быть (от наиболее подробного — к наименее): debug, verbose, notice, warning.
Значение по-умолчанию — notice, пока сервис в процессе допиливания — можно оставить notice, позже — переключить в warning.
OS-level config
Transparent Huge Page
Механизм ядра Linux, позволяющий уменьшить количество объектов при выделении и управлении виртуальной памятью. См Transparent Hugepages: measuring the performance impact, Disable Transparent Hugepages и Latency induced by transparent huge pages.
В Redis, судя по документации>>>, имеет значение только при включенном RDB, но имеет смысл отключить вообще:
Проверить текущее значение можно:
Значение в скобках явлется текущим заданным значением, а данном случае — madvice.
madvice указывает на использование THP только в случае, если это явно запрошено приложением через вызов madvice()
.
Проверить состояние можно так:
maxclients
и fs.file-max
Задаёт максимальное количество одновременно подключенных клиентов.
Значение по умолчанию — 10.000, переопределяется через maxclients
, см. Maximum number of clients.
При этом Redis проверяет лимиты операционной системы на максимальное количество файловых дескрипторов — sysctl fs.file-max
глобально для ядра:
И ulimit
для пользователя на каждый процесс:
Для systemd-based систем можно задать лимит через systemd-юнит файл Redis с помощью LimitNOFILE
:
tcp-backlog
и net.core.somaxconn
Redis задаёт ограничение очереди подключения клиентов в параметре tcp-backlog (по-умолчанию 511).
При этом — операционна ясистема проверяет собственный лимит — net.core.somaxconn
, и если он меньше, чем лимит Redis — будет выдано предупреждение вида:
The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128
Что такое TCP backlog и net.core.somaxconn
Что бы понять значение tcp-backlog и роль net.core.somaxconn
— вспомним процесс установления сессии и начала передачи данных:
- сервер: приложение на сервере выполняет
listen()
, передавая вlisten()
первым аргументом файловый дескриптор сокета, а вторым — размер accept backlog (значениеtcp-backlog
изredis.conf
) - клиент: приложение клиента выполняет
connect()
и отправляет серверу SYN-пакет- на стороне клиента соединение переходит в состояние SYN_SENT
- на стороне сервера новое соединение переходит в состояние SYN_RCVD, и попадает в очередь syn backlog (
net.ipv4.tcp_max_syn_backlog
) — incomplete connection queue
- сервер: отправляет SYN+ACK
- клиент: отправляет ACK, и переводит соединение в ESTABLISHED
- сервер: принимет ACK, и переводит соединение в ESTABLISHED, перемещая его в accept backlog — complete connection queue
- сервер вызывает
accept()
, передавая ему соединение из очереди accept backlog - клиент: вызывает
write()
, и начинает передачу данных - север: вызывает
read()
, и получает данные
Собственно, если в listen()
Redis-а значение backlog передаётся больше, чем оно задано в лимитах ядра — net.core.somaxconn
— и вызывается сообещение «TCP backlog setting cannot be enforced«.
128 является значением по-умолчанию:
Задаём через -w
:
См. TCP connection backlog — a struggling server и TCP Three-Way Handshake.
vm.overcommit_memory
Наверно, самый неоднозначный параметр.
Крайне рекомендую посмотреть пост Redis: fork — Cannot allocate memory, Linux, виртуальная память и vm.overcommit_memory — про виртуальную память, системные вызовы и Redis.
См. также overcommit_memory
и См. Background saving fails with a fork() error under Linux even if I have a lot of free RAM.
overcommit_memory
играет роль при выполнении операций созданий снапшотов данных из памяти на диск, а конкретно — при вызове BGSAVE
.
В нашем случае, с отключенным RDB и AOF, когда Redis используется только для кеширования, и хранить данные на диске смысла нет — нет смысла и в изменении overcommit_memory
, и следует оставить его в значении по-умолчанию — 0.
А уж если хочется задать лимит вручную — то лучше использовать overcommit_memory
== 2, и ограничение по %, что бы всегда оставался запас памяти.
vm.swappiness
Если операционной системе разрешено использование SWAP — она может сдемпить часть данных Redis на диск, и когда Redis попробует их считать — это вызовет задержку, т.к. ему придётся ждать, пока система не считает данные с диска обратно в память.
Во избежание — отключаем SWAP вообще: