English translation is not available yet. Showing Russian content.
Настроить Redis cluster с LFU eviction
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить Redis cluster с LFU eviction
1. Цель задачи
Научиться разворачивать Redis cluster и конфигурировать политику вытеснения LFU (Least Frequently Used). Провести A/B‑тест: сравнить hit rate и количество вытесненных ключей при политиках allkeys-lfu и allkeys-lru на синтетических данных с Zipf-распределением доступа. Зафиксировать преимущество LFU в сценариях с «горячими» и «холодными» ключами.
Ключевой результат Работающий Redis cluster с политикой allkeys-lfu, метрики A/B‑теста, показывающие hit rate LFU выше, чем LRU, минимум на 5%.
2. Исходные данные
Перед началом необходимо иметь:
| Что нужно | Откуда взять |
|---|---|
| Docker Engine 24+ и Docker Compose v2 | Установить с оф. сайта или через пакетный менеджер |
| Redis 7.2+ образ (официальный) | docker pull redis:7.2 |
| Python 3.10+ | Установить или использовать conda/venv |
Библиотека redis-py | pip install redis |
| Библиотеки для анализа: pandas, matplotlib | pip install pandas matplotlib |
| Инструмент для генерации данных (Python скрипт) | Создать в рамках задачи (этап 2) |
Если нет реального кластера — симулируем:
- Локальный Redis cluster в Docker
- Генерация нагрузки
- Вместо redis-benchmark (не поддерживает точный контроль паттернов) пишем Python-скрипт с redis-py, который имитирует чтение/запись с Zipf-распределением ключей.
- Сбор метрик
- Используем redis-cli INFO stats или Python-клиент для получения keyspace_hits, keyspace_misses, evicted_keys.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Redis cluster | Redis 7.2, Docker, docker-compose | Запуск распределённого кэша |
| Генерация нагрузки | Python 3.10+, redis-py, numpy, matplotlib | Создание данных, выполнение запросов, сбор статистики |
| Мониторинг | redis-cli, Redis INFO, pandas | Сбор и обработка метрик производительности |
| Визуализация | matplotlib / seaborn | Графики hit rate, evictions |
4. Этапы выполнения
Этап 1: Развёртывание Redis cluster (45 минут)
Действия
-
Создать docker-compose.yml с 6 сервисами (redis-1..redis-6):
- Каждый сервис использует образ redis:7.2.
- Пробросить порты
7001-7006на хосте. - В каждом контейнере указать конфигурацию через volume: redis.conf с настройками кластера.
Пример конфигурационного файла
redis-cluster.conf:port 7001 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes maxmemory 256mb maxmemory-policy allkeys-lru # на старте LRU(для теста LFU будем менять политику позже через CONFIG SET).
-
Запустить кластер
docker-compose up -d -
Создать кластер с помощью redis-cli
docker exec -it redis-1 redis-cli --cluster create \ 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \ 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \ --cluster-replicas 1 -
Проверить состояние
docker exec -it redis-1 redis-cli -p 7001 cluster info docker exec -it redis-1 redis-cli -p 7001 cluster nodes
Ожидаемый результат этапа 6 Docker-контейнеров работают, кластер в статусе ok, все слоты покрыты.
Этап 2: Генерация тестовых данных с Zipf-распределением (30 минут)
Действия
-
Написать Python-скрипт
generate_data.py- Подключается к кластеру через redis.RedisCluster(startup_nodes=[{"host":"localhost","port":7001}]).
- Создаёт 100 000 ключей вида
key_000001…key_100000. - Распределение доступа (частоты чтения) подчиняется закону Zipf:
P(key_i) ∝ 1/(i^s), гдеs ≈ 1.2. - Для каждого ключа генерируем значение (например,
value_<номер>) и записываем черезSET. - Важно: все ключи должны иметь одинаковый размер (например, 256 байт), чтобы не влиять на политику вытеснения.
Пример фрагмента:
import numpy as np from redis.cluster import RedisCluster rc = RedisCluster(startup_nodes=[{"host":"localhost","port":7001}]) n_keys = 100_000 # Zipf распределение: вероятность обращения к i-му ключу ~ 1/(i**1.2) zipf_probs = np.random.zipf(1.2, n_keys) # Нормализация для выбора индекса keys = [f"key_{i:06d}" for i in range(1, n_keys+1)] # Заполнение for idx, key in enumerate(keys): rc.set(key, f"value_{idx:06d}" * 4) # ~256 байт -
Запланировать профиль доступа
-
Сохранить список операций в файл workload.csv (ключ и флаг "get").
Ожидаемый результат этапа Кластер заполнен 100 000 ключами, сгенерирован файл с нагрузкой.
Этап 3: A/B тест — LRU vs LFU (1 час)
Действия
-
Тест LRU
- Убедиться, что политика allkeys-lru (уже установлена по умолчанию на этапе 1).
- Запустить скрипт
run_workload.py, который считывает workload.csv и выполняет все GET-запросы к кластеру. - Скрипт должен собирать метрики до и после прогона:
before = rc.info("stats") # выполнить нагрузку after = rc.info("stats") hits_lru = after["keyspace_hits"] - before["keyspace_hits"] misses_lru = after["keyspace_misses"] - before["keyspace_misses"] evicted_lru = after["evicted_keys"] - before["evicted_keys"] hit_rate_lru = hits_lru / (hits_lru + misses_lru) * 100 - Записать результаты в CSV.
-
Сброс состояния кластера
- Очистить все данные: FLUSHALL на одном из мастеров (реплицируется на все шарды).
- Перезаполнить кластер снова из
generate_data.py(чтобы начальные условия были идентичны).
-
Настройка политики LFU
- На каждом мастере выполнить:
Повторить для портов 7002, 7003 (или использовать --cluster call).docker exec -it redis-1 redis-cli -p 7001 CONFIG SET maxmemory-policy allkeys-lfu - Проверить: CONFIG GET maxmemory-policy на всех мастерах.
- На каждом мастере выполнить:
-
Тест LFU
- Запустить тот же
run_workload.py(тот же workload.csv, тот же порядок операций). - Собрать метрики:
hits_lfu,misses_lfu,evicted_lfu,hit_rate_lfu.
- Запустить тот же
Ожидаемый результат этапа Два CSV-файла (или один сводный) с метриками для LRU и LFU.
Этап 4: Анализ результатов и построение графиков (30 минут)
Действия
-
Написать скрипт
analyze.py -
Выводы
Ожидаемый результат этапа Файл с графиком (comparison.png) и сводная таблица в stdout или текстовом файле.
Этап 5: Фиксация конфигурации и документация (15 минут)
Действия
-
Сохранить итоговую конфигурацию кластера
- Экспортировать
nodes.confиз одной из нод (можно черезredis-cli --cluster backup, но проще — сохранить файл из контейнера). - Записать в
final-redis.confвсе параметры, включаяmaxmemory-policy allkeys-lfu.
- Экспортировать
-
Написать краткий отчёт
REPORT.mdсо структурой:- Цель
- Методика (паттерн Zipf, параметры кластера)
- Результаты (таблица hit rate, evictions)
- График
- Выводы
Ожидаемый результат этапа Файлы: docker-compose.yml, generate_data.py, run_workload.py, analyze.py, comparison.png, REPORT.md.
5. Критерии приемки (Definition of Done)
- Redis cluster из 3 мастеров + 3 реплик успешно поднят и отвечает на клиентские запросы.
- Политика вытеснения
allkeys-lfuприменена на всех мастерах. - Выполнен прогон нагрузки с одинаковыми условиями для LRU и LFU.
- Метрики
keyspace_hits,keyspace_misses,evicted_keysзафиксированы до и после каждого прогона. - Hit rate при LFU превышает hit rate при LRU не менее чем на 5%.
- Построен график сравнения hit rate.
- Создан отчёт
REPORT.mdс описанием задачи, конфигурации и результатов.
6. Ожидаемый результат
Конечные артефакты
docker-compose.yml— конфигурация для запуска кластера.generate_data.py— скрипт генерации данных с Zipf-распределением.run_workload.py— скрипт нагрузочного тестирования (сбор метрик).analyze.py— скрипт анализа и построения графика.comparison.png— график сравнения hit rate LRU vs LFU.REPORT.md— отчёт с выводами.
Содержание отчёта
# A/B тест: LFU vs LRU в Redis cluster
## Конфигурация
- 3 мастера, 3 реплики, maxmemory 256MB
- Ключей: 100 000, значение ~256 Б
- Нагрузка: 500 000 GET с Zipf(1.2)
## Результаты
| Политика | Hit rate | Evicted keys |
|----------|----------|--------------|
| allkeys-lru | 78.3% | 45 000 |
| allkeys-lfu | 85.1% | 42 000 |
Дополнительно (опционально):
- Скрипт для автоматического развёртывания кластера с одной командой (
make deploy). - Dockerfile для образа с предустановленными зависимостями.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
Кластер не создаётся — ошибка ERR Invalid node address | Убедиться, что в docker-compose.yml используются внутренние IP (или 127.0.0.1 на хосте). Для redis-cli --cluster create нужно указывать адреса, доступные внутри сети Docker. Использовать имена контейнеров (например, redis-1:7001). |
| maxmemory не достигается — вытеснения не происходят | Уменьшить maxmemory до 128 MB или меньше, или увеличить количество данных (200 000 ключей). |
| Политика LFU не срабатывает, как ожидалось | Проверить, что используется Redis 7.2+ (в ранних версиях LFU был экспериментальным). Для allkeys-lfu должен работать все ключи. |
| Hit rate LFU не выше LRU | Возможно, паттерн доступа слишком «случайный» — уменьшить skew параметр Zipf (сделать s больше, например, 1.5). Убедиться, что workload одинаков для обоих тестов. |
Redis-py с кластером падает с MovedError | Использовать RedisCluster из redis.cluster, а не стандартный StrictRedis. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Развёртывание Redis cluster | 45 мин |
| Этап 2: Генерация тестовых данных | 30 мин |
| Этап 3: A/B тест (LRU + LFU) | 1 час |
| Этап 4: Анализ и графики | 30 мин |
| Этап 5: Документация | 15 мин |
| Итого | 3 часа |
Примечание При первом выполнении заложите дополнительно 30–60 мин на отладку Docker-сети и понимание принципов Redis cluster.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 101 | Как настроить политику вытеснения в Redis? |
| 205 | Разница между LRU и LFU |
| 312 | Как собрать метрики Redis через INFO? |
| 408 | Docker Compose для Redis cluster |
| 555 | Нагрузочное тестирование Redis (redis-benchmark vs custom) |
| 620 | Что такое Zipf distribution и зачем оно нужно? |
| 701 | Redis cluster vs standalone: плюсы и минусы |
| 810 | Как работает approximate LFU в Redis? |
| 888 | A/B тестирование в инфраструктуре |
| 250 | Настройка maxmemory в Redis |
10. Чек-лист самопроверки
- Я развернул Redis cluster из 3 мастеров и 3 реплик в Docker.
- Я настроил maxmemory и политику
allkeys-lfuна всех мастерах. - Я сгенерировал 100 000 ключей с Zipf-распределением и подготовил идентичный workload.
- Я провёл нагрузочный тест сначала с
allkeys-lru, затем (после сброса и перезаполнения) сallkeys-lfu. - Я зафиксировал метрики
keyspace_hits,keyspace_misses,evicted_keysдо и после каждого прогона. - Я сравнил hit rate и убедился, что LFU показал результат выше хотя бы на 5%.
- Я построил график сравнения и сохранил его.
- Я написал отчёт
REPORT.mdс описанием конфигурации и выводами.