İstemci-sunucu senkronizasyon modeli / algoritması?


224

Orada istemci-sunucu eşitleme desenleri olması gerektiğini hissediyorum. Ama ben tamamen bir google başarısız oldu.

Durum oldukça basittir - sunucu, birden çok istemcinin aynı verilere bağlandığı ve bunları değiştirdiği merkezi düğümdür. Veriler atomlar halinde bölünebilir, çakışma durumunda, sunucuda ne varsa, önceliği vardır (kullanıcının çakışma çözmesine engel olmak için). Potansiyel olarak büyük miktarda veri nedeniyle kısmi senkronizasyon tercih edilir.

Böyle bir durum için herhangi bir kalıp / iyi uygulama var mı veya hiç bilmiyorsanız - yaklaşımınız ne olurdu?

Aşağıda nasıl çözmeyi düşündüğümü aşağıda bulabilirsiniz: Verilere paralel olarak, tüm işlemlerin zaman damgalı bir değişiklik günlüğü yapılacaktır. İstemci bağlandığında, son kontrolden bu yana yapılan tüm değişiklikleri birleştirilmiş biçimde alır (sunucu listelerden geçer ve ardından silme işleminden sonra yapılan eklemeleri kaldırır, her atom için güncellemeleri birleştirir, vb.). Et voila, günceliz.

Alternatif olarak, her kayıt için değişiklik tarihi saklanır ve veri silme işlemi yerine bunları silinmiş olarak işaretler.

Düşüncesi olan var mı?


27
Bu senaryo oldukça yaygın olmasına rağmen, bu tür şeyler için çok az desen konuşulduğu konusunda anlaştılar
Jack Ukleja

Yanıtlar:


88

Dağıtılmış değişiklik yönetiminin nasıl çalıştığına bakmalısınız. Delta çalışmalarını yöneten SVN, CVS ve diğer depolara bakın.

Birkaç kullanım vakanız var.

  • Değişiklikleri senkronize edin. Değişiklik günlüğü (veya delta geçmişiniz) yaklaşımınız bunun için iyi görünüyor. İstemciler deltalarını sunucuya gönderir; server deltaları birleştirir ve istemcilere dağıtır. Bu tipik bir durum. Veritabanları bu "işlem çoğaltması" olarak adlandırılır.

  • İstemci senkronizasyonu kaybetti. Yedekleme / geri yükleme veya hata nedeniyle. Bu durumda, istemcinin geçerli durumu deltalardan geçmeden sunucudan alması gerekir. Bu, master'dan detay, delta ve performansa bir kopyadır. Bu bir defalık bir şey; müşteri bozuldu; Bunu optimize etmeye çalışmayın, sadece güvenilir bir kopya uygulayın.

  • Müşteri şüpheli. Bu durumda, istemcinin güncel olup olmadığını ve herhangi bir deltaya ihtiyacı olup olmadığını belirlemek için istemciyi sunucu ile karşılaştırmanız gerekir.

Her değişikliği sırayla numaralandıran veritabanı (ve SVN) tasarım desenini izlemelisiniz. Bu şekilde, bir istemci senkronize etmeyi denemeden önce önemsiz bir istekte bulunabilir ("Hangi düzeltmeyi yapmalıyım?"). Ve o zaman bile, sorgu ("2149'dan beri tüm deltalar") istemci ve sunucunun işlemesi için son derece basittir.


Bir deltanın tam olarak ne olduğunu açıklayabilir misiniz? Benim tahminim bu bir karma / zaman damgası kombinasyonu ... Ben sizden duymak istiyorum efendim.
Anis

Bir delta, iki düzeltme arasındaki değişikliği ifade eder. Örneğin, bir kullanıcının adı değiştiyse, delta {revizyon: 123, ad: "John Doe"}
dipole_moment

31

Ekibin bir parçası olarak, veri senkronizasyonu içeren birçok proje yaptım, bu yüzden bu soruya cevap vermeye yetkin olmalıyım.

Veri senkronizasyonu oldukça geniş bir kavramdır ve tartışılması gereken çok şey vardır. Üst ve alt yanları ile bir dizi farklı yaklaşımı kapsar. İki perspektife dayanan olası sınıflandırmalardan biri şunlardır: Senkron / Asenkron, İstemci / Sunucu / Eşler Arası. Senkronizasyon uygulaması bu faktörlere, veri modeli karmaşıklığına, aktarılan ve depolanan veri miktarına ve diğer gereksinimlere bağlıdır. Yani her özel durumda seçim, uygulama gereksinimlerini karşılayan en basit uygulama lehine olmalıdır.

Mevcut kullanıma hazır çözümlerin bir incelemesine dayanarak, senkronizasyona tabi nesnelerin ayrıntı düzeylerinden farklı olarak birkaç ana senkronizasyon sınıfını tanımlayabiliriz:

  • Bir belgenin veya veritabanının tamamının senkronizasyonu, Dropbox, Google Drive veya Yandex.Disk gibi bulut tabanlı uygulamalarda kullanılır. Kullanıcı bir dosyayı düzenleyip kaydettiğinde, yeni dosya sürümü buluta tamamen yüklenerek önceki kopyanın üzerine yazılır. Bir çakışma durumunda, kullanıcının hangi sürümün daha alakalı olacağını seçebilmesi için her iki dosya sürümü de kaydedilir.
  • Anahtar / değer çiftlerinin senkronizasyonu, değişkenlerin atomik olduğu, yani mantıksal bileşenlere bölünmediği basit bir veri yapısına sahip uygulamalarda kullanılabilir. Bu seçenek, hem değerin hem de belgenin üzerine tamamen yazılabileceğinden, tüm belgelerin senkronizasyonuna benzer. Bununla birlikte, kullanıcı bakış açısından, bir belge birçok bölümden oluşan karmaşık bir nesnedir, ancak bir anahtar / değer çifti kısa bir dize veya sayıdır. Bu nedenle, bu durumda, değişimin sonuncusu olsaydı daha alakalı değeri göz önüne alarak daha basit bir çatışma çözümü stratejisi kullanabiliriz.
  • Bir ağaç veya grafik olarak yapılandırılan verilerin senkronizasyonu, veri miktarının her güncellemede veritabanını bütünüyle göndermek için yeterince büyük olduğu daha karmaşık uygulamalarda kullanılır. Bu durumda, çatışmaların tek tek nesneler, alanlar veya ilişkiler düzeyinde çözülmesi gerekir. Öncelikle bu seçeneğe odaklanıyoruz.

Bu yüzden, bilgimizi Çekirdek Veri Tabanlı iOS uygulamalarında Veri Senkronizasyonu ile ilgilenen herkes için çok yararlı olabileceğini düşündüğüm bu makaleye aldık ( http://blog.denivip.ru/index.php/2014/04 / çekirdek veri tabanlı veri senkronizasyonu-ios-apps /? lang = tr )


3
^ ^ ^ ^ ^ ^ Bu açık ara en iyi cevap, çocuklar!
hgoebl

Kabul ediyorum, Denis konuya çok şey getirdi + makale linkleri harika. Ayrıca DanielPaull tarafından bahsedilen OT hakkında konuşuyor. S.Lott tarafından cevap iyi ama bu çok daha derinlemesine.
Krystian

28

Gerçekten ihtiyacınız olan şey Operasyonel Dönüşümdür (OT). Bu, birçok durumda çatışmaları bile karşılayabilir.

Bu hala aktif bir araştırma alanıdır, ancak etrafında çeşitli OT algoritmalarının uygulamaları vardır. Birkaç yıldır böyle bir araştırmaya katıldım, bu yüzden bu rotanın ilginizi çekip çekmediğini bize bildirin, sizi ilgili kaynaklara sunmaktan mutluluk duyarım.


7
Daniel, ilgili kaynaklara bir işaretçi takdir edilecektir.
Parand 25.05.2018

4
Wikipedia makalesini tekrar okudum. Uzun bir yol kat etti ve sayfanın alt kısmında alakalı birçok referans var. Seni Chengzheng Sun'un çalışmalarına işaret ederdim - eserine wikipedia'dan atıfta bulunulur. en.wikipedia.org/wiki/Operational_transformation . Umarım yardımcı olur!
Daniel Paull

13

Soru çok net değil, ama ben olsaydım iyimser kilitlemeye bakardım . Sunucunun her kayıt için döndürdüğü bir sıra numarası ile uygulanabilir. İstemci kaydı geri kaydetmeye çalıştığında, sunucudan aldığı sıra numarasını içerecektir. Sıra numarası, güncellemenin alındığı sırada veritabanında bulunanlarla eşleşiyorsa, güncelleştirmeye izin verilir ve sıra numarası artırılır. Sıra numaraları eşleşmezse, güncellemeye izin verilmez.


2
Sıra numaraları burada arkadaşınızdır. Kalıcı mesaj kuyruklarını düşünün.
Daniel Paull

7

Yaklaşık 8 yıl önce bir uygulama için böyle bir sistem oluşturdum ve uygulama kullanımı arttıkça evrimleştiği birkaç yolu paylaşabilirim.

Herhangi bir cihazdaki her değişikliği (ekleme, güncelleme veya silme) "geçmiş" tablosuna kaydederek başladım. Örneğin, birisi "kişi" tablosundaki telefon numarasını değiştirirse, sistem contact.phone alanını düzenler ve ayrıca action = update, field = phone, record = [kişi kimliği], değer = [yeni telefon numarası]. Daha sonra bir cihaz her senkronize edildiğinde, son senkronizasyondan bu yana geçmiş öğelerini indirir ve bunları yerel veritabanına uygular. Bu, yukarıda açıklanan "işlem çoğaltma" düzeni gibi görünür.

Bir sorun, öğeler farklı cihazlarda oluşturulabildiğinde kimlikleri benzersiz tutmaktır. Bunu başlattığımda UUID'leri bilmiyordum, bu yüzden otomatik artan kimlikleri kullandım ve cihazlardan yüklenen yeni kimlikleri kontrol etmek, bir çakışma varsa benzersiz bir kimliğe değiştirmek için merkezi sunucuda çalışan kıvrımlı bir kod yazdım ve kaynak aygıta yerel veritabanındaki kimliği değiştirmesini söyleyin. Sadece yeni kayıtların kimliklerini değiştirmek o kadar da kötü değildi, ancak örneğin, kişi tablosunda yeni bir öğe oluşturursam, olay tablosunda yeni bir ilgili öğe oluşturursam, şimdi de ihtiyacım olan yabancı anahtarlarım var kontrol edin ve güncelleyin.

Sonunda UUID'lerin bundan kaçınabileceğini öğrendim, ancak o zamana kadar veritabanım oldukça genişledi ve tam bir UUID uygulamasının bir performans sorunu yaratacağından korktum. Bu yüzden tam UUID'leri kullanmak yerine, kimlik olarak rastgele oluşturulmuş 8 karakterli alfasayısal anahtarları kullanmaya başladım ve çakışmaları çözmek için mevcut kodumu yerinde bıraktım. Mevcut 8 karakterli anahtarlarım ve bir UUID'nin 36 karakteri arasında bir yerde, gereksiz şişkinlik olmadan çatışmaları ortadan kaldıracak tatlı bir nokta olmalı, ancak zaten çatışma çözümleme koduna sahip olduğum için, bunu denemek bir öncelik değildi .

Sonraki sorun, geçmiş tablosunun veritabanının geri kalanından yaklaşık 10 kat daha büyük olmasıydı. Bu, depolamayı pahalı hale getirir ve geçmiş tablosundaki herhangi bir bakım acı verici olabilir. Bu tablonun tamamını tutmak, kullanıcıların önceki değişiklikleri geri almasına izin verir, ancak bu aşırı doldurma gibi hissetmeye başlar. Bu yüzden senkronizasyon işlemine bir rutin ekledim; burada bir cihazın en son indirildiği geçmiş öğesi artık geçmiş tablosunda yoksa, sunucu ona son geçmiş öğelerini vermez, bunun yerine tüm verileri içeren bir dosya verir. o hesap. Sonra 90 günden eski tarih öğelerini silmek için bir cronjob ekledim. Bu, kullanıcıların 90 günden daha eski değişiklikleri geri alabilecekleri anlamına gelir ve en az 90 günde bir senkronizasyon yaparlarsa, güncellemeler önceki gibi artırılır. Fakat 90 günden uzun beklerse,

Bu değişiklik, geçmiş tablosunun boyutunu neredeyse% 90 oranında azalttı, bu nedenle artık geçmiş tablosunu korumak, veritabanını on kat daha büyük değil, yalnızca iki kat büyütüyor. Bu sistemin bir başka avantajı da senkronizasyonun gerekirse geçmiş tablosu olmadan da çalışabilmesidir - geçici olarak çevrimdışı alan bazı bakımları yapmam gerekiyormuş gibi. Veya farklı fiyat noktalarındaki hesaplar için farklı geri alma süreleri sunabilirim. Ve indirilecek 90 günden fazla değişiklik varsa, tam dosya genellikle artımlı formattan daha verimlidir.

Bugün başlamış olsaydım, kimlik çakışması kontrolünü atlardım ve her ihtimale karşı bir tür hata kontrolü ile çatışmaları ortadan kaldırmak için yeterli bir anahtar uzunluğunu hedeflerdim. Ancak geçmiş tablosu ve son güncellemeler için artımlı indirmelerin veya gerektiğinde tam indirmenin kombinasyonu iyi çalışıyor.


1

Delta (değişiklik) senkronizasyonu için, değişiklikleri abone olan tüm istemcilere geri yayınlamak için pubsub desenini kullanabilirsiniz, itici gibi hizmetler bunu yapabilir.

Veritabanı yansıması için, bazı web çerçeveleri sunucu tarafı veritabanını tarayıcı veritabanındaki yerel ile eşitlemek için yerel bir mini veritabanı kullanır, kısmi eşitleme desteklenir. Metreyi kontrol edin .

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.