Гарантии согласованности
Три настройки контролируют согласованность и долговечность в RethinkDB: подтверждения записей и долговечность на уровне таблицы, а также режим чтения запросов.
Настройки
-
Подтверждения записей устанавливаются на уровне таблицы с помощью настройки
write_acks, либо с помощью команды config, либо записью вtable_configсистемную таблицу. По умолчанию значениеmajority, что означает, что записи будут подтверждены, когда большинство (голосовых) реплик подтвердят их запись. Другой возможный вариант -single, что означает, что записи будут подтверждены, когда подтвердит одна реплика. -
Долговечность устанавливается на уровне таблицы с помощью настройки
durability, снова используя либоreconfigure, либо записью вtable_configсистемную таблицу. В режиме долговечностиhard, записи записываются на диск до отправки подтверждения; в режимеsoftзаписи подтверждаются немедленно после хранения в памяти. Режимsoftбыстрее, но немного менее устойчив к сбоям. По умолчаниюhard. -
Режим чтения устанавливается для каждого запроса с помощью необязательного аргумента,
read_mode(илиreadMode), к таблице. У него есть три возможных значения:-
singleвозвращает значения, которые находятся в памяти (но необязательно записаны на диск) на первичной реплике. Это значение по умолчанию. -
majorityвозвращает только значения, которые безопасно сохранены на диске на большинстве реплик. Это требует отправки сообщения каждой реплике при каждом чтении, поэтому это самый медленный, но наиболее согласованный режим. -
outdatedвозвращает значения, которые находятся в памяти на произвольно выбранной реплике. Это самый быстрый, но наименее согласованный режим.
-
Обратите внимание, что изменения игнорируют флаг read_mode и всегда ведут себя так, как если бы он был установлен на single.
Линейная и атомарная гарантии согласованности
При следующих настройках RethinkDB гарантирует линейность отдельных атомарных операций с отдельными документами:
-
write_acks:majority -
durability:hard -
read_mode:majority
Это означает, что каждое чтение будет видеть все предыдущие успешные записи, и ни одно чтение никогда не увидит определённо проваленную запись. (См. примечание о определённо проваленных и неопределённых записях ниже.)
Гарантия линейности относится к атомарным операциям, а не к запросам. Один запрос RethinkDB не обязательно выполняется как одна атомарная операция. Возможно, что запрос:
r.table("foo").get("bar").eq(r.table("foo").get("bar")).run(conn, callback);
может вернуть false! Каждая отдельная операция get атомарна, но сам запрос — нет. Чтобы прочитать и изменить документ в одной атомарной операции, используйте команды update или replace.
r.table("foo").get(id).update({hits: r.row("hits") + 1}).run(conn, callback);
Это также может быть использовано для реализации регистрового устройства проверки и установки. Следующий запрос атомарно проверит, равно ли поле check значению old_value, и изменит его на new_value, если это так:
r.table("foo").get(register_id).update({
check: r.branch(r.row("check").eq(old_value), new_value, r.row("check"))
}).run(conn, callback);
Операции RethinkDB никогда не являются атомарными по нескольким ключам. По этой причине RethinkDB не может считаться базой данных ACID.
В настоящее время filter, get_all и подобные операции выполняются как отдельные операции от update и других операций мутации. Поэтому следующее не является правильной реализацией регистрового устройства проверки и установки, так как filter и update не будут выполняться в одной атомарной операции:
r.table("foo").filter({
id: register_id, foo: old_val
}).update({foo: new_val}).run(conn, callback);
table.filter({id: register_id, foo: old_val}).update({foo: new_val})
Это поведение может измениться в будущем. См. Github issue #3992 для отслеживания обсуждения.
Гарантии доступности
За исключением кратких периодов, таблица будет полностью доступна, пока более половины голосующих реплик для каждого фрагмента и для всей таблицы в целом будут доступны. Если потеряно половина или больше голосующих реплик для фрагмента, операции чтения или записи для этого фрагмента завершатся неудачно.
Переконфигурация таблицы (изменение количества фрагментов, балансировка и т. д.) вызывает кратковременную потерю доступности в различные моменты во время переконфигурации.
Если первичная реплика потеряна, но более половины голосующих реплик по-прежнему доступны, произвольная голосующая реплика будет избрана в качестве первичной. Новая первичная реплика будет появляться в table_status, но поле primary_replica из table_config не изменится. Если старая первичная реплика снова станет доступной, система вернётся к ней. При изменении первичной реплики будет небольшой период недоступности.
Если половина или больше голосующих реплик фрагмента потеряны, единственный способ восстановить доступность — запустить reconfigure с параметром emergency_repair. Обратитесь к документации по reconfigure для получения дополнительной информации.
Операции чтения в режиме single могут завершаться успешно, даже если таблица недоступна, но это не гарантируется. Чтения в режиме outdated будут успешны, пока доступна хотя бы одна реплика для каждого соответствующего фрагмента.
Голосующие и не голосующие? По умолчанию все реплики являются «голосовыми» репликами, что просто означает, что они учитываются в любой операции, для которой требуется большинство доступных реплик. Однако скорость, с которой реплики «голосуют», зависит от задержки сети; если у вас есть удалённый дата-центр с большей задержкой, вы можете установить его реплики в не голосующие, чтобы улучшить производительность, но с потерей гарантированной доступности в этом дата-центре. Вы можете установить реплику как «не голосующую», изменив ее конфигурацию таблицы с помощью
reconfigure.
Баланс безопасности и производительности
По умолчанию RethinkDB отдаёт предпочтение безопасности над производительностью, за исключением одного случая: read_mode по умолчанию single вместо majority. Режим чтения majority требует отправки запроса всем репликам и ожидания ответа большинства, что значительно снижает производительность.
В обычном режиме чтения single производит те же результаты, что и majority, но может возвращать устаревшие результаты в случае сбоя сети или сбоя. Также возможно, что чтение в режиме single может вернуть результаты неполной записи, которая позже будет отменена.
То же самое относится к режиму записи single и режиму долговечности soft. В обычном режиме они дают те же результаты, что и majority и hard, но в случае сбоя сети или сервера недавние операции записи, выполненные в этих режимах, могут быть потеряны.
Обратите внимание, что write_acks и durability фактически не влияют на то, как выполняется запись; они только влияют на то, когда подтверждение возвращается клиенту.
Чтения в режиме "outdated" вернут устаревшие данные даже при нормальной работе, но данные обычно будут устаревшими менее чем на секунду. В случае сбоя сети или сервера данные могут быть гораздо более устаревшими. Преимущество запуска чтений в режиме "outdated" заключается в том, что задержка и пропускная способность часто лучше, чем в режиме "single", помимо различий в доступности, описанных в предыдущем разделе.
Примечания
Использование параметра emergency_repair для таблицы аннулирует все гарантии.
Существует два способа, которыми операция записи может завершиться неудачно. Если запись завершается определённо неудачно, ни одно чтение никогда не увидит её, даже в более слабых режимах чтения. Если запись завершается неопределённо неудачно, чтения в режимах single или outdated могут увидеть её, но при устранении сбоя сети или сервера, вызвавшего проблему, запись может быть отменена или нет. В общем случае записи завершатся неопределённо неудачно, если они выполнялись в точный момент, когда возникла проблема с сетью или сервером. Оба эти сбоя вызовут ошибки, и вы можете проверить сообщение об ошибке, чтобы узнать, был ли сбой определённым или неопределённым.
Автоматическое переключение RethinkDB имеет ограничения в случаях непереходных сбоев подключений, то есть сервер А может связаться с Б, Б может связаться с С, но А не может связаться с С. Подробности см. в документации по переключению.
© RethinkDB contributors
Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
https://rethinkdb.com/docs/consistency/