В процессе настройки Redis в роли кеширующего сервиса для приложения — набросался такой вот пост.
Рассмотрим основные параметры конфигурации Redis, их значения, как они и на что они влияют, и на какие из них стоит обратить внимание.
Местами совсем кратко, но везде со ссылками.
Начать, пожалуй, стоит с утилиты redis-benchmark
.
Устанавливается вместе с сами Redis, можно сразу использовать:
[simterm]
root@bttrm-dev-app-1:/home/admin# redis-benchmark -p 6389 -n 1000 -c 10 -k 1 ====== 1 ====== 1000 requests completed in 0.03 seconds 10 parallel clients 3 bytes payload keep alive: 1 98.30% <= 1 milliseconds 99.30% <= 2 milliseconds 100.00% <= 2 milliseconds 30303.03 requests per second
[/simterm]
Кроме того — можно выполнить проверку кол-ва операций с помощью redis-cli
и опции --latency
или --latency-dist
:
Содержание
Redis server-level config
timeout
Отключать соединение при неактивности клиента заданное количество секунд.
Ноль для отключения возможности (IDLE-клиенты будут висеть до перезагрузки, или пока не отключатся сами):
... timeout 0 ...
В целом — есть смысл оставить дефолтные 300 секунд, что бы не оставались зависшие клиенты.
tcp-keepalive
Не влияет при PUBLISH/SUBSCRIBE (real-time operations), см. Redis Pub/Sub: Intro Guide и Redis Pub/Sub… How Does it Work?
Сервер отправляет ACK-запросы (Acknowledgment) через указанный промежуток времени в секундах, поддерживая сессию:
... tcp-keepalive 300 ...
[simterm]
127.0.0.1:6389> CONFIG GET tcp-keepalive 1) "tcp-keepalive" 2) "300"
[/simterm]
Значение по-умолчанию — 300 секунд (но зависит от версии).
Если клиент не отвечает на запрос — соединение закрывается.
Если и timeout
, и tcp-keepalive
на стороне сервера будут заданы в 0 (отключены) — то «мёртвые» подключения будут висеть до перезагрузки сервера.
См. Things that you may want to know about TCP Keepalives.
Проверяем с включенным tcp-keepalive
(-k
== 1):
[simterm]
root@bttrm-dev-app-1:/home/admin# redis-benchmark -p 6389 -n 1000 -c 10 -k 1 -q | tail -2 MSET (10 keys): 16129.03 requests per second
[/simterm]
И без:
[simterm]
root@bttrm-dev-app-1:/home/admin# redis-benchmark -p 6389 -n 1000 -c 10 -k 0 -q | tail -2 MSET (10 keys): 7042.25 requests per second
[/simterm]
Снова-таки — не вижу смысла в отключении проверки вообще, потому — оставляем дефолтные 300 секунд.
RDB Persistence
Создаёт полную копию базы. См. Redis Persistence.
Поведение определяется параметром save
(см. также Redis save, SAVE и BGSAVE).
Проверяем:
[simterm]
127.0.0.1:6379> CONFIG GET save 1) "save" 2) "3600 1 300 100 60 10000"
[/simterm]
Удаляем:
[simterm]
127.0.0.1:6379> CONFIG SET save "" OK 127.0.0.1:6379> CONFIG GET save 1) "save" 2) ""
[/simterm]
Сохраняем:
[simterm]
127.0.0.1:6389> CONFIG rewrite OK
[/simterm]
В случае, если Redis используется просто для кеширования — можно отключить: убираем save
из конфига вообще.
При этом сам механизм RDB будет использоваться для синхронизации мастер-слейв при использовании репликации (см. Redis: репликация, часть 1 — обзор. Replication vs Sharding. Sentinel vs Cluster. Топология Redis).
AOF persistence
Append Only File — сохраняет в лог каждую операцию.
Аналогично RDB, если Redis используем просто, как кеш — лог не нужен.
Для отключения — меняем параметр appendonly
, и задаём его в no:
... appendonly no ...
maxmemory
maxmemory
задаёт максимальный размер памяти сервера, который будет доступен Redis-у для хранения данных.
См. Using Redis as an LRU cache.
Может быть задан в виде %:
[simterm]
127.0.0.1:6389> CONFIG SET maxmemory 80 OK
[/simterm]
Или мегабайт/гигабайт:
[simterm]
127.0.0.1:6389> CONFIG SET maxmemory 1gb OK 127.0.0.1:6389> CONFIG GET maxmemory 1) "maxmemory" 2) "1073741824"
[/simterm]
Или в 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
:
[simterm]
127.0.0.1:6379> set test "test" OK 127.0.0.1:6379> ttl test (integer) -1 127.0.0.1:6379> pttl test (integer) -1 127.0.0.1:6379> EXPIRE test 10 (integer) 1 127.0.0.1:6379> ttl test (integer) 8 127.0.0.1:6379> ttl test (integer) 7 127.0.0.1:6379> ttl test (integer) 7
[/simterm]
В нашем случае — девелоперы не уверены, что expire
задаётся для всех ключей, а учитывая, что снова-таки — это просто сервис кеширования, данные из которого потерять не страшно — то задаём maxmemory-policy allkeys-lru
.
unixsocket
Если приложение и Redis работают на одном хосте — попробуйте использование сокета вместо TCP-порта.
Задаём:
... unixsocket /tmp/redis.sock unixsocketperm 755 ...
Может дать хороший прирост производительности, см. Tuning Redis for extra Magento performance.
Проверим с redis-benchmark
.
Создаём тестовый конфиг:
unixsocket /tmp/redis.sock unixsocketperm 775 port 0
Запускаем с сокетом:
[simterm]
root@bttrm-dev-console:/etc/redis-cluster# redis-server /etc/redis-cluster/test.conf
[simterm]
Проверяем:
[simterm]
root@bttrm-dev-console:/home/admin# redis-benchmark -s /tmp/redis.sock -n 1000 -c 100 -k 1 ... 90909.09 requests per second
[/simterm]
И через TCP-порт:
[simterm]
root@bttrm-dev-console:/home/admin# redis-benchmark -p 7777 -n 1000 -c 100 -k 1 ... 66666.67 requests per second
[/simterm]
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, но имеет смысл отключить вообще:
Проверить текущее значение можно:
[simterm]
root@bttrm-dev-app-1:/home/admin# cat /sys/kernel/mm/transparent_hugepage/enabled always [madvise] never
[/simterm]
Значение в скобках явлется текущим заданным значением, а данном случае — madvice.
madvice указывает на использование THP только в случае, если это явно запрошено приложением через вызов madvice()
.
Проверить состояние можно так:
[simterm]
root@bttrm-dev-app-1:/home/admin# grep HugePages /proc/meminfo AnonHugePages: 0 kB ShmemHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0
[/simterm]
maxclients
и fs.file-max
Задаёт максимальное количество одновременно подключенных клиентов.
Значение по умолчанию — 10.000, переопределяется через maxclients
, см. Maximum number of clients.
При этом Redis проверяет лимиты операционной системы на максимальное количество файловых дескрипторов — sysctl fs.file-max
глобально для ядра:
[simterm]
root@bttrm-dev-app-1:/home/admin# sysctl fs.file-max fs.file-max = 202080 root@bttrm-dev-app-1:/home/admin# cat /proc/sys/fs/file-max 202080
[/simterm]
И ulimit
для пользователя на каждый процесс:
[simterm]
root@bttrm-dev-app-1:/home/admin# ulimit -Sn 1024
[/simterm]
Для systemd-based систем можно задать лимит через systemd-юнит файл Redis с помощью LimitNOFILE
:
[simterm]
root@bttrm-dev-app-1:/home/admin# cat /etc/systemd/system/redis.service | grep LimitNOFILE LimitNOFILE=65535
[/simterm]
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 является значением по-умолчанию:
[simterm]
root@bttrm-dev-app-1:/home/admin# sysctl net.core.somaxconn net.core.somaxconn = 128
[/simterm]
Задаём через -w
:
[simterm]
root@bttrm-dev-console:/home/admin# sysctl -w net.core.somaxconn=65535 net.core.somaxconn = 65535 root@bttrm-dev-console:/home/admin# sysctl -p
[/simterm]
См. 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 вообще:
[simterm]
root@bttrm-dev-console:/home/admin# sysctl -w vm.swappiness=0
[/simterm]
Ссылки по теме
- redis.conf
- sentinel.conf
- 5 Tips for Running Redis over AWS
- Redis: I like you, but you’re crazy
- Redis Best Practices and Performance Tuning
- Learn Redis the hard way (in production)
- Optimizing Redis Usage For Caching
- Benchmarking the experimental Redis Multi-Threaded I/O
- Redis configuration for production
- Things that you may want to know about TCP Keepalives
- Redis Configuration Controls
- Understanding the Top 5 Redis Performance Metric
- Сollection of our notes to tweak redis
- Влияние Transparent Huge Pages на производительность системы
- Redis latency due to Transparent Huge Pages
- Transparent Hugepages: measuring the performance impact
- Disable Transparent Hugepages
- Running Redis in production (2014 год)
- Настройка Redis