Протокол консенсуса RAFT - должны ли записи быть устойчивыми перед фиксацией

У меня есть следующий вопрос о реализации RAFT:

Рассмотрим следующий сценарий \ реализацию:

  1. Лидер RAFT получает ввод команды, он добавляет запись к массиву в памяти, а затем отправляет записи последователям (с тактовым импульсом)
  2. Последователи получают запись и добавляют ее в свой массив в памяти, а затем отправляют ответ, что он получил запись.
  3. Затем лидер фиксирует запись, записывая ее в долговременное хранилище (файл). Лидер отправляет последний индекс фиксации в тактовом импульсе.
  4. Затем последователи фиксируют записи на основе индекса фиксации лидера, сохраняя запись в своем долговременном хранилище (файле).

Одна из реализаций RAFT (ссылка: https://github.com/peterbourgon/raft/) похоже, реализует это таким образом. Я хотел подтвердить, хорошо ли это.

Можно ли, если записи хранятся «в памяти» лидером и последователями до тех пор, пока они не будут зафиксированы? При каких обстоятельствах этот сценарий может потерпеть неудачу?


person coder_bro    schedule 29.04.2014    source источник


Ответы (3)


Я не согласен с принятым ответом.

  1. Диск не является мистически прочным. Если предположить, что диск является локальным по отношению к серверу, он может выйти из строя. Очевидно, что запись на диск от этого не спасает. Репликация - это надежность при условии, что реплики находятся в разных доменах отказа, что, если вы серьезно относитесь к долговечности, так и будет. Конечно, есть много опасностей для процесса, от которого не страдают диски (linux oom убит, oom в целом, мощность и т. Д.), Но выделенный процесс на выделенной машине может работать довольно хорошо. Особенно, если хранилище журналов, скажем, ramfs, поэтому перезапуск процесса не является проблемой.

  2. Если хранилище журнала потеряно, идентификация хоста также должна быть потеряна. A, B, C определяют журналы. Новый журнал, новый идентификатор. B «повторное присоединение» после (потенциальной) потери памяти - это просто ошибочная реализация. Новый процесс не может претендовать на идентичность B, потому что он не может быть уверен, что у него есть вся информация, которая была у B. Точно так же, как в случае постоянной очистки на диск, если мы заменили диск на машине, на которой размещен B, мы не могли просто перезапустить процесс, настроив его на идентификацию B. Это было бы чепухой. Он должен перезапуститься как D в обоих случаях, а затем попросить присоединиться к кластеру. В этот момент проблема потери зафиксированных записей исчезает в клубах дыма.

person benjumanji    schedule 07.11.2018

Я нашел ответ на вопрос, разместив сообщение в группе raft-dev google. Я добавил ответ для справки.

Ссылка: https://groups.google.com/forum/#!msg/raft-dev/_lav2NeiypQ/1QbUB52fkggJ

Цитируя ответ Диего:

В целях безопасности даже в условиях коррелированных перебоев в подаче электроэнергии большинству серверов необходимо сохранять запись в журнале, прежде чем ее последствия будут перенесены во внешний вид. Любое меньшее число, чем большинство, и эти серверы могут навсегда выйти из строя, что приведет к потере / повреждению данных.

Цитата из ответа Бена Джонсона на мое электронное письмо по этому поводу:

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

Например, предположим, что у вас есть кластер узлов под названием A, B и C, где A - лидер.

  1. Узел A реплицирует запись на узел B.

  2. Узел B хранит запись в памяти и отвечает узлу A.

  3. Узел A теперь имеет кворум и фиксирует запись.

  4. Затем узел A отделяется от узлов B и C.

  5. Затем узел B умирает и теряет копию записи в памяти.

  6. Узел B возвращается.

  7. Когда узлы B и C затем выбирают лидера, в их журнале не будет записи о «совершенных».

  8. Когда узел A снова присоединяется к кластеру, у него будет несогласованный журнал. Запись будет зафиксирована и применена к конечному автомату, поэтому ее нельзя будет откатить.

Бен

person coder_bro    schedule 29.04.2014
comment
Я считаю, что на шаге 6 узел B должен прочитать кворум машины для последнего зафиксированного индекса перед присоединением. Но это невозможно, поскольку узел A все еще разделен. Итак, что должно случиться, так это то, что узел B должен оставаться в режиме ожидания до тех пор, пока узел A не присоединится, тогда узел B будет читать последний зафиксированный индекс от узла A. Другой вариант - если на шаге 4 один из B или C станет лидером, ему потребуется 2 голосов, и, таким образом, последняя зафиксированная запись будет храниться на обоих узлах (B и C) - person skyde; 12.04.2016

Я думаю, что записи должны быть долговечными до совершения.

В качестве примера возьмем рисунок 8 (e) расширенного документа Raft. Если записи устойчивы при фиксации, то:

  1. S1 реплицирует 4 на S2 и S3, затем фиксирует 2 и 4.
  2. Все серверы вылетают. Поскольку S2 и S3 не знают, что S1 совершил 2 и 4, они не зафиксируют 2 и 4. Следовательно, S1 совершил 1,2,4, S2, S3, S4, S5 зафиксировал 1.
  3. Все серверы перезагружаются, кроме S1.
  4. Поскольку долговечными являются только зафиксированные записи, S2, S3, S4, S5 имеют одну и ту же единственную запись: 1.
  5. S2 избран лидером.
  6. S2 реплицирует новую запись на все остальные серверы, кроме сбойного S1.
  7. S1 перезапускается. Поскольку записи S2 новее, чем S1, поэтому записи 2 и 4 в S1 заменяются предыдущей новой записью.

В результате зафиксированные записи 2 и 4 теряются. Поэтому я думаю, что незафиксированные записи также должны быть долговечными.

person jl0x61    schedule 26.05.2019
comment
Не совсем. В случае реализации только памяти сбои процесса являются постоянными сбоями, требующими новых идентификаторов для присоединения к кластеру. Если вы убьете все серверы одновременно, вы нарушите условие N = 2f - 1, и ваш кластер станет тостовым. Процессы, сохраняющие свои идентификаторы, но не свои журналы, глючат, будь то отдельный локальный диск, массив рейдов, в памяти процесса, tmpfs, массив SAN или что-то еще. - person benjumanji; 22.07.2019