Наскільки найкраще ви представляєте двонаправлену синхронізацію в програмі REST?


23

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

Приклад:

У мене є API, який представляє список todo.

GET / POST / PUT / DELETE / todos / тощо.

Цей API може посилатися на віддалені служби TODO.

GET / POST / PUT / DELETE / todo_services / тощо.

Я можу маніпулювати Todos з віддаленої служби через мій API як проксі

GET / POST / PUT / DELETE / todo_services / abc123 / тощо.

Я хочу, щоб можна було робити двонаправлену синхронізацію між локальним набором Todos та віддаленим набором TODOS.

Таким чином, це можна зробити

POST / todo_services / abc123 / sync /

Але в ідеї "дієслова погані", чи є кращий спосіб представити цю дію?


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

Правильно - припустимо, що алгоритм синхронізації розроблений та функціонує в API "рівня коду" - як я викрию це через REST. Один із способів синхронізації здається набагато простішим для вираження: я GET /todo/1/і POSTце до /todo_services/abc123/ Але, 2-й спосіб - я не беру набір даних і передаю його на ресурс, дія, яку я вживаю, фактично призводить до потенційної модифікації двох ресурсів. Я думаю, я міг би відмовитися від того, щоб "синхронізації Тодо" були самими ресурсами POST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
Едвард М Сміт,

У нас все ще є випуск перед конем. Моя думка полягала в тому, що ви не можете припустити, що синхронізація працює і розробляє API. Дизайн API буде обумовлений численними проблемами того, як саме працює алгоритм синхронізації.
Адам Кросленд

Це потенційно виявляє корисні результати: GET /todo_synchronizations/1=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
Едвард М Сміт

2
Я згоден з @Adam. Чи знаєте ви, як ви збираєтеся реалізувати синхронізацію? Як ви обробляєте зміни? Чи просто у вас є два набори елементів, які ви хочете узгодити, чи у вас є журнал дій, які спричинили розбіжність двох наборів з моменту останньої синхронізації? Причину, про яку я запитую, - це може бути складно виявити додавання та видалення (незалежно від REST). Якщо у вас є об’єктний сервер і не має його на стороні клієнта, ви повинні запитати себе: "Клієнт видалив його чи створив його сервер?" Тільки коли ви точно знаєте, як веде себе "ресурс", ви зможете точно представити його в REST.
Реймонд Сальтреллі

Відповіді:


17

Де і які ресурси?

REST - це все, що стосується ресурсів у безгромадянському, відкритому вигляді. Її не потрібно реалізовувати через HTTP, а також не покладатися на JSON або XML, хоча настійно рекомендується використовувати формат даних гіпермедіа (див. Принцип HATEOAS ), оскільки посилання та ідентифікатори бажані.

Отже, виникає питання: як можна думати про синхронізацію з точки зору ресурсів?

Що таке двонаправлена ​​синхронізація? **

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

Отже, ключовим ресурсом, на який потрібно звернутись, є журнал транзакцій, а отже, процес синхронізації може виглядати таким чином для колекції "items" під HTTP:

Крок 1 - Локальне отримання журналу транзакцій

Місцеві: GET /remotehost/items/transactions?earliest=2000-01-01T12:34:56.789Z

Віддалений: 200 ОК з тілом, що містить журнал транзакцій, що містить подібні до цього поля.

  • itemId - UUID для надання спільного первинного ключа

  • updatedAt - часова мітка для надання узгодженої точки, коли дані востаннє оновлювалися (за умови, що історія редагування не потрібна)

  • fingerprint- хеш SHA1 вмісту даних для швидкого порівняння, якщо updateAtйде кілька секунд

  • itemURI - повний URI для елемента, щоб дозволити його пізніше

Крок 2 - Місцевий порівнює журнал віддалених транзакцій із власним

Це застосування ділових правил, як синхронізувати. Зазвичай itemIdволевиявлення виявить локальний ресурс, а потім порівняє відбиток пальців. Якщо є різниця, то проводиться порівняння updatedAt. Якщо вони занадто близькі для виклику, тоді потрібно буде прийняти рішення вивести на основі іншого вузла (можливо, це важливіше) або натиснути на інший вузол (цей вузол важливіший). Якщо віддаленого ресурсу немає локально, робиться натискання (це містить фактичні дані для вставки / оновлення). Будь-які локальні ресурси, відсутні в журналі віддалених транзакцій, вважаються незмінними.

Запити на виклик виконуються проти віддаленого вузла, щоб дані існували локально, використовуючи itemURI. Вони не застосовуються локально до пізніше.

Крок 3 - Натисніть на журнал транзакцій локальної синхронізації на віддалений

Місцевий: PUT /remotehost/items/transactions з тілом, що містить локальний журнал транзакцій синхронізації.

Віддалений вузол може обробити це синхронно (якщо він невеликий і швидкий) або асинхронно (думаю 202 прийнято ), якщо це може призвести до великих витрат. Якщо припустити синхронну операцію, то результат буде або 200 ОК, або 409 КОНФЛІКТ, залежно від успіху чи невдачі. У випадку 409 CONFLICT процес слід запустити заново, оскільки стався оптимістичний збій блокування на віддаленому вузлі (хтось змінив дані під час синхронізації). Віддалені оновлення обробляються під власною транзакцією програми.

Крок 4 - Оновлення локально

Дані, витягнуті на етапі 2, застосовуються локально під транзакцією програми.

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


6

Я б розглядав операцію синхронізації як ресурс, до якого можна отримати доступ (GET) або створити (POST). Зважаючи на це, URL-адреса API може бути:

/todo_services/abc123/synchronization

(Називаючи це "синхронізація", а не "синхронізація", щоб зрозуміти, що це не дієслово)

Потім зробіть:

POST /todo_services/abc123/synchronization

Щоб запустити синхронізацію. Оскільки операція синхронізації є ресурсом, цей виклик потенційно може повернути ідентифікатор, який потім може бути використаний для перевірки стану операції:

GET /todo_services/abc123/synchronization?id=12345

3
Ця проста відповідь - відповідь. Перетворіть свої дієслова на іменники та рухайтесь далі ...
HDave

5

Це важка проблема. Я не вірю, що REST є відповідним рівнем для впровадження синхронізації. Надійна синхронізація по суті повинна бути розподіленою транзакцією. REST не є інструментом для цієї роботи.

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

Ви можете подумати про те, щоб зробити одного "господарем", а іншого - "рабом", щоб ви могли впевнено клопотати раба періодично за допомогою даних майстра.

Ви також можете розглянути рамку Microsoft Sync Framework, якщо вам абсолютно потрібно підтримувати незалежно змінюються сховища даних. Це не вдасться через REST, але поза кадром.


5
+1 для "важкої проблеми". Двонаправлена ​​синхронізація - одна з тих речей, за якими ви не усвідомлюєте, як важко, поки не заглибитесь у грязь.
Ден Рей

2

Apache CouchDB - це база даних, яка базується на REST, HTTP та JSON. Розробники виконують основні CRUD-операції через HTTP. Він також забезпечує механізм реплікації, який є одноранговим, використовуючи лише методи HTTP.

Щоб забезпечити цю реплікацію, CouchDB повинен мати деякі конвенції, характерні для CouchDB. Жодне з них не проти REST. Він надає кожному документу (що є ресурсом REST в базі даних) номер редакції . Це частина представлення JSON цього документа, але також знаходиться у заголовку HTTP HTag. Кожна база даних також має порядковий номер, який дозволяє відстежувати зміни в базі даних в цілому.

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

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


Я люблю CouchDB, і це його наступник CouchBase + SyncGateway. +1
Леонід Усов

-1

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

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

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