Синхронізація баз даних клієнт-сервер


85

Я шукаю деякі загальні стратегії для синхронізації даних на центральному сервері з клієнтськими програмами, які не завжди є в мережі.

У моєму конкретному випадку у мене є програма для телефонів Android із базою даних sqlite та веб-програма PHP із базою даних MySQL.

Користувачі зможуть додавати та редагувати інформацію в телефонній програмі та веб-програмі. Мені потрібно переконатися, що зміни, внесені в одному місці, відображаються скрізь, навіть коли телефон не може негайно зв’язатись із сервером.

Мене не цікавить, як перенести дані з телефону на сервер або навпаки. Я згадую свої конкретні технології лише тому, що я не можу використовувати, наприклад, функції реплікації, доступні для MySQL.

Я знаю, що проблема синхронізації даних клієнт-сервер існує довгий, довгий час і хотіла б отримати інформацію - статті, книги, поради тощо - про схеми вирішення проблеми. Я хотів би знати про загальні стратегії боротьби з синхронізацією для порівняння сильних, слабких сторін та компромісів.

Відповіді:


96

Перше, що вам слід вирішити, це загальна політика щодо того, яка сторона вважається "авторитетною" у разі суперечливих змін.

Тобто: припустимо, запис № 125 змінено на сервері 5 січня о 22:00, і той самий запис змінено на одному з телефонів (назвемо його Клієнтом А) 5 січня о 23:00. Останній синхрон був 3 січня. Потім користувач повторно підключається, скажімо, 8 січня.

Визначити, що потрібно змінити, є "простим" у тому сенсі, що і клієнт, і сервер знають дату останньої синхронізації, тому все, що було створено або оновлено (докладніше про це див. Нижче), оскільки останню синхронізацію потрібно узгодити.

Отже, припустимо, що єдиний змінений запис - це # 125. Ви або вирішите, що одна з двох автоматично "виграє", а другу замінить, або вам потрібно підтримати фазу узгодження, коли користувач може вирішити, яка версія (сервер або клієнт) є правильною, замінивши іншу.

Це рішення надзвичайно важливо, і ви повинні зважити "роль" клієнтів. Особливо, якщо існує потенційний конфлікт не тільки між клієнтом та сервером, але у випадку, якщо різні клієнти можуть змінити однакові записи.

[Припускаючи, що # 125 може бути змінений другим клієнтом (Клієнт B), існує ймовірність того, що Клієнт B, який ще не синхронізувався, надасть ще одну версію того самого запису, що робить попереднє вирішення конфлікту неправдивим]

Щодо пункту " створено або оновлено " вище ... як ви можете правильно визначити запис, якщо він створений одним із клієнтів (якщо це має сенс у вашому проблемному домені)? Припустимо, ваша програма керує списком ділових контактів. Якщо клієнт А каже, що вам потрібно додати нещодавно створеного Джона Сміта, а на сервері є Джон Сміт, створений вчора Клієнтом Д ... чи створюєте ви два записи, оскільки ви не можете бути впевнені, що це не різні особи? Ви попросите користувача також примирити цей конфлікт?

Чи мають клієнти "право власності" на підмножину даних? Тобто, якщо Клієнт B налаштований на «повноваження» даних для Зони №5, чи може Клієнт А змінювати / створювати записи для Зони №5 чи ні? (Це полегшить вирішення конфліктів, але може виявитись нездійсненним для вашої ситуації).

Підводячи підсумок, основними проблемами є:

  • Як визначити "ідентичність", враховуючи, що відключені клієнти, можливо, не мали доступу до сервера до створення нового запису.
  • Попередня ситуація, хоч би яким складним було рішення, може призвести до дублювання даних, тому ви повинні передбачити, як їх періодично вирішувати та як повідомляти клієнтам, що те, що вони вважали "записом №675", насправді було об'єднано / замінено Запис No 543
  • Вирішіть, чи будуть конфлікти вирішуватися за допомогою fiat (наприклад, "Версія сервера завжди перевершує клієнтську, якщо перша була оновлена ​​після останньої синхронізації") або за допомогою втручання вручну
  • У випадку фіату , особливо якщо ви вирішите, що клієнт має пріоритет, ви також повинні подбати про те, як поводитися з іншими, ще не синхронізованими клієнтами, які можуть намітити ще кілька змін.
  • Попередні елементи не враховують деталізацію ваших даних (щоб спростити опис). Досить сказати, що замість міркувань на рівні "Record", як у моєму прикладі, ви можете виявити більш доцільним запис змін на місцевому рівні. Або працювати над набором записів (наприклад, Запис особи + Запис адреси + Запис контактів) одночасно, розглядаючи їх сукупність як свого роду "Метазапис".

Бібліографія:

  • Більше про це, звичайно, у Вікіпедії .

  • Простий алгоритм синхронізації від автора Vdirsyncer

  • Стаття OBJC про синхронізацію даних

  • SyncML®: Синхронізація та керування вашими мобільними даними (книга на O'Reilly Safari)

  • Безконтактні реплікаційні типи даних

  • Оптимістична реплікація YASUSHI SAITO (HP Laboratories) та MARC SHAPIRO (Microsoft Research Ltd.) - Обстеження обчислювальної техніки ACM, вип. V, NoN, 3 2005.

  • Олександр Трауд, Юрген Наглер-Іхляйн, Франк Каргл і Майкл Вебер. 2008. Циклічна синхронізація даних шляхом повторного використання SyncML. У матеріалах дев'ятої міжнародної конференції з управління мобільними даними (MDM '08). Комп'ютерне товариство IEEE, Вашингтон, округ Колумбія, США, 165-172. DOI = 10.1109 / MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.10

  • Лам, Ф., Лам, Н. та Вонг, Р. 2002. Ефективна синхронізація мобільних даних XML. У матеріалах одинадцятої міжнародної конференції з питань управління інформацією та знаннями (Маклін, штат Вірджинія, США, 04 - 09 листопада 2002 р.). CIKM '02. ACM, Нью-Йорк, Нью-Йорк, 153-160. DOI = http://doi.acm.org/10.1145/584792.584820

  • Кунья, PR та Майбаум, TS 1981. Ресурс & equil; абстрактний тип даних + синхронізація - Методологія програмування, орієнтованого на повідомлення -. У матеріалах 5-ї міжнародної конференції з програмної інженерії (Сан-Дієго, Каліфорнія, США, 9 - 12 березня 1981 р.). Міжнародна конференція з програмної інженерії. IEEE Press, Piscataway, NJ, 263-272.

(Останні три - із цифрової бібліотеки ACM, не маючи уявлення, чи є ви членом або можете отримати їх за іншими каналами).

З сайту Dr.Dobbs :

  • Створення додатків за допомогою SQL Server CE та SQL RDA, автор Білл Вагнер, 19 травня 2004 р.

З arxiv.org:

  • Безконфліктний реплікаційний тип даних JSON - у статті описується реалізація JSON CRDT (безконфліктні реплікаційні типи даних - CRDT - це сімейство структур даних, які підтримують одночасну модифікацію та гарантують зближення таких одночасних оновлень).

Спасибі за вашу відповідь. Мені дуже цікаво прочитати про загальновживані / можливі рішення (плюси, мінуси, порівняння) проблем, які ви окреслюєте.
Скотт Сондерс,

Припускаю, ви вже перевірили Вікіпедію та речі, на які вони посилаються, так?
p.marino

3
+1 Це чудовий допис із дуже важливою інформацією з цього питання. Один відсутній момент: синхронізація видалених записів.
Stefan Steinegger

7
Я схильний розглядати "видалене" як особливий випадок "оновленого", особливо тому, що для такого роду ситуацій я віддаю перевагу "логічному видаленню" замість "фізичного видалення". Отже, для мене "видалено" на стороні ведучого або веденого означає "спеціальний логічний вилучений прапор перевернуто" більше, ніж будь-що інше.
p.marino

Дякую. Я додав ще одне посилання до іншої статті (dr.dobbs) і оновлю бібліографію, якщо зможу знайти щось інше.
p.marino

9

Я б рекомендував вам мати стовпець позначки часу в кожній таблиці, і кожного разу, коли ви вставляєте або оновлюєте, оновлюйте значення позначки часу кожного зазначеного рядка. Потім ви виконуєте ітерацію по всіх таблицях, перевіряючи, чи мітка часу новіша за ту, яку ви маєте в базі даних призначення. Якщо він новіший, перевірте, чи потрібно вставляти чи оновлювати.

Спостереження 1: пам’ятайте про фізичне видалення, оскільки рядки видаляються з вихідного db, і ви повинні зробити те саме на сервері db. Ви можете вирішити цю проблему, уникаючи фізичного видалення або записуючи кожне видалення в таблиці з позначками часу. Приблизно так: DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)Отже, вам потрібно прочитати всі нові рядки таблиці DeletedRows і виконати видалення на сервері, використовуючи table_name, pk_column і pk_column_value.

Спостереження 2: пам’ятайте про FK, оскільки вставка даних у таблицю, пов’язану з іншою таблицею, може бути невдалою. Вам слід деактивувати кожен FK перед синхронізацією даних.


3
годинники повинні бути синхронізованими
tofutim

6

Якщо хтось стикається з подібною проблемою дизайну і йому потрібно синхронізувати зміни на декількох пристроях Android, я рекомендую перевірити Google Cloud Messaging для Android (GCM).

Я працюю над одним рішенням, де зміни, внесені на одному клієнті, повинні поширюватися на інших клієнтів. І я щойно застосував доказ реалізації концепції (сервер і клієнт), і це працює як шарм.

В основному кожен клієнт надсилає дельта-зміни на сервер. Наприклад, ідентифікатор ресурсу ABCD1234 змінився зі значення 100 на 99.

Сервер перевіряє ці дельта-зміни щодо своєї бази даних або затверджує зміни (клієнт синхронізується) та оновлює свою базу даних або відхиляє зміни (клієнт не синхронізований).

Якщо зміна схвалена сервером, сервер повідомляє про це інших клієнтів (крім того, хто надіслав зміну дельти) через GCM і надсилає багатоадресне повідомлення з такою ж зміною дельти. Клієнти обробляють це повідомлення та оновлюють свою базу даних.

Класна річ, що ці зміни поширюються майже миттєво !!! якщо ці пристрої в мережі. І мені не потрібно застосовувати будь-який механізм опитування щодо цих клієнтів.

Майте на увазі, що якщо пристрій занадто довго перебуває в автономному режимі, і в черзі на доставку в черзі GCM чекає більше 100 повідомлень, GCM відхилить ці повідомлення та надішле спеціальне повідомлення, коли пристрої знову з’єднаються з Інтернетом. У цьому випадку клієнт повинен виконати повну синхронізацію з сервером.

Також перегляньте цей посібник, щоб розпочати роботу із впровадженням клієнта CGM.


5

це відповідає розробникам, які використовують фреймворк Xamarin (див. /programming/40156342/sync-online-offline-data )

Дуже простий спосіб досягти цього за допомогою фреймворку xamarin - використовувати автономну синхронізацію даних Azure, оскільки вона дозволяє надсилати та витягувати дані із сервера на вимогу. Операції читання виконуються локально, а операції запису - за запитом; Якщо мережеве з'єднання розривається, операції запису ставляться в чергу, поки з'єднання не відновиться, а потім виконуються.

Реалізація досить проста:

1) створити мобільний додаток на блакитному порталі (ви можете спробувати його безкоштовно тут https://tryappservice.azure.com/ )

2) підключіть клієнта до мобільного додатка. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3) код для налаштування локального сховища:

const string path = "localrepository.db";

//Create our azure mobile app client
this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in azure");

//setup our local sqlite store and initialize a table
var repository = new MobileServiceSQLiteStore(path);

// initialize a Foo table
store.DefineTable<Foo>();

// init repository synchronisation
await this.MobileService.SyncContext.InitializeAsync(repository);
var fooTable = this.MobileService.GetSyncTable<Foo>();

4) потім натискати та тягнути ваші дані, щоб переконатися, що ми маємо останні зміни:

await this.MobileService.SyncContext.PushAsync();
await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery());

https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/


0

Я пропоную вам також поглянути на Symmetricds . це бібліотека реплікації SQLite, доступна для систем Android. Ви можете використовувати його для синхронізації бази даних клієнта та сервера, я також пропоную мати окремі бази даних на сервері для кожного клієнта. Спроба зберегти дані всіх користувачів в одній базі даних mysql - не завжди найкраща ідея. Особливо, якщо дані користувача будуть швидко зростати.


0

Давайте назвемо це проблемою синхронізації CUDR (мені не подобається CRUD - оскільки створення / оновлення / видалення - це записи, і їх слід поєднувати між собою)

Проблему також можна розглядати з точки зору списання або спочатку написання в Інтернеті . Підхід до запису в автономному режимі має проблему з конфліктом унікальних ідентифікаторів, а також кількома викликами мережі для однієї і тієї ж транзакції, що збільшує ризик (або вартість) ...

Мені особисто зручніше керувати підходом до написання в Інтернеті (отже, це буде єдиним джерелом істини - звідки синхронізується все інше). Підхід підключення до Інтернету вимагатиме не дозволяти спочатку користувачам писати в автономному режимі - вони будуть писати в автономному режимі, отримуючи нормальну форму відповіді в режимі онлайн.

Він може спочатку читати в автономному режимі, і як тільки мережа стане доступною, отримати дані з Інтернету та оновити локальну базу даних, а потім оновити інтерфейс ....

Одним із способів уникнути конфлікту унікального ідентифікатора є використання комбінації унікального ідентифікатора користувача + імені таблиці або ідентифікатора таблиці + ідентифікатора рядка (генерується sqlite) ... а потім використання синхронізованого логічного стовпця з ним .. але все ж реєстрацію потрібно зробити спочатку в Інтернеті, щоб отримати унікальний ідентифікатор, на якому будуть сформовані всі інші ідентифікатори ... тут проблема також буде, якщо годинники не синхронізуються - про що хтось згадав вище ...


Далі підхід до запису в автономному режимі матиме проблему з видаленням програми, всі дані, не завантажені в Інтернеті, будуть видалені
DragonFire
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.