База данных Redis на основе памяти должна быть наиболее часто используемой базой данных «ключ-значение» в различных компаниях, занимающихся веб-разработкой.Мы часто используем ее в нашем бизнесе для хранения статуса входа пользователя (хранилище сеансов) для ускорения некоторых горячих запросов данных (по сравнению с mysql). , скорость была улучшена на порядки), выполняя простые очереди сообщений (LPUSH и BRPOP), системы публикации подписки (PUB/SUB) и т. д. В крупных интернет-компаниях обычно есть специальные команды, которые предоставляют хранилище Redis для различных деловых вызовов в виде базовых услуг.
Но для любого поставщика базовых услуг один вопрос, который задает звонящий: высокодоступна ли ваша услуга? Лучше не причинять вреда моему бизнесу, потому что ваши услуги часто идут не так, как надо. Недавно я также создал небольшой «высокодоступный» сервис Redis в своем проекте, и я сделаю здесь свое собственное резюме и размышления.
В первую очередь нам нужно определить, что представляет собой высокая доступность для сервисов Redis, то есть в случае различных исключений сервисы все же могут предоставляться в обычном режиме. Или, наоборот, в случае неисправности нормальная служба может быть восстановлена лишь через короткий промежуток времени. Так называемое исключение должно включать как минимум следующие возможности:
[Исключение 1] Процесс узла сервера внезапно выходит из строя (например, разработчик с отключенной рукой убивает процесс redis-server сервера)
[Исключение 2] Сервер узла не работает, что означает, что все процессы на этом узле остановлены (например, отключена определенная рука по эксплуатации и обслуживанию, отключено питание сервера; например, некоторые старые машины есть аппаратные сбои)
[Аномалия 3] Прервана связь между любыми двумя узловыми серверами (например, временный работник отключен, а оптический кабель, используемый для связи между двумя машинными залами, обрезан)
На самом деле любое из вышеперечисленных исключений является маловероятным событием, а основная идеология достижения высокой доступности заключается в том, что вероятность нескольких маловероятных событий, происходящих одновременно, можно игнорировать. Высокая доступность может быть достигнута до тех пор, пока система, которую мы проектируем, может выдерживать единую точку отказа в течение короткого периода времени.
Для создания высокодоступных сервисов Redis в Интернете есть множество решений, таких как Keepalived, Codis, Twemproxy и Redis Sentinel. Среди них Codis и Twemproxy в основном используются в крупномасштабных кластерах Redis, а также являются решениями с открытым исходным кодом, предоставляемыми Twitter и Wandoujia до того, как Redis официально выпустила Redis Sentinel. Объем данных в моем бизнесе невелик, поэтому выполнение кластерных услуг — пустая трата машин. В итоге был сделан выбор между Keepalived и Redis Sentinel, и было выбрано официальное решение Redis Sentinel.
Redis Sentinel можно понимать как процесс, который отслеживает, нормально ли работает служба Redis Server, и при обнаружении неисправности резервный (подчиненный) сервер Redis может быть автоматически включен, чтобы внешние пользователи не знали об аномалии, происходящей внутри Redis. оказание услуг. Мы следуем шагам от простого к сложному, чтобы создать минимальную высокодоступную службу Redis.
Вариант 1: автономный сервер Redis без Sentinel
В обычных обстоятельствах, когда мы создаем личный веб-сайт или обычно занимаемся разработкой, мы запускаем один экземпляр Redis Server. Вызывающий может напрямую подключиться к службе Redis, даже если клиент и Redis находятся на одном сервере. Эта комбинация подходит только для личного обучения и развлечения, ведь такая конфигурация всегда будет иметь единую точку отказа, которую невозможно решить. Когда процесс службы Redis зависает или сервер 1 выходит из строя, служба становится недоступной. И если сохранение данных Redis не настроено, данные, уже хранящиеся в Redis, также будут потеряны.
Вариант 2: синхронизация ведущий-ведомый сервер Redis, один экземпляр Sentinel
Для достижения высокой доступности и проблемы единой точки отказа, описанной в Решении 1, мы должны добавить службу резервного копирования, то есть запустить процесс Redis Server на каждом из двух серверов.Как правило, мастер предоставляет службу, а слейв отвечает только за синхронизацию.и бекап. В то же время запускается дополнительный процесс Sentinel для мониторинга доступности двух экземпляров Redis Server, чтобы, когда мастер умирает, подчиненный мог быть повышен до роли мастера вовремя, чтобы продолжать предоставлять услуги, тем самым реализуя высокая доступность сервера Redis. Это основано на принципах проектирования службы высокой доступности, то есть единичная точка отказа сама по себе является событием с небольшой вероятностью, и несколько одноточечных сбоев одновременно (то есть главный и подчиненный зависают одновременно). ) можно рассматривать как (в основном) невозможные события.
Для вызывающей стороны службы Redis теперь необходимо подключиться к службе Redis Sentinel, а не к серверу Redis. Обычный процесс вызова заключается в том, что клиент сначала подключается к Redis Sentinel и спрашивает, какая служба является главной, а какая подчиненной на текущем сервере Redis, а затем подключается к соответствующему серверу Redis для работы. Конечно, текущие сторонние библиотеки обычно реализуют этот процесс вызова, и нам больше не нужно реализовывать его вручную (например, ioredis для Nodejs, predis для PHP, go-redis/redis для Golang, jedis для JAVA и т. д.).
Однако после того, как мы внедрили переключатель master-slave службы Redis Server, появилась новая проблема, то есть сам Redis Sentinel также является одноточечной службой: после зависания процесса Sentinel клиент не может подключиться к Sentinel. Следовательно, конфигурация схемы 2 не может обеспечить высокую доступность.
Вариант 3: Синхронизация Master-Slave Redis Server, Sentinel с двумя экземплярами
Чтобы решить проблему решения 2, мы также запускаем дополнительную копию процесса Redis Sentinel, и два процесса Sentinel предоставляют клиенту функцию обнаружения службы одновременно. Клиент может подключиться к любой службе Redis Sentinel, чтобы получить основную информацию о текущем экземпляре Redis Server. При нормальных обстоятельствах мы настроим несколько адресов ссылок Redis Sentinel на стороне клиента. Как только клиент обнаружит, что определенный адрес не может быть подключен, он попытается подключиться к другим экземплярам Sentinel. Конечно, это не требует от нас реализации вручную В каждом языке разработки более популярные библиотеки соединений Redis помогли нам реализовать эту функцию. Мы ожидаем, что даже если один из Redis Страж умирает, и остается служить другому Стражу.
Однако видение прекрасно, а реальность жестока. При такой архитектуре по-прежнему невозможно добиться высокой доступности сервисов Redis. На схематической диаграмме схемы 3 часть красной линии представляет собой связь между двумя серверами, а ненормальный сценарий, который мы предполагаем ([аномалия 2]), заключается в том, что сервер в целом не работает. Можно предположить, что сервер 1 не работает. В настоящее время только оставшийся Redis Sentinel и подчиненный Redis Server обрабатывают на сервере 2. В настоящее время Sentinel фактически не переключит оставшееся подчиненное устройство на главное для продолжения службы, что сделает службу Redis недоступной, поскольку настройка Redis такова, что только тогда, когда более 50% процессов Sentinel могут подключиться и проголосовать за новый master Когда действительно происходит переключение ведущий-ведомый. В данном примере может быть подключен только один из двух Sentinel, что равно 50% и не находится в сцене, где возможно переключение master-slave.
Вы можете спросить, почему в Redis есть настройка 50%? Предполагая, что мы разрешаем меньше или равно 50% подключений Sentinel, также может быть выполнено переключение ведущий-ведомый. Представьте себе [Исключение 3], то есть сеть между сервером 1 и сервером 2 прервана, но сам сервер работает. Как показано ниже:
Фактически, для сервера 2 прямое отключение сервера 1 имеет тот же эффект, что и отказ сервера 1 подключиться к сети.В любом случае, он внезапно теряет возможность осуществлять какую-либо связь. Предположим, мы позволяем Sentinel сервера 2 переключать ведомое устройство на ведущее, когда сеть прерывается.В результате теперь у вас есть два сервера Redis, которые могут предоставлять услуги внешнему миру. Любые добавления, удаления и модификации, выполненные Клиентом, могут приходиться на Redis на Сервере 1 или на Redis на Сервере 2 (в зависимости от того, к какому Sentinel подключен Клиент), что приводит к путанице данных. Даже если сеть между сервером 1 и сервером 2 будет восстановлена позже, мы не сможем унифицировать данные (две разные данные, кому нам доверять?), и целостность данных будет полностью нарушена.
Вариант 4: Синхронизация Master-Slave Redis Server, три экземпляра Sentinel
Учитывая, что в решении 3 невозможно добиться высокой доступности, нашей окончательной версией является решение 4, как показано на рисунке выше. Это на самом деле архитектура, которую мы в итоге построили. Мы представили сервер 3 и создали процесс Redis Sentinel поверх 3. Теперь три процесса Sentinel управляют двумя экземплярами Redis Server. В этом сценарии, будь то сбой одного процесса, сбой одного компьютера или сбой сетевого соединения между двумя компьютерами, службы Redis могут по-прежнему предоставляться извне.
На самом деле, если ваша машина относительно простаивает, конечно, вы также можете открыть Redis Server на сервере 3, чтобы сформировать архитектуру 1 master + 2 slave.Каждые данные имеют две резервные копии, и доступность будет улучшена. Конечно, дело не в том, что чем больше ведомых, тем лучше, ведь синхронизация master-slave тоже требует времени.
В сценарии 4, как только связь между сервером 1 и другими серверами будет полностью прервана, серверы 2 и 3 переключат ведомые устройства на ведущие. Для клиента в этот момент будет обслуживаться 2 мастера, и после восстановления сети все новые данные, которые попали на сервер 1 во время сбоя, будут потеряны. Если вы хотите частично решить эту проблему, вы можете настроить процесс Redis Server для немедленной остановки службы при обнаружении проблемы с собственной сетью, чтобы избежать поступления новых данных во время сбоя сети (см. Redis min-slaves-to - напишите и min-slaves-max-lag эти два элемента конфигурации).
На данный момент мы создали высокодоступный сервис Redis с 3 машинами. На самом деле, в Интернете существует более экономичный способ: поместить процесс Sentinel на клиентский компьютер, а не на компьютер поставщика услуг. Просто в компании провайдер и звонящий по общим услугам не из одной команды. Две команды работают вместе на одной машине, и из-за проблем со связью легко вызвать какие-то неверные операции, поэтому для этого человеческого фактора мы все же принимаем архитектуру схемы 4. А так как на сервере 3 работает только один процесс Sentinel, он не потребляет много ресурсов сервера, а сервер 3 также можно использовать для запуска некоторых других служб.
Простота использования: используйте Redis Sentinel так же, как и автономную версию Redis.
Как поставщики услуг, мы всегда говорим о пользовательском опыте. В приведенных выше решениях всегда есть место, где клиентской стороне не так комфортно. Для автономной версии Redis клиентская сторона напрямую подключается к серверу Redis, нам нужно только указать IP и порт, и клиент может использовать наш сервис. После перехода в режим Sentinel Клиент должен принять некоторые внешние пакеты зависимостей, поддерживающие режим Sentinel, а также изменить собственную конфигурацию подключения к Redis, что явно неприемлемо для «хайповых» пользователей. Есть ли способ предоставлять услуги, предоставляя клиенту только фиксированный IP-адрес и порт, как при использовании автономной версии Redis?
Ответ, конечно, да. Для этого может потребоваться введение виртуального IP (Virtual IP, VIP), как показано на рисунке выше. Мы можем указать виртуальный IP-адрес на сервер, на котором находится мастер Redis Server.Когда произойдет переключение Redis master-slave, будет запущен сценарий обратного вызова, и VIP будет переключен на сервер, где находится подчиненный сервер в обратном вызове. сценарий. Таким образом, со стороны клиента кажется, что он все еще использует автономную версию высокодоступного сервиса Redis.
Эпилог
Создать любой сервис и сделать его «пригодным для использования» на самом деле очень просто, точно так же, как мы запускаем автономную версию Redis. Но как только должна быть достигнута «высокая доступность», все становится сложнее. В бизнесе используются два дополнительных сервера, 3 процесса Sentinel + 1 подчиненный процесс, просто чтобы гарантировать, что служба по-прежнему доступна в этой маловероятной аварии. В реальном бизнесе мы также включаем супервизор для наблюдения за процессом: как только процесс неожиданно завершится, он автоматически попытается перезапуститься.