В чем разница вертикального и горизонтального масштабирования Redis
Что проверяют
Понимаете ли вы, во что упирается Redis на одном узле и что именно даёт каждый способ масштабирования: более мощная машина, реплики, шардирование. Следом обычно спрашивают, как с этим работает клиент StackExchange.Redis и что сломается в коде при переходе на кластер.
Как отвечать
- вертикальное: больше памяти и быстрее процессор на том же узле. Команды Redis исполняет в одном основном потоке (I/O-потоки с версии 6 разгружают только сеть), поэтому лишние ядра почти не помогают, а упор чаще в объём памяти. Помните про
forkприBGSAVE: на запись снимка нужен запас памяти под copy-on-write; - реплики: копии основного узла, масштабируют чтение, но не запись. Репликация асинхронная, так что с реплики можно прочитать устаревшее значение, а при переключении потерять последние записи. Автоматический failover даёт Sentinel, он про доступность, а не про объём;
- Redis Cluster: горизонтальное шардирование по 16384 хеш-слотам, слот ключа считается как
CRC16(key) mod 16384. Каждый шард держит свою часть данных и свои реплики, слоты переносятся между узлами без остановки.
Цена кластера в ограничениях. Многоключевые команды, транзакции и Lua-скрипты работают только внутри одного слота, иначе ошибка CROSSSLOT. Лечится хеш-тегами: ключи {user:42}:cart и {user:42}:profile попадут в один слот. Доступна только база 0, SELECT не работает.
В C# ConnectionMultiplexer сам понимает топологию кластера и перенаправления MOVED, его создают один раз на приложение. Чтение с реплик включается флагом CommandFlags.PreferReplica.
Где спотыкаются
Считают, что реплики увеличивают ёмкость. Каждая реплика хранит полную копию данных, больше в неё не влезет.
Предлагают вертикальное масштабирование в духе «добавим ядер», не зная, что команды выполняются в одном потоке.
Переходят на кластер и получают CROSSSLOT на MGET и транзакциях, потому что ключи раскладывались без хеш-тегов.