İki yönlü bir senkronizasyonu REST api'sinde en iyi ne şekilde temsil edersiniz?


23

Kaynaklı bir Web Uygulaması olan ve bir başka benzer kaynağa sahip uzak bir uygulamaya yapılan bir referansı olan bir sistem varsayarak, 'yerel' kaynağı 'uzak' kaynakla senkronize eden iki yönlü bir senkronizasyon eylemini nasıl temsil edersiniz?

Örnek:

Bir yapılacaklar listesini temsil eden bir API var.

GET / POST / PUT / SİL / todos /, vb.

Bu API uzak TODO servislerine referans verebilir.

GET / POST / PUT / SİL / todo_services /, vb.

API'leri aracılığıyla uzak hizmetten todos'ları proxy olarak değiştirebilirim

GET / POST / PUT / SİL / todo_services / abc123 /, vb.

Yerel bir set todos ve TODOS'un uzak seti arasında iki yönlü bir senkronizasyon yapma yeteneği istiyorum.

Bir rpc cinsinden, biri yapabilir

POST / todo_services / abc123 / sync /

Ancak, "fiiller kötüdür" fikrinde, bu eylemi temsil etmenin daha iyi bir yolu var mı?


4
İyi bir API tasarımının kesinlikle ne demek istediğinizi senkronize etmekle ilgili somut bir anlayışa bağlı olduğunu düşünüyorum. İki veri kaynağının "senkronizasyonu" genellikle basitleştirilmesi çok kolay fakat tüm sonuçları üzerinde düşünmesi çok zor olan çok karmaşık bir sorundur. İki yönlü bir senkronizasyon yapın ve aniden zorluk çok daha yüksek. Ortaya çıkan çok zor soruları düşünerek başlayın.
Adam Crossland

Doğru - senkronizasyon algoritmasının "kod düzeyinde" API'de tasarlandığını ve işlevsel olduğunu varsayalım - bunu REST yoluyla nasıl gösterebilirim. Tek yönlü bir senkronizasyonu ifade etmesi çok daha kolay görünüyor: Ben GET /todo/1/ve POSTo /todo_services/abc123/ Ama, 2 yönlü - Bir veri setini alıp bir kaynağa koymuyorum, attığım eylem aslında iki kaynağın potansiyel değişikliğine yol açıyor. Sanırım kaynakların kendileri olmak "todo syncronizations" a geri dönebilirim POST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
Edward M Smith

Hala attan önce bir sorunumuz var. Demek istediğim, senkronizasyonun sadece çalıştığını ve API'yi tasarlayacağını varsaymamaktı. API'nin tasarımı, senkronizasyon algoritmasının tam olarak nasıl çalıştığına dair sayısız kaygı ile yönlendirilecektir.
Adam Crossland

Bu potansiyel olarak faydalı sonuçlar ortaya koyuyor: GET /todo_synchronizations/1=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
Edward M Smith

2
@Adam ile aynı fikirdeyim. Senkronizasyonunuzu nasıl uygulayacağınızı biliyor musunuz? Değişiklikleri nasıl idare ediyorsunuz? Uzlaştırmak istediğiniz iki öğe kümeniz mi var veya son iki eşitlemeden bu yana iki kümenin birbirinden ayrılmasına neden olan eylemlerin bir günlüğü var mı? Sormamın nedeni, ekleme ve silme işlemlerini tespit etmenin zor olabileceğidir (REST ne olursa olsun). Sunucu tarafında bir nesne varsa ve istemci tarafında yoksa, kendinize, "İstemci sildi mi veya sunucu oluşturdu mu?" Yalnızca "kaynağın" nasıl davrandığını tam olarak bildiğiniz zaman, onu REST'te doğru şekilde temsil edebilirsiniz.
Raymond Saltrelli,

Yanıtlar:


17

Kaynaklar nerede ve nelerdir?

REST, kaynakları vatansız, keşfedilebilir bir şekilde ele almakla ilgilidir. HTTP üzerinden uygulanmasına gerek yoktur, JSON veya XML'e dayanmak zorunda değildir, ancak linkler ve ID'ler istendiği için bir hipermedia veri formatının kullanılması ( HATEOAS prensibine bakınız ) şiddetle tavsiye edilir.

Öyleyse, soru şu şekilde olur: İnsan kaynakları açısından eşitleme hakkında nasıl düşünür?

İki yönlü senkronizasyon nedir? **

İki yönlü senkronizasyon, bir düğüm grafiği üzerinde bulunan kaynakları güncelleme işlemidir, böylece işlem sonunda tüm düğümler bu kaynakları yöneten kurallara uygun olarak kaynaklarını güncellemiş olur. Genellikle, bunun tüm düğümlerin grafikte mevcut olan kaynakların en son sürümüne sahip olacağı anlaşılmaktadır. En basit durumda, grafik iki düğümden oluşur: yerel ve uzak. Yerel senkronizasyonu başlatır.

Bu nedenle ele alınması gereken kilit kaynak bir işlem günlüğüdür ve bu nedenle, bir senkronizasyon işlemi HTTP altındaki "öğeler" koleksiyonu için şöyle görünebilir:

Adım 1 - Yerel işlem günlüğünü alır

Yerel: GET /remotehost/items/transactions?earliest=2000-01-01T12:34:56.789Z

Uzaktan: buna benzer alanlar içeren işlem günlüğü içeren gövde ile 200 OK .

  • itemId - paylaşılan bir birincil anahtar sağlamak için bir UUID

  • updatedAt - Verilerin en son güncellendiğinde (revizyon geçmişinin gerekli olmadığını varsayarak) koordineli bir nokta sağlamak için zaman damgası

  • fingerprint- updateAtBirkaç saniye sonra, hızlı karşılaştırma için verilerin içeriğinin bir SHA1 karması

  • itemURI - daha sonra alınabilmesi için öğeye tam bir URI

Adım 2 - Yerel uzak işlem günlüğünü kendisiyle karşılaştırır

Bu, nasıl senkronize edileceğine ilişkin iş kurallarının uygulanmasıdır. Tipik olarak, itemIdyerel kaynağı tanımlayacak, sonra parmak izini karşılaştıracaksınız. Bir fark varsa o zaman bir karşılaştırma updatedAtyapılır. Bunların aramaya çok yakın olması durumunda, diğer düğüme dayanma (belki de daha önemlidir) veya diğer düğüme itme kararı (bu düğüm daha önemlidir) gerekir. Uzak kaynak yerel olarak mevcut değilse, bir push girişi yapılır (bu, ekleme / güncelleme için gerçek verileri içerir). Uzak işlem günlüğünde bulunmayan herhangi bir yerel kaynağın değişmediği varsayılmaktadır.

Çekme istekleri uzak düğüme karşı yapılır, böylece veriler yerel olarak kullanılarak kullanılabilir itemURI. Daha sonra yerel olarak uygulanmazlar.

Adım 3 - Yerel senkronizasyon işlem günlüğünü uzaklara itin

Yerel: PUT /remotehost/items/transactions yerel senkronizasyon işlem günlüğünü içeren gövdeyle.

Uzak düğüm , çok fazla ek yüke yol açması muhtemel ise, bunu senkronize (küçük ve hızlıysa) veya senkronize olmayan şekilde (düşünerek KABUL EDİLİR ) düşünebilir . Eşzamanlı bir işlem varsayalım, sonuç başarı veya başarısızlığa bağlı olarak ya 200 OK ya da 409 CONFLICT olacaktır . Bir 409 ÇATIŞMA durumunda , uzak düğümde iyimser bir kilitleme hatası olduğu için işlem yeniden başlatılmalıdır (birisi senkronizasyon sırasında verileri değiştirdi). Uzaktan güncellemeler kendi başvuru işlemleriyle işlenir.

Adım 4 - Yerel olarak güncelleyin

2. Adımda çekilen veriler yerel olarak bir başvuru işlemi altında uygulanır.

Yukarıdakiler mükemmel olmasa da (yerel ve uzaktan kumandanın başını belaya sokabileceği ve yerelden uzaktan çekme verilerinin büyük bir PUT'a doldurmaktan daha verimli olabileceği çeşitli durumlar vardır), REST'in bir çiftlikte nasıl kullanılabileceğini göstermektedir. yönlü senkronizasyon işlemi.


6

Bir senkronizasyon işlemini erişilebilen (GET) veya yaratılan (POST) bir kaynak olarak görürüm. Bunu akılda tutarak, API URL olabilir:

/todo_services/abc123/synchronization

("Senkronizasyon" demek, fiil olmadığını açıklığa kavuşturmak için "senkronizasyon" değil)

O zaman yapın:

POST /todo_services/abc123/synchronization

Bir senkronizasyon başlatmak için. Bir senkronizasyon işlemi bir kaynak olduğundan, bu çağrı potansiyel olarak işlemin durumunu kontrol etmek için kullanılabilecek bir ID döndürür:

GET /todo_services/abc123/synchronization?id=12345

3
Bu basit cevap cevaptır. Fiillerinizi isimlere çevirin ve devam edin ...
HDave

5

Bu zor bir sorun mu. REST'in senkronizasyonu gerçekleştirmek için uygun bir seviye olduğunu sanmıyorum. Sağlam bir senkronizasyonun esasen dağıtılmış bir işlem olması gerekir. REST, bu iş için bir araç değildir.

(Varsayım: "senkronizasyon" ile herhangi bir kaynağın herhangi bir zamanda diğerinden bağımsız olarak değişebileceğini ve güncellemeleri kaybetmeden yeniden hizalama yeteneğini istediğinizi ima ediyorsunuz.)

Birini "ana" ve diğerini "köle" yapmayı düşünebilirsiniz, böylece köleyi güvenle ustadan verilerle periyodik olarak gizleyebilirsiniz.

Bağımsız olarak değişen veri depolarını kesinlikle desteklemeniz gerekiyorsa , Microsoft Sync Framework'ü göz önünde bulundurmak isteyebilirsiniz . Bu, REST’te işe yaramayacak, sahnelerin gerisinde kalacaktır.


5
"Zor problem" için +1. İki yönlü senkronizasyon, çamurun derinliklerine gelene kadar ne kadar zor olduğunu anlamadığınız şeylerden biridir.
Dan Ray

2

Apache CouchDB , REST, HTTP ve JSON tabanlı bir veritabanıdır. Geliştiriciler, HTTP üzerinden temel CRUD işlemlerini gerçekleştirir. Ayrıca, yalnızca HTTP yöntemlerini kullanarak eşler arası olan bir çoğaltma mekanizması da sağlar.

Bu çoğaltmayı sağlamak için CouchDB'nin bazı CouchDB'ye özgü kuralları olması gerekir. Bunların hiçbiri REST'e karşı değil. Her belgeye (bir veritabanındaki REST kaynağı olan) revizyon numarası verilir . Bu, bu belgenin JSON temsilinin bir parçasıdır, ancak aynı zamanda ETag HTTP başlığında da bulunmaktadır. Her veritabanı aynı zamanda veritabanındaki değişikliklerin bir bütün olarak izlenmesini sağlayan bir sıra numarasına sahiptir .

İçin çatışma çözümü , onlar sadece bir çatışma çözümü algoritması sağlamak için veritabanı kullanan geliştiriciler bıraktığına bir belge çatışmalı olduğuna dikkat ve çatışmalı versiyonlarını korur.

CouchDB'yi REST API'niz olarak kullanabilirsiniz, bu da size kutudan senkronizasyonu sağlayabilir veya kendi algoritmanızı yapmak için bir başlangıç ​​noktası sağlamak için çoğaltmanın nasıl yapıldığına bir göz atabilirsiniz.


CouchDB'yi seviyorum ve halefi CouchBase + SyncGateway. +1
Leonid Usov

-1

"Fiiller kötü" sorununu basit bir yeniden adlandırma ile çözebilirsiniz - "sync" yerine "güncellemeler" kullanın.

Senkronizasyon işlemi aslında son senkronizasyondan bu yana yapılan yerel güncellemelerin bir listesini gönderiyor ve aynı zamanda sunucuda yapılan güncellemelerin bir listesini alıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.