RethinkDB - это допустимая оптимистическая реализация блокировки

Я пробую много новых идей (DDD, Event Sourcing и CQRS) и оцениваю RethinkDB как потенциальное хранилище данных для событий домена. В DDD агрегат - это набор объектов, которые работают вместе для обеспечения определенного поведения. Каждый агрегат - это граница транзакции / согласованности. Корень агрегата - это объект, который предоставляет API и скрывает внутреннюю реализацию.

Для сохранения агрегата обычно рекомендуется использовать оптимистическую блокировку. Идея состоит в том, чтобы иметь атрибут номера версии в агрегате, и когда приходит время сохранять агрегат, мы проверяем, чтобы версия агрегата в базе данных соответствовала версии агрегата, который был прочитан / обновлен в приложении. Это гарантирует, что пока никто не изменил агрегат, и предотвращает перезапись других изменений.

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

Вот простая реализация с использованием Ruby API RethinkDB.

Я создал таблицу под названием "кандидаты" с одной записью

"id":  "6b3b57a7-3ba8-4322-873e-1d6c8333daae" ,
"name":  "Homer Simpson" ,
"updated_at": Mon Dec 28 2015 12:05:40 GMT+05:30 ,
"version": 1

Вот пример кода теста, который я дважды запускал параллельно.

require 'rethinkdb'
include RethinkDB::Shortcuts

conn = r.connect(:host => 'localhost',
             :port => 28015,
             :db => 'test')

def update_applicant(conn, current_version)
  result = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').update{ |applicant|
  r.branch(
      applicant['version'].eq(current_version),
      {updated_at: Time.now, version: current_version + 1},
      {}
  )
}.run(conn)

  fail 'optimistic locking failure' if result['unchanged'] == 1
rescue => e
 puts "optimistic locking failure: #{current_version}"
 current_version = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').run(conn)['version']
 retry
end

(1..100).each { |version| update_applicant(conn, version) }

conn.close

Кажется, это работает, но я хочу убедиться, что при таком подходе в производственной среде не будет условий гонки и других проблем. Я предполагаю, что обновление - это атомарная операция, и использование ветки в обновлении по-прежнему сохраняет ее атомарностью.

Я ищу некоторые подтверждения и предложения от разработчиков / пользователей RethinkDB. Спасибо.


person Sarat Kongara    schedule 28.12.2015    source источник


Ответы (1)


update всегда является атомарной операцией, если вы не передаете флаг non_atomic: true (что иногда необходимо, если обновление содержит недетерминированную операцию), поэтому этот код мне кажется безопасным.

person mlucy    schedule 28.12.2015
comment
Спасибо за ответ. - person Sarat Kongara; 28.12.2015