Как правильно синхронизировать данные между клиентскими приложениями?

Имеется серверное приложение, для производельности и непривязанности к наличию интернета, у клиентов стоят локальные копии с необходимым для работы клиента объемом данных. Клиенты работают с этими серверами, все изменения записываются в локальные БД, после чего, раз в 5 минут, через очередь RabbitMQ синхронизируются на основной сервер и получают ревизионно изменения с него.
Из важных деталей - у одного клиента может стоять сразу несколько локальных серверов, данные между ними синхронизируются через основной сервер. Ревизионность изменений реализована на уровне приложения, при открытии транзакции мы получаем из БД новую ревизию для этой транзакции, помечаем ей все измененные сущности, и сохраняем в БД.

Некоторое время назад, заметили что подход приводит к потерям данных при обмене, если объемы данных приходящих в пакетах синхронизации сильно различаются (с локального сервера А, просидевшего без интернета приходит несколько тысяч изменений, а с сервера Б - несколько штук).
При этом, так как мы начинаем импорт с сервера А раньше - его изменения отмечаются ревизией меньшей, чем данные сервера Б, но так как импорт идет дольше и коммит происходит сильно позже - на локальные сервера уже ушла ревизия, выданная серверу Б и они считают что уже знают изменения сервера А, хотя они тольоко еще коммитятся в БД.
Решили проблему по простому, вводом пессимистичных крупноблочных блокировок, приводящих к тому что пересекающиеся данные может редактировать только один поток.

И вроде как жили с ним, пока не стали появляться клиенты с 50-60 локальных серверов, данные с которых мы импортировать не успеваем. Да, сейчас мы их в каком-то виде ускорили, добавили кеширования и временно решили проблему, и есть еще запас, что можно улучшить в текущем решении (перейти на более оптимистичные блокировки например). Но, стали задаваться вопросом, возможно наш подход неправилен принципиально и мы городим костыли, когда есть более менее стандартное решение для этой проблемы?
В целом, нашли решение на уровне БД, которое нас вроде бы устроило бы и позволило не переписывать целиком наш механизм обмена данными (https://docs.microsoft.com/en-us/sql/relational-da... Но проблема в том, что в ближайший год планируем переход с MS SQL (да, из-за стоимости лицензий), и завязываться на его специфику не хотелось бы. Пока что планируем переход на PostgreSQL, но в целом готовы подумать о других альтернативах, если они позволили бы решить эту (и другие естественно) проблему проще. Возможно сможете посоветовать статьи/книги на эту тему, или кто-то сталкивался с такими проблемами и сможет описать в каком направлении нам стоит думать?
  • Вопрос задан
  • 1009 просмотров
Пригласить эксперта
Ответы на вопрос 2
DmitriyEntelis
@DmitriyEntelis
Думаю за деньги
У вас из описания получается что версионность идет на уровне всей базы целиком, а не конкретных объектов?
Если не секрет, что именно за данные?
Про "тысячи штук" - это метафора, или поток записей действительно небольшой?

А как вообще в этой архитектуре вы разруливаете (планируете разруливать) перезапись данных даже без учета технических проблем?
Или данные такие, что клиенты не могут их перезаписать?

Тогда я бы смотрел все таки в сторону введения версионности по конкретным объектам, хоть это и тянет на "переписать все целиком"
Ответ написан
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
Если у Вас есть синхронизация на клиенте, то следует различать работу с базой и модификацию базы:
1. Работа - это SELECT.
2. Модификация - это всё остальное.

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

Пример: Добавили запись и тут же её удалили - "разница" значимых данных равна нулю. Изменений в модифицирующих запросах - нет.

После появления сети (или по тайм-ауту) - отправляйте все модифицирующие запросы на сервер центральной БД для их последующего запуска там.

Перед модификацией очередных данных - проверяйте сразу конфликты между всеми клиентами (пришедшими стеками). При конфликте - берите стек самого последнего (нового по timestamp) клиента с модификацией этих данных.

Т.е., Вам нужно построить систему разбора запросов синхронизации с клиентов на сервере с поиском пересечений и построением корректной очереди для их исполнения в правильном порядке.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы