Date

Redis Cluster

Начало

Стоит начать с того, что Redis - это, по сути, очень удобная штука. В двух словах, Redis - это персистентное key-value хранилище в памяти, со своим блэкджеком и куртизантками. Чаще всего его сравнивают с устаревшим Memcached, который не умеет делать почти ничего из того, что умеет делать Redis.

Преимущества Redis:

  • очень очень быстрая скорость доступа к данным. Это же мемчик.

  • смешанные типы данных, хеши. По одному ключу (ивент), мы можем сторить кучу инфы (юзер айди, тип ивента, время, токен, сессию). Это могут быть байты, килобайты, мегабайты данных.

  • дженерик TTL. Нам не нужно удалять то, что мы положили в Redis. Внутренний механизм сам удалит ключ, TTL которого пришел. Это невероятно удобно.

  • унарные операции, инкременты, декременты - все это отрабатывает не моментально, а просто невероятно моментально. Соответственно, в Redis удобно и легко реализовывать комплексные прогресс бары, ивенты, класть кастомные данные, которые изменяются с разных мест системы.

  • персистентность и бин-лог. Есть возможность периодически флашить все данные на диск, обеспечивая высокую доступность данных, и почти нивелируя их потерю.

 

Получается, что Redis - это такая "серебряная пуля", абсолютно для всех кейсов, подходов и практик? Ну, такое. Скорее нет, чем да.

 

Например, проблемы, которые очень очень мешают жить:

  • стенделон. По факту, на данный момент, дефолтная инсталляция Redis - это стенделон. Это значит, что если у нас есть Single point of Failure, то у нас невероятно плохая архитектура, т.к. в случае падения Redis - вся система перестанет работать.

  • флаш на диск. Это очень затратная операция, с высокой нагрузкой на IO, на мемчик. И ладно даже на железо - но наш сервис же невероятно тупит, ведь Redis должен зафиксировать все что у него там есть, и сделать большой Flush из быстрой памяти на медленный диск. В этот момент латенси на всех сервисах возрастает до секунд.

 

Вывод очевиден - Redis ускоряет продукт, ускоряет разработку, и его однозначно, нужно использовать, но ... есть проблемы.

 

Redis Cluster

Там же есть Redis Cluster! Скажете Вы, но я бы попросил не спешить. На самом деле, у Redis есть 2 типа кластеризации:

  • Redis Sentinel - для старых версий

  • Redis Cluster - для новых версий

Redis Sentinel - это очень примитивная штука, которая выстраивает древовидную структуру из Ваших стенделон редисок, и называет это кластером. Никакого шардинга, балансировки, ничего. И тем более, это работает для старых версий Redis, если не ошибаюсь, ниже 3.0.

Redis Cluster - это штука повеселее, тут уже есть шардинг, репликация, отказоустойчивость, мастера-слейвы, разные там штуки прикольные и все такое. Это уже однозначно похоже на нормальный кластер, но все равно юзать это таким, как оно есть - не получится.

Redis Cluster Fail

 

Почему это не работает

Для того, чтобы понять почему это не работает, нужно понять, как это работает внутри.

 

Во первых, сам процесс создания Redis Cluster из стенделон нод - это дикость и унижение, в том виде, в котором это есть сейчас. В нашем 2017 году все привыкли к дискаверингу, провижинингу и репорту типа "я все сделал, тут уже кластер, все ок!" - но реалии таковы, что в сорсах Redis есть скрипт, написанный на рубях, который занимается тем, что принимает как аргументы инстансы редиски, и потом соединяет их в кластер. Доверяете ли вы подобным штукам? Думаю да, доверяли, лет 100500 назад.

 

Окей, у нас есть кластер. Теперь немного теории: внутри кластера есть такие штуки, как hash slots. По сути, слот - это число, которое подразумевает набор данных, за которые ответственна конкретная нода кластера. Всего существует 16384 слота, которые равномерно делятся между всеми мастерами.

 

Кстати, о мастерах. По умолчанию Redis Cluster может состоять не менее чем из трех нод, и все это будут мастера. Соответсвенно, они поделят слоты между собой.

 

Второй нюанс использования кластера - это невероятная хрупкость. Например, у нас из кластера с 3 нодами отвалилась одна нода. Логичным решением было бы продолжить работать - у нас же есть 66,6% данных, но все совсем не радужно. В дефолтной конфигурации будет ответ 'CLUSTER IS DOWN' по запросу любого, даже живого ключа.

 

Если рассматривать кластер побольше, например из 6 нод (3 мастера и 3 слейва) - ситуация повторяется. Пока происходит автоматический промоутинг слейва в мастера после падения, ответ аналогичен - 'CLUSTER IS DOWN'. А это - секунды, хотя эта задержка зависит от количества данных в кластере.

 

Третья проблема - это клиенты. Точнее, коннекторы в апликейшнах. Если взять предыдущий кейс, когда у нас идет промоутинг кластера - все клиенты отвалятся с socket error, или connection timeout, или с чем-то похожим, потому что держат коннект ко всем мастерам в кластере. Это тоже нужно доделывать.

 

Четвертый, и один из самых неприятных, нюанс - это изменение набора команд. Стандартные команды, которые работают по вайлдкардам - не работают, и это не удивительно. Это нужно переделывать по всему проекту, учить апликейшн работать как со стенделоном так и с кластером. По факту - это самая длинная и затратная часть имплементации Redis Cluster.

 

Как заставить это работать

Первый нюанс с провижинингом мы исправить не в состоянии, разве что сделать LWRP для Chef, и провижинить это как-то более нормально. По сути, примерно так мы и сделали.

 

А вот второй и третий - это уже наша компетенция!

 

Исправить 'CLUSTER IS DOWN' при отсутствии части слотов очень легко и просто - достаточно добавить параметр конфигурации: cluster-require-full-coverage no

 

Проблему с клиентами, которые отваливаются можно решить, потратив немного времени. В нашем проекте используется 2 языка - PHP и Java, поэтому нам нужно было делать два раза одну и ту же работу. Общий алгоритм сводится к таким степам:

  1. Получаем на клиенте 'CLUSTER IS DOWN' - во время пересборки кластера

  2. Кетчим эту ошибку, сохраняем существующую нерабочую слотмапу.

  3. Ретраим конекшн, определенное количество раз, и ждем новую слотмапу.

  4. Когда слотмапа изменилась - вычитываем наше значение и радуемся.

 

Изменение слотмапы будет означать, что кластер перешел в рабочее состояние, и наши данные уже похвалит какой-то слейв, и он готов с ними работать.

 

Ни для кого не будет секретом, если я скажу, что в кластере с 6+ нод, смысла флашить данные на диск нети никакого. Соответственно, если отключить персистентность - все будет работать очень и очень быстро.

 

Baby

Результат

Что же получилось в результате?

  • Мы достигли отличных показателей TTFB (так как теперь не боимся хранить сессии в Redis).

  • У нас получился, наверное лучший в мире прогресс лоадер - там самая актуальная информация (актуальнее некуда!)

  • Мы не боимся за данные, которые кладем в Redis Cluster и спим спокойно.

  • SLA и User Experience намного улучшился из-за быстрой отзывчивости многих частей апликейшна

 

Вот такой интересный путь у нас получился.

 

А как Вы используете общедоступные инструменты?


Comments

comments powered by Disqus