Может ли команда WAIT обеспечить строгую согласованность в Redis?

Привет, цветочки,

Можем ли мы в настройке Sentinel/кластера Redis использовать команду WAIT с общим количеством ведомых устройств, чтобы обеспечить строгую согласованность между серверами Redis? Почему нет?

С уважением


person geeko    schedule 10.11.2015    source источник


Ответы (1)


WAIT реализует синхронную репликацию для Redis. Синхронная репликация требуется, но недостаточна для достижения строгой согласованности. Сильная согласованность — это практически сумма двух вещей:

  1. Синхронная репликация на большинство узлов распределенной системы.
  2. Способ организовать смену лидера (в основном отказоустойчивость), чтобы гарантировать, что может быть избран только узел, сохраняющий полную историю подтвержденных операций в предыдущем лидере.

WAIT не предоставляет "2". Процесс репликации в Redis выполняется Sentinel или Redis Cluster и не может предоставить свойство 2 (поскольку синхронная репликация в Redis является исключением, а не правилом, поэтому этому аспекту не уделялось особого внимания). Однако репликация Redis пытается продвигать ведомое устройство, которое похоже, сохраняет наибольший объем данных. Хотя это не меняет теоретических гарантий аварийного переключения Redis, при котором все еще могут быть потеряны подтвержденные записи, это означает, что если вы используете WAIT, в памяти будет больше ведомых устройств, выполняющих данную операцию, и, в свою очередь, гораздо более вероятно, что в в случае аварийного переключения операция будет сохранена. Однако, несмотря на то, что это затруднит запуск режима сбоя, который отбрасывает подтвержденную операцию, всегда существует режим сбоя с такими свойствами.

TLDR: WAIT не делает Redis линеаризуемым, он гарантирует, что указанное количество ведомых устройств получит запись, что, в свою очередь, делает аварийное переключение более надежным, но без каких-либо жестких гарантий.

person antirez    schedule 10.11.2015
comment
Спасибо антирез за ответ. Я обязательно приму ваш ответ. Тем не менее, я имею в виду этот сценарий, и я хотел бы услышать ваши мысли по этому поводу. Я пытаюсь реализовать распределенные блокировки с помощью операции WAIT, чтобы в случае сбоя WAIT с какой-либо ошибкой блокировка не была получена, а вместо этого ключи блокировки будут немедленно удалены или в конечном итоге автоматически истекли. Другие клиенты просто не смогут получить неудачные блокировки, пока они не будут удалены/истечет срок их действия. Предполагая, что я занимался другими проблемами, такими как синхронизация, является ли это безопасным подходом? - person geeko; 11.11.2015
comment
Если вам нужны распределенные блокировки с жесткими гарантиями, у вас есть гораздо лучший способ сделать это! Алгоритм redlock представляет собой реализацию с использованием N разных мастеров, синхронной репликации, реализованной на стороне клиента, и доступен для несколько языков. Надеюсь, это поможет! - person antirez; 11.11.2015
comment
Спасибо антирез. В настоящее время я использую Redlocks. Тем не менее, я все равно хотел бы понять, безопасно ли мое предложение. В настоящее время наше решение не требует настройки с несколькими мастерами (за исключением случаев использования красных замков), и мы хотели бы изучить использование WAIT с настройкой с одним мастером и несколькими подчиненными, так как им проще управлять. - person geeko; 11.11.2015
comment
Я не думаю, что ваш алгоритм безопасен. Например, что происходит после аварийного переключения? Если вы выбираете ведомое устройство без заданной блокировки, даже если сама блокировка достигла других узлов N/2+1, SETNX в (новом) ведущем устройстве будет успешным, а также WAIT будет выполнено успешно, так как теперь другие экземпляры реплицируются из нового узла. мастер. Если вы не выполняете аварийное переключение, то вы можете просто использовать один экземпляр :-) Так как у вас все равно недоступная система во время сбоев. Кстати, управлять системой с несколькими мастерами ИМХО проще, поэтому я бы все равно выбрал redlock. - person antirez; 11.11.2015
comment
Спасибо за ваше время и усилия, чтобы ответить на мои вопросы. После отработки отказа все операции WAIT завершатся сбоем с ошибкой, из-за которой клиенты также не смогут получить блокировки. Следовательно, новые клиенты теперь могут безопасно получать одни и те же блокировки независимо от вновь выбранного мастера. Я ошибся? :) - person geeko; 11.11.2015
comment
Проблема в блокировках, уже предоставленных другим клиентам. Пример: ‹старый мастер› блокирует и записывает на N/2+1 серверов. ЗДЕСЬ ПРОИСХОДИТ FAILVER ‹new master› не было среди N/2+1 серверов, теперь все ведомые реплицируются с него, поэтому внутри Redis больше не существует старой блокировки. Однако клиент использует его. Однако ‹новый сервер› выдаст тот же самый pock другому клиенту: нарушение безопасности, игра окончена. - person antirez; 12.11.2015
comment
Я действительно ценю ваше терпение со мной :) Но команде WAIT можно задать параметр, который принудительно синхронизирует все подчиненные устройства и подтверждает синхронизацию до того, как WAIT будет считаться успешным. Таким образом, мы можем гарантировать, что все ведомые устройства имеют одинаковое представление о блокировках. Я что-то упустил здесь? - person geeko; 12.11.2015
comment
Да, как я уже сказал, вы не считаете, что после аварийного переключения вы можете выбрать ведомое устройство, которое не получило последнюю блокировку (или любую другую прошлую блокировку, все еще действующую с точки зрения клиента, получившего ее). - person antirez; 12.11.2015
comment
Но это невозможно, так как клиент ЖДЕТ, пока все подчиненные устройства (используя параметр количества подчиненных устройств, о котором я упоминал ранее) зарегистрируют блокировку до того, как клиент потребует блокировку, в противном случае клиент считает, что блокировка как не приобретенный. Не могли бы вы уточнить, как это может произойти в этом конкретном подходе? - person geeko; 13.11.2015
comment
Три сервера A, B, C. A является текущим мастером. Какой-то клиент получает блокировку L1, записывая в A и ОЖИДАЯ с коэффициентом репликации 2. Запись получена A и B, так как C в данный момент был отключен, или была задержка в канале репликации, или что-то еще. Тогда A выходит из строя, механизм аварийного переключения выбирает C в качестве ведомого, поскольку для временного сетевого раздела B был недоступен (а A все еще дает сбой). Теперь новым мастером является C, который не имеет представления о замке L1, B и A становятся рабами C, также теряя ключ L1, так что теперь L1 больше не существует. Новый клиент запрашивает L1 и получает его снова. НЕУДАЧА - person antirez; 13.11.2015
comment
Я несколько раз редактировал комментарий выше, пожалуйста, перезагрузите и перечитайте. - person antirez; 13.11.2015
comment
Вот мое понимание этого сценария. Клиент пытается получить L1, записывая на ведущее устройство A и ОЖИДАЯ, пока запись будет реплицирована на все подчиненные устройства B и C. Поскольку C в этот момент отключен, WAIT вернет 1 как количество подчиненных устройств. что подтвердил запись (а именно B). В это время клиент увидит, что не все ведомые устройства подтвердили запись, поэтому он не сможет получить блокировку. Любая подтвержденная запись теперь может быть отменена клиентом путем немедленного удаления или автоматически серверами через возможное истечение срока действия. Оба безопасны. - person geeko; 14.11.2015
comment
Как правило, любой неисправный сервер (ведущий или подчиненный) приведет к сбою блокировки, поскольку количество подтвержденных операций записи будет меньше 100%, что требуется для строгой согласованности между всеми серверами. Я надеюсь, что я не пропускаю очень очевидную вещь здесь :) - person geeko; 14.11.2015
comment
Да, вы что-то упустили (это нарушает доступность), но это обсуждение слишком длинное на данный момент :-) Я предлагаю прочитать несколько вводных статей о распределенных системах, подобных этой (совсем не идеально, но достойное начало): book.mixu.net/distsys/single-page.html, документ Raft и в целом, как достичь согласованности в реплицированном конечном автомате. Это предоставит вам некоторые POV и инструменты, чтобы легко найти проблемы, которые есть у вашей схемы, и почему требуется соглашение для решения этой проблемы в общем случае (если вы хотите использовать репликацию). - person antirez; 18.11.2015
comment
Redlock — это явно способ сделать проблему намного проще по сравнению с реплицированными конечными автоматами, используя тот факт, что нам нужны только определенные гарантии, чтобы распределенная блокировка имела определенные гарантии безопасности и доступности. Но для управления синхронной репликацией, необходимой для этого варианта использования, она реализована на стороне клиента, а не зависит от репликации Redis, разработанной по-другому. - person antirez; 18.11.2015
comment
Привет @antirez, что, если я подожду, пока весь кластер (1 главный и 2 подчиненных) получит записи, а затем только подтвержу клиент. Это сделает его строго последовательным? (Учитывая, что кластер не принимает записи, даже если одна из машин выходит из строя.) - person ptntialunrlsd; 14.12.2015
comment
Да, @ptntialunrlsd, полностью жертвуя доступностью любого рода во время сбоев, вы действительно в безопасности. Таким образом, ваши реплики не позволят пережить сбои, но сделают запись более безопасной, потому что вы можете запускать разные узлы в разных географических точках. Все это имеет смысл, если вы запускаете AOF в режиме fsync=always, иначе во время перезапуска каждая реплика может потерять записи, что сделает схему слабой. - person antirez; 15.12.2015
comment
Спасибо @antirez! Да, мой мастер будет писать AOF с fsync=always, а RDB будет отключен. 2 подчиненных устройства этого мастера не будут вести журналы. Будет ли это полностью безопасно (учитывая, что жесткий диск мастера никогда не выйдет из строя), или мне следует также записать RDB в один из ведомых устройств? (Хотя я не чувствую необходимости.) - person ptntialunrlsd; 16.12.2015
comment
@antirez, рассмотрите возможность объединения вашего последнего комментария со своим ответом, так как это очень важно. То есть следующие два условия гарантируют строгую согласованность (за счет доступности): 1. ЖДИТЕ, пока каждая реплика получит запись; 2. Каждая отдельная реплика использует сохраняемость AOF с fsync=always. - person Sergei Patiakin; 14.09.2016