Комментарии 12
1. Был у меня рубль.
2. На одной реплике я купил за него очки.
3. На второй реплике я купил за него сигару.
4. В итоге я в очках и с сигарой и должен вам рубль, который вы из меня не выбьете.
state-based:
1. Был у меня рубль.
2. На одной реплике я купил за него очки.
3. На второй реплике я купил за него сигару.
4. В итоге я в очках и с сигарой, и даже ничего вам не должен.
Это я к чему — далеко не всегда результат слияния валидных веток приводит к валидному результату. В данном случае правильная стратегия разрешения конфликта должна отменить одну из транзакций и выдать пользователю об этом сообщение.
Может я неправильно понял, но вроде как смогли решить эту проблему.
Вообще говоря, когда нужна транзакционная целостность, никто не мешает добавить commitment protocol, который будет гарантировать доставку уведомлений между репликами или обязательный мёрж с проверкой доступности реплик и устранением аномалий.
Протокол не поможет, если связь с удаленной нодой пропала. Что делать? Варианты по САР-теореме Брюэра:
1. Не доставлять (потерять букву А) — подождать, пока нода починится. На это время операции блокируются.
2. Доставить потом — потерять согласованность (букву С). В это время удаленная нода тратит деньги, которых уже нет.
3. Объявить ноду нерабочей. Все операции идут с оставшейся, ту потом придется догонять «данными». (потеряли букву Р). Проблемы начнутся, когда система действительно децентрализованная, тогда как нода должна понять, что ее «соседка» потерялась и взять на себя операции? А может быть это она сама потерялась, а на той стороне все хорошо?
Причем все решение проблем потом должно выполняться внешними средствами:
— в git-е это будет делать пользователь, разруливая merge conflict
— в банке договорная служба выпишет пользователю овердрафт с требованием погасить. Если она не справится, то служба безопасности ей поможет.
Вот возможная стратегия. Мерджится не множество { очки, сигара }, а множество { (очки, 1руб.), (сигара, 1руб.) }. Количество денег рассчитывается как «доход» минус «сумма расходов по всем покупкам». Если выясняется, что значение отрицательное, то какая-нибудь покупка или несколько игнорируются (последние по времени или хоть по алфавиту). Они не удаляются из внутреннего инвентаря (монотонность не нарушается), просто не отображаются и не учитываются как доступные. Когда у пользователя увеличится доход, у него станут учитываться и сделанные ранее овердрафт-покупки. Это механизм «выбивания долга». То есть да, хранится как бы список транзакций. Но это не op-based CRDT, т.к. весь монотонный снэпшот синхронизируется, и ничего не отменяется.
То есть, когда пользователь уже забыл, что когда-то у него не хватало денег на айфон10, и он купил самсунг галакси100, и положил ещё денег, чтобы купить что-то другое, то внезапно эти деньги у него пропадут и через день ему придёт посылка с ненужным ему айфон10?
Я рассматривал в контексте своей области — мобильные игры, покупка предметов за игровую валюту.
что когда-то у него не хватало денег на айфон10, и он купил самсунг
Почему не хватало на айфон? Хватало. У него не хватало на два смартфона одновременно, но на каждый по отдельности хватало. Иначе сервис не позволил бы купить. И пользователь сознательно в разных экземплярах сервиса купил и айфон, и самсунг на один и тот же рубль (временно на один и тот же, а после пополнения на разные).
Насколько я помню он говорил, что тема оказалась очень сложная. Сделать качественно и учесть все детали практически нереально. В его словах кажется было некоторое сожаление, возможно есть какие то концептуальные сложности в реализации… Наверно поэтому проект не очень активен на данный момент
Репликация без конфликтов: CRDT в теории и на практике