#database #synchronization #distributed #offline
#База данных #синхронизация #распределенный #Не в сети
Вопрос:
У меня есть интернет-приложение, которое поддерживает автономный режим, в котором пользователи могут создавать данные, которые будут синхронизированы с сервером, когда пользователь вернется в сеть. Поэтому я использую UUID для идентификации в своей базе данных, чтобы отключенные клиенты могли генерировать новые объекты, не опасаясь использования идентификатора, используемого другим клиентом, и т.д. Однако, хотя это отлично работает для объектов, принадлежащих этому пользователю, существуют объекты, которые совместно используются несколькими пользователями. Например, теги, используемые пользователем, могут быть глобальными, и удаленная база данных не может содержать все возможные теги во вселенной.
Если автономный пользователь создает объект и добавляет к нему некоторые теги. Допустим, эти теги не существуют в локальной базе данных пользователя, поэтому программное обеспечение генерирует для них UUID. Теперь, когда эти теги синхронизированы, потребуется процесс разрешения для устранения любого перекрытия. Какой-нибудь способ сопоставить любые существующие теги в удаленной базе данных с локальными версиями.
Один из способов — использовать некоторый процесс, с помощью которого глобальные объекты разрешаются с помощью естественного ключа (имя в случае тега), и локальная база данных должна заменить свой существующий объект этим объектом из глобальной базы данных. Это может привести к беспорядку, когда имеется много подключений к другим объектам. Что-то подсказывает мне, что этого следует избегать.
Другой способ справиться с этим — использовать два идентификатора. Один глобальный идентификатор и один локальный идентификатор. Я надеялся, что использование UUID поможет избежать этого, но я продолжаю переходить от использования одного UUID к использованию двух разделенных идентификаторов. Использование этой опции заставляет меня задуматься, не выпустил ли я проблему из-под контроля.
Другой подход заключается в отслеживании всех изменений через объекты, не являющиеся общими. В этом примере объекту пользователь присвоил теги. Когда пользователь синхронизирует свои автономные изменения, сервер может заменить его локальный тег глобальным. В следующий раз, когда этот клиент синхронизируется с сервером, он обнаруживает изменение в объекте, не являющемся общим. Когда клиент извлекает этот объект, он получает глобальный тег. Программное обеспечение просто повторно сохранит объект, не являющийся общим, указав его на тег сервера и потеряв его локальную версию. Некоторые проблемы, связанные с этим, заключаются в дополнительных обходах для полной синхронизации и дополнительных данных в локальной базе данных, которые просто потеряны. Существуют ли другие проблемы или баги, которые могут возникнуть, когда система находится между состояниями синхронизации? (например, попытка связаться с сервером и отправка ему локальных UUID для объектов и т.д.).
Другой альтернативой является избегание общих объектов. В моем программном обеспечении это могло бы быть приемлемым ответом. Я не занимаюсь совместным использованием объектов между пользователями, но это не значит, что я НЕ буду делать этого в будущем. Это означает, что выбор этого параметра может парализовать работу моего программного обеспечения в будущем, если мне понадобится добавить эти типы функций. У этого выбора есть последствия, и я не уверен, что полностью изучил их.
Итак, я ищу любую наилучшую практику, существующие алгоритмы для работы с системой такого типа, рекомендации по выбору и т.д.
Комментарии:
1. Я знаю, что этому вопросу около 6 лет. Я сталкиваюсь в основном с той же ситуацией. Интересно, дало ли вам ваше время опыт в этой области какие-либо дополнительные идеи? Имя тега в качестве естественного ключа кажется хорошим выбором. Как сработало использование UUID для запроса ваших первичных ключей?
Ответ №1:
В зависимости от того, какую семантику приложения вы хотите предложить пользователям, вы можете выбрать разные решения. Например, если вы на самом деле говорите о пометке объектов, созданных автономным пользователем, ключевым словом, и хотите поделиться тегами с несколькими объектами, созданными разными пользователями, тогда использование «текста» для тега подойдет, как вы и предлагали. Как только все изменения будут объединены, теги с одинаковым «текстом», например, скажем, «ЭТО ПОТРЯСАЮЩЕ», станут общедоступными.
Существуют другие способы обработки отключенных обновлений общих объектов. SVN, CVS и другие системы контроля версий пытаются автоматически разрешать конфликты, а когда не могут, просто сообщают пользователю о наличии конфликта. Вы можете сделать то же самое, просто сообщите пользователю, что были одновременные обновления, и пользователи должны обработать разрешение.
В качестве альтернативы вы также можете регистрировать обновления как единицы изменения и пытаться объединить изменения вместе. Например, если ваш общий объект представляет собой холст, а семантика вашего приложения допускает совместное рисование на одном и том же холсте, то можно создать отключенное обновление, которое рисует линию из точки A в точку B, и другое отключенное обновление, рисующее линию из точки C в точку D. В этом случае, если вы сохраняете эти два обновления как всего две операции, вы можете заказать два обновления, и при повторном подключении каждый пользователь загружает все свои отключенные операции и применяет отсутствующие операции от других пользователей. Вероятно, вам нужно какое-то правило упорядочивания, возможно, основанное на номере версии.
Другой вариант: если обновления общих объектов не могут быть автоматически согласованы, и семантика вашего приложения не поддерживает уведомление пользователя и запрос пользователя разрешить конфликты из-за отключенных обновлений, то вы также можете использовать дерево версий для обработки этого. Каждое обновление общего объекта создает новую версию с предыдущей версией в качестве родительской. При отключенных обновлениях общего объекта от двух разных пользователей две отдельные дочерние версии / конечные узлы являются результатом одной и той же родительской версии. Если внутренним представлением состояния вашего приложения является это дерево версий, то внутреннее состояние вашего приложения остается неизменным, несмотря на отключенные обновления, и вы можете обрабатывать две ветви дерева версий каким-либо другим способом (например, сообщать пользователю о ветвях и создавать для них инструменты для объединения ветвей, как в системах управления версиями).
Всего несколько вариантов. Надеюсь, это поможет.
Комментарии:
1. Я часто вижу, как люди приводят SVN, CVS и т.д. В качестве примеров синхронизации, но никакого реального обсуждения по существу того, КАК они это делают, нет. Как они вычисляют различия в больших масштабах? Как они отслеживают, что изменилось с момента последней синхронизации? В какой-то степени я думаю, что CVS и SVN неприменимы. SVN напрямую не обрабатывает ситуации, когда я создаю файл, а другой пользователь создает файл с тем же именем. Пользователь должен принять решение путем слияния. В моем случае мне нужно быть более изящным, потому что его старый тег не совпадает с идентификатором в удаленном хранилище. SVN не является графом объектов. Никаких сдвигающихся идентификаторов.
2. Требования вашего приложения важны. Возможно, вы захотите ознакомиться с файловой системой Coda и другим известным уровнем техники. Я думаю, у вас есть 3 варианта. Вариант 1. попросите пользователя помочь объединить конфликты и очистить состояние приложения. Вариант 2. всегда разрешайте параллельные операции. Например. используя глобально уникальные идентификаторы для новых файлов, но разрешайте пользователям создавать файлы с одинаковыми именами в одном общем каталоге. Вариант 3: автоматическое разделение на две ветви / версии объекта при одновременных обновлениях. Пользователь может объединять ветви в любое время, но перед объединением внутреннее состояние приложения является «согласованным».
3. Я был бы рад провести мозговой штурм подробнее, если бы вы подробнее описали, что вы пытаетесь сделать…
4. возможно, мы могли бы провести мозговой штурм по электронной почте, поскольку эти комментарии ограничены 600 символами. Я продолжаю работать над этим, и я думаю, что моим решением было просто синхронизировать локальные объекты вместе с тем, к чему они подключаются. Эти общие / глобальные объекты будут просто разрешены, потому что сервер отправит их клиенту при синхронизации. В это время он удалит свою локальную версию и выберет серверную. Но, я думаю, дальнейшее обсуждение может дать больше понимания. Я в игре, если вы в игре. Я не уверен, как я могу отправить вам личное сообщение или связаться с вами напрямую.
Ответ №2:
Ваша проблема очень похожа на системы управления версиями, такие как SVN. Вы могли бы взять пример из них.
У каждого пользователя будет набор личных объектов плюс любые общие объекты, которые ему нужны. Локально они будут работать так, как если бы им принадлежали все объекты.
Во время синхронизации клиент сначала загружает любые изменения в объектах и автоматически синхронизирует то, что очевидно. В вашем примере, если с сервера поступает новый тег с тем же именем, то он соответствующим образом обновит UUID в локальной системе.
Это также было бы хорошим местом для обнаружения и обработки случаев, таких как данные, переданные от другого клиента, но тем же пользователем.
Как только клиент получит обновленную и объединенную версию данных, вы можете выполнить загрузку.
Будут обходы, но я не вижу способа сделать это без чрезмерного усложнения структуры данных и возникновения потенциальных подводных камней в том, как вы выполняете синхронизацию.
Ответ №3:
В качестве совершенно неуместного предложения в левом поле мне интересно, может ли использование чего-то вроде CouchDB подойти для вашей ситуации. Ее функции репликации могут решить за вас множество проблем с синхронизацией в режиме онлайн / офлайн, включая механизмы, позволяющие приложению разрешать конфликты при их возникновении.
Комментарии:
1. Только если бы я мог изучить, как они выбирают репликацию, и переписать ее для моей среды. Я не могу использовать CouchDB на обоих концах, выбор на клиенте ограничен только одной базой данных. Поэтому, даже если я использовал CouchDB на стороне сервера, мне все равно придется синхронизироваться с не-CouchDB.
2. Да, вы правы. Если вы не сможете запустить CouchDB на обоих концах, в этом нет никакого преимущества. Жаль.
3. Мне было бы интересно услышать алгоритм CouchDB. Как они обнаруживают изменения от одного набора к другому. Я вроде как хотел, чтобы это было скорее обсуждение алгоритмов синхронизации, в отличие от продуктов, которые выполняют синхронизацию.