Раздел 37 · Redis с нуля

Redis Cluster: шардирование

junior~25 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке реплики спасали нас от падения сервера. Но каждая реплика хранит те же самые данные. Если магазину нужно 200 ГБ кэша, а у машины 64 ГБ памяти, реплики не помогут. Данные придётся разделить между несколькими серверами. Это шардирование, и в Redis его делает Redis Cluster.

Библиотека с залами

Представь библиотеку, где 16384 пронумерованные полки, а залов три. Первый зал держит полки с 0 по 5460, второй с 5461 по 10922, третий остальные. Номер полки для книги не выбирают: его вычисляют по названию одной и той же формулой. Ты приходишь в любой зал и спрашиваешь книгу. Если её полка в другом зале, библиотекарь не бежит туда сам, а говорит: «Тебе в третий зал». Умный читатель запоминает, какие полки где, и в следующий раз идёт сразу куда надо.

Redis Cluster устроен так же. Полки это 16384 слота, залы это основные узлы. Номер слота считается из имени ключа: от него берут контрольную сумму CRC16 и остаток от деления на 16384. Команда CLUSTER KEYSLOT покажет результат:

127.0.0.1:7000> CLUSTER KEYSLOT book:1
(integer) 759
127.0.0.1:7000> CLUSTER KEYSLOT book:2
(integer) 12948
127.0.0.1:7000> CLUSTER KEYSLOT user:7:cart
(integer) 5538
127.0.0.1:7000> CLUSTER KEYSLOT user:7:sessions
(integer) 8850

Соседние по смыслу ключи легко разлетаются по разным слотам, а значит, и по разным узлам. Это сделано нарочно: так ключи распределяются ровно. Но, как увидим, у этого есть цена.

Кластер из шести контейнеров

Минимальный разумный кластер это три основных узла и по реплике на каждый. Поднимаем шесть контейнеров с фиксированными адресами и включённым режимом кластера:

docker network create --subnet 10.0.7.0/24 cluster-net
for i in 0 1 2 3 4 5; do
  docker run -d --name redis-c$i --network cluster-net --ip 10.0.7.1$i redis:7 \
    redis-server --port 700$i --cluster-enabled yes --cluster-node-timeout 5000
done
docker exec redis-c0 redis-cli --cluster create \
  10.0.7.10:7000 10.0.7.11:7001 10.0.7.12:7002 \
  10.0.7.13:7003 10.0.7.14:7004 10.0.7.15:7005 \
  --cluster-replicas 1 --cluster-yes

--cluster-replicas 1 просит дать каждому основному узлу одну реплику. Утилита сама делит слоты и печатает план:

M: 71200652df4645f0de239a2fcc0cfa7495b5c6dc 10.0.7.10:7000
   slots:[0-5460] (5461 slots) master
M: 095a9fa5084becb38aeeb97d8ece0d747f191772 10.0.7.11:7001
   slots:[5461-10922] (5462 slots) master
M: 1229fb0ed3ed9ecf2280244e558c372472999259 10.0.7.12:7002
   slots:[10923-16383] (5461 slots) master
S: 7011800994ab08ad92f1e8ea14121370d0830d0a 10.0.7.13:7003
   replicates 1229fb0ed3ed9ecf2280244e558c372472999259
S: cf36a74f3a09d6baf8c9606980d68046a35b4658 10.0.7.14:7004
   replicates 71200652df4645f0de239a2fcc0cfa7495b5c6dc
S: 793060ce0c118c5af90641a343c04df27149df94 10.0.7.15:7005
   replicates 095a9fa5084becb38aeeb97d8ece0d747f191772
...
[OK] All 16384 slots covered.

M это основные узлы со своими диапазонами слотов, S реплики, у каждой указано, кого она копирует. Общее состояние кластера:

127.0.0.1:7000> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
...

cluster_state:ok и все 16384 слота на месте. cluster_size:3 значит три основных узла.

MOVED: тебе в другой зал

Подключаемся к узлу 7000 обычным redis-cli и пишем ключ:

127.0.0.1:7000> SET book:1 "Master and Margarita"
OK
127.0.0.1:7000> SET book:2 Solaris
(error) MOVED 12948 10.0.7.12:7002

Слот 759 у этого узла, и запись прошла. А слот 12948 принадлежит узлу 7002, и узел ответил ошибкой MOVED: «слот 12948 живёт на 10.0.7.12:7002, иди туда». Сам узел запрос никуда не пересылает.

Флаг -c включает у redis-cli режим кластера: он сам ходит по адресу из MOVED.

127.0.0.1:7000> SET book:2 Solaris
-> Redirected to slot [12948] located at 10.0.7.12:7002
OK
10.0.7.12:7002> GET book:1
-> Redirected to slot [759] located at 10.0.7.10:7000
"Master and Margarita"

Обрати внимание, как меняется приглашение: redis-cli переходит на тот узел, куда его отправили. Библиотеки для приложений делают умнее: при подключении скачивают карту «слот → узел» и сразу отправляют каждую команду куда нужно. MOVED они получают, только если карта устарела, и тогда обновляют её.

урок из курса

Урок из курса «Redis с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.