Начало
Стоит начать с того, что 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 из стенделон нод - это дикость и унижение, в том виде, в котором это есть сейчас. В нашем 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, поэтому нам нужно было делать два раза одну и ту же работу. Общий алгоритм сводится к таким степам:
-
Получаем на клиенте 'CLUSTER IS DOWN' - во время пересборки кластера
-
Кетчим эту ошибку, сохраняем существующую нерабочую слотмапу.
-
Ретраим конекшн, определенное количество раз, и ждем новую слотмапу.
-
Когда слотмапа изменилась - вычитываем наше значение и радуемся.
Изменение слотмапы будет означать, что кластер перешел в рабочее состояние, и наши данные уже похвалит какой-то слейв, и он готов с ними работать.
Ни для кого не будет секретом, если я скажу, что в кластере с 6+ нод, смысла флашить данные на диск нети никакого. Соответственно, если отключить персистентность - все будет работать очень и очень быстро.
Результат
Что же получилось в результате?
-
Мы достигли отличных показателей TTFB (так как теперь не боимся хранить сессии в Redis).
-
У нас получился, наверное лучший в мире прогресс лоадер - там самая актуальная информация (актуальнее некуда!)
-
Мы не боимся за данные, которые кладем в Redis Cluster и спим спокойно.
-
SLA и User Experience намного улучшился из-за быстрой отзывчивости многих частей апликейшна
Вот такой интересный путь у нас получился.
А как Вы используете общедоступные инструменты?