Гарантии согласованности
Три настройки управляют согласованностью и долговечностью в RethinkDB: подтверждения записи и долговечность по таблице, а также режим чтения запроса.
Настройки
-
Подтверждения записи настраиваются по таблице с помощью настройки
write_acks, используя команду config или запись в системную таблицуtable_configсистемную таблицу. По умолчанию установлено значениеmajority, что означает, что записи будут подтверждаться, когда большинство (голосовых) реплик подтвердят свои записи. Другой возможный вариант —single, что означает, что записи будут подтверждаться, когда подтвердит их одна реплика. -
Долговечность настраивается по таблице с помощью настройки
durability, опять же, используя либоreconfigure, либо запись в системную таблицуtable_config. В режиме долговечностиhard, записи сохраняются на диск до отправки подтверждения; в режимеsoft, записи подтверждаются немедленно после хранения в памяти. Режимsoftбыстрее, но немного менее устойчив к сбоям. По умолчанию установлено значениеhard. -
Режим чтения настраивается по запросу с помощью необязательного аргумента
read_mode(илиreadMode), для table. Он имеет три возможных значения:-
singleвозвращает значения, которые находятся в памяти (но необязательно записаны на диск) на первичной реплике. Это значение по умолчанию. -
majorityбудет возвращать только значения, которые безопасно сохранены на диске на большинстве реплик. Это требует отправки сообщения каждой реплике при каждом чтении, поэтому это самый медленный, но наиболее согласованный режим. -
outdatedвозвращает значения, которые находятся в памяти на произвольной реплике. Это самый быстрый, но наименее согласованный режим.
-
Обратите внимание, что changefeeds игнорирует флаг 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-and-set. Следующий запрос атомарно проверит, равно ли поле 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 и других операций мутации. Поэтому следующее не является правильной реализацией регистра check-and-set, так как операции 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 prioritizes safety over performance, за исключением одного случая: read_mode по умолчанию single, а не majority. Режим чтения majority требует отправки запроса ко всем репликам и ожидания ответа большинства, что значительно снижает производительность.
В нормальной работе режим чтения single даёт такие же результаты, как режим чтения majority, но может возвращать устаревшие результаты в случае сбоя сети или сбоя. Также возможно, что чтение, выполненное в режиме single , может вернуть результаты незавершенной записи, которая позже будет отменена.
То же самое относится к режиму записи single и режиму долговечности soft. В нормальной работе эти режимы дают такие же результаты, как majority и hard, но в случае сбоя сети или сервера недавние операции записи, выполненные с помощью этих режимов, могут быть потеряны.
Обратите внимание, что write_acks и durability фактически не влияют на выполнение записи; они только влияют на то, когда подтверждение отправляется клиенту.
Чтения, выполненные в режиме "outdated" , вернут устаревшие данные даже при нормальной работе, но данные, как правило, будут устаревшими менее чем на секунду. В случае сбоя сети или сервера данные могут быть намного более устаревшими. Преимущество выполнения чтений в режиме "outdated" заключается в том, что задержка и пропускная способность часто лучше, чем в режиме "single", помимо различий в доступности, описанных в предыдущем разделе.
Примечания
Использование опции emergency_repair в таблице аннулирует все гарантии.
Существуют два способа, которыми операция записи может завершиться сбоем. Если запись завершается сбоем окончательно, ни одно чтение никогда не увидит её, даже в более слабых режимах чтения. Если запись завершается сбоем неопределённо, чтения, выполненные в режимах single или outdated , могут увидеть её, но когда проблема, вызвавшая сбой сети или сервера, будет решена, запись может или не может быть отменена. Как правило, записи завершаются неопределённо, если они выполнялись в тот момент, когда впервые произошла проблема с сетью или сервером. Оба эти сбоя приведут к ошибкам, и вы можете проверить сообщение об ошибке, чтобы узнать, был ли сбой окончательным или неопределённым.
Автоматический failover RethinkDB имеет ограничения в случаях сбоев с непереходной связностью, т. е. сервер A может связаться с B, а B может связаться с C, но A не может связаться с C. Для получения дополнительной информации см. документацию по Failover.
© RethinkDB contributors
Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
https://rethinkdb.com/docs/consistency/