Pierwszą rzeczą, którą musisz zdecydować, jest ogólna polityka dotycząca tego, która strona jest uważana za „autorytatywną” w przypadku sprzecznych zmian.
To znaczy: załóżmy, że rekord # 125 jest zmieniany na serwerze 5 stycznia o godzinie 22:00, a ten sam rekord jest zmieniany na jednym z telefonów (nazwijmy go Klientem A) 5 stycznia o godzinie 23:00. Ostatnia synchronizacja miała miejsce 3 stycznia. Następnie użytkownik łączy się ponownie, powiedzmy 8 stycznia.
Zidentyfikowanie tego, co należy zmienić, jest „łatwe” w tym sensie, że zarówno klient, jak i serwer znają datę ostatniej synchronizacji, więc wszystko, co zostało utworzone lub zaktualizowane (więcej informacji na ten temat poniżej) od ostatniej synchronizacji, musi zostać uzgodnione.
Załóżmy więc, że jedyny zmieniony rekord to # 125. Możesz zdecydować, że jedna z dwóch automatycznie „wygrywa” i nadpisuje drugą, albo musisz obsługiwać fazę uzgadniania, w której użytkownik może zdecydować, która wersja (serwer lub klient) jest właściwa, nadpisując drugą.
Ta decyzja jest niezwykle ważna i trzeba wyważyć „rolę” klientów. Zwłaszcza jeśli istnieje potencjalny konflikt nie tylko między klientem a serwerem, ale w przypadku, gdy różni klienci mogą zmienić te same rekordy.
[Zakładając, że numer 125 może zostać zmodyfikowany przez drugiego klienta (klienta B), istnieje szansa, że klient B, który nie został jeszcze zsynchronizowany, dostarczy kolejną wersję tego samego rekordu, co spowoduje, że poprzednie rozwiązanie konfliktu będzie dyskusyjne]
Odnośnie do punktu „ utworzonego lub zaktualizowanego ” powyżej ... jak można prawidłowo zidentyfikować rekord, jeśli został on utworzony na jednym z klientów (zakładając, że ma to sens w domenie, w której występuje problem)? Załóżmy, że Twoja aplikacja zarządza listą kontaktów biznesowych. Jeśli Klient A mówi, że musisz dodać nowo utworzonego Johna Smitha, a serwer ma John Smith utworzony wczoraj przez Klienta D… czy tworzysz dwa rekordy, ponieważ nie możesz być pewien, że nie są to różne osoby? Czy poprosisz użytkownika również o pogodzenie tego konfliktu?
Czy klienci mają „własność” podzbioru danych? To znaczy, jeśli Klient B jest ustawiony jako „organ” w zakresie danych dla Obszaru 5, czy Klient A może modyfikować / tworzyć rekordy dla Obszaru 5, czy nie? (Ułatwiłoby to niektóre konflikty, ale może okazać się niewykonalne w twojej sytuacji).
Podsumowując, główne problemy to:
- Jak zdefiniować „tożsamość”, biorąc pod uwagę, że odłączeni klienci mogli nie uzyskać dostępu do serwera przed utworzeniem nowego rekordu.
- Poprzednia sytuacja, bez względu na to, jak skomplikowane jest rozwiązanie, może skutkować duplikacją danych, więc musisz przewidzieć, jak okresowo je rozwiązywać i jak informować klientów, że to, co uważali za „Rekord nr 675”, zostało faktycznie połączone z / zastąpione przez Rekord # 543
- Zdecyduj, czy konflikty zostaną rozwiązane przez fiat (np. „Wersja serwera zawsze ma pierwszeństwo przed wersją klienta, jeśli poprzednia została zaktualizowana od czasu ostatniej synchronizacji”) lub przez interwencję ręczną
- W przypadku fiat , zwłaszcza jeśli uznasz, że klient ma pierwszeństwo, musisz również zadbać o to, jak radzić sobie z innymi, jeszcze niezsynchronizowanymi klientami, którzy mogą mieć więcej zmian.
- Poprzednie pozycje nie uwzględniają szczegółowości danych (w celu ułatwienia opisu). Wystarczy powiedzieć, że zamiast rozumowania na poziomie „rekordu”, jak w moim przykładzie, bardziej odpowiednie może być zapisanie zmian na poziomie pola. Lub pracować na zbiorze rekordów (np. Rekord osoby + rekord adresu + rekord kontaktów) w tym samym czasie, traktując ich agregat jako rodzaj „meta rekordu”.
Bibliografia:
Więcej na ten temat oczywiście w Wikipedii .
Prosty algorytm synchronizacji autorstwa autora Vdirsyncer
Artykuł OBJC dotyczący synchronizacji danych
SyncML®: synchronizacja i zarządzanie danymi mobilnymi ( zarezerwuj na O'Reilly Safari)
Wolne od kon iktów replikowane typy danych
Optymistyczna replikacja YASUSHI SAITO (HP Laboratories) i MARC SHAPIRO (Microsoft Research Ltd.) - ACM Computing Surveys, Vol. V, nr N, 3 2005.
Alexander Traud, Juergen Nagler-Ihlein, Frank Kargl i Michael Weber. 2008. Cykliczna synchronizacja danych poprzez ponowne użycie SyncML. W obradach dziewiątej międzynarodowej konferencji nt. Mobilnego zarządzania danymi (MDM '08). IEEE Computer Society, Washington, DC, USA, 165-172. DOI = 10.1109 / MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.10
Lam, F., Lam, N. i Wong, R. 2002. Efektywna synchronizacja mobilnych danych XML. W materiałach z jedenastej międzynarodowej konferencji nt. Informacji i zarządzania wiedzą (McLean, Virginia, USA, 04 - 09 listopada 2002). CIKM '02. ACM, Nowy Jork, NY, 153–160. DOI = http://doi.acm.org/10.1145/584792.584820
Cunha, PR i Maibaum, TS 1981. Resource & equil; abstrakcyjny typ danych + synchronizacja - Metodologia programowania zorientowanego na komunikaty -. W materiałach z V Międzynarodowej Konferencji Inżynierii Oprogramowania (San Diego, Kalifornia, Stany Zjednoczone, 9-12 marca 1981). Międzynarodowa konferencja nt. Inżynierii oprogramowania. IEEE Press, Piscataway, NJ, 263-272.
(Ostatnie trzy pochodzą z biblioteki cyfrowej ACM, nie mam pojęcia, czy jesteś jej członkiem lub czy możesz je zdobyć za pośrednictwem innych kanałów).
Z witryny Dr.Dobbs :
- Tworzenie aplikacji za pomocą SQL Server CE i SQL RDA - Bill Wagner 19 maja 2004 (Najlepsze praktyki projektowania aplikacji na komputer stacjonarny i komputer przenośny - Windows / .NET)
Z arxiv.org:
- A Conflict-Free Replicated JSON Datatype - artykuł opisuje implementację JSON CRDT (bezkonfliktowe replikowane typy danych - CRDT - to rodzina struktur danych, które obsługują równoczesną modyfikację i gwarantują konwergencję takich równoległych aktualizacji).
Zalecałbym, aby w każdej tabeli znajdowała się kolumna sygnatury czasowej i za każdym razem, gdy wstawiasz lub aktualizujesz, aktualizuj wartość sygnatury czasowej każdego wiersza, którego dotyczy problem. Następnie iterujesz po wszystkich tabelach, sprawdzając, czy sygnatura czasowa jest nowsza niż ta, którą masz w docelowej bazie danych. Jeśli jest nowszy, sprawdź, czy musisz go wstawić lub zaktualizować.
Uwaga 1: pamiętaj o fizycznym usuwaniu, ponieważ wiersze są usuwane ze źródłowej bazy danych i musisz zrobić to samo w bazie danych serwera. Możesz rozwiązać ten problem, unikając fizycznego usuwania lub rejestrowania każdego usunięcia w tabeli z sygnaturami czasowymi. Coś takiego:
DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)
Więc musisz przeczytać wszystkie nowe wiersze tabeli DeletedRows i wykonać usuwanie na serwerze używając nazwa_tabeli, pk_column i pk_column_value.Uwaga 2: bądź świadomy FK, ponieważ wstawianie danych do tabeli, która jest powiązana z inną tabelą, może się nie powieść. Przed synchronizacją danych należy dezaktywować każdy FK.
źródło
Jeśli ktoś ma do czynienia z podobnym problemem projektowym i musi zsynchronizować zmiany na wielu urządzeniach z Androidem, polecam sprawdzenie Google Cloud Messaging dla Androida (GCM).
Pracuję nad jednym rozwiązaniem, w którym zmiany wprowadzone na jednym kliencie muszą być propagowane do innych klientów. Właśnie zaimplementowałem dowód implementacji koncepcji (serwer i klient) i działa to jak marzenie.
Zasadniczo każdy klient wysyła zmiany delta do serwera. Np. Identyfikator zasobu ABCD1234 zmienił się z wartości 100 na 99.
Serwer sprawdza poprawność tych zmian w swojej bazie danych i albo zatwierdza zmianę (klient jest zsynchronizowany) i aktualizuje swoją bazę danych, albo odrzuca zmianę (klient nie jest zsynchronizowany).
Jeśli zmiana zostanie zatwierdzona przez serwer, serwer powiadamia następnie innych klientów (z wyjątkiem tego, który wysłał zmianę delta) za pośrednictwem GCM i wysyła wiadomość multiemisji zawierającą tę samą zmianę delta. Klienci przetwarzają tę wiadomość i aktualizują swoją bazę danych.
Fajne jest to, że te zmiany rozprzestrzeniają się niemal natychmiastowo !!! jeśli te urządzenia są w trybie online. I nie muszę implementować żadnego mechanizmu odpytywania na tych klientach.
Pamiętaj, że jeśli urządzenie jest zbyt długo w trybie offline, a w kolejce GCM czeka na dostarczenie ponad 100 wiadomości, GCM odrzuci te wiadomości i wyśle specjalną wiadomość, gdy urządzenie wróci do trybu online. W takim przypadku klient musi wykonać pełną synchronizację z serwerem.
Zapoznaj się również z tym samouczkiem, aby rozpocząć wdrażanie klienta CGM.
źródło
to odpowiada deweloperom korzystającym z platformy Xamarin (zobacz /programming/40156342/sync-online-offline-data )
Bardzo prostym sposobem osiągnięcia tego za pomocą platformy Xamarin jest użycie synchronizacji danych w trybie offline platformy Azure, ponieważ umożliwia ona wypychanie i pobieranie danych z serwera na żądanie. Operacje odczytu są wykonywane lokalnie, a operacje zapisu są wypychane na żądanie; W przypadku zerwania połączenia sieciowego operacje zapisu są umieszczane w kolejce do momentu przywrócenia połączenia, a następnie wykonywane.
Wdrożenie jest dość proste:
1) Stwórz aplikację mobilną w portalu Azure (możesz wypróbować ją bezpłatnie tutaj https://tryappservice.azure.com/ )
2) połącz swojego klienta z aplikacją mobilną. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/
3) kod do konfiguracji lokalnego repozytorium:
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) następnie wypchnąć i pobrać dane, aby upewnić się, że mamy najnowsze zmiany:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/
źródło
Proponuję również przyjrzeć się Symmetricds . jest to biblioteka replikacji SQLite dostępna dla systemów Android. możesz go użyć do zsynchronizowania bazy danych klienta i serwera, proponuję również mieć osobne bazy danych na serwerze dla każdego klienta. Próba przechowywania danych wszystkich użytkowników w jednej bazie danych mysql nie zawsze jest najlepszym pomysłem. Szczególnie jeśli dane użytkowników będą szybko rosły.
źródło
Nazwijmy to CUDR Sync problemem (nie lubię CRUD - ponieważ Create / Update / Delete to zapisy i powinny być sparowane razem)
Problem może być również rozpatrywany w trybie odpisywania w trybie offline lub najpierw zapisu online . Podejście do zapisu w trybie offline ma problem z konfliktem unikalnych identyfikatorów, a także z wieloma wywołaniami sieciowymi dla tej samej transakcji, co zwiększa ryzyko (lub koszty) ...
Osobiście uważam, że podejście polegające na pisaniu online jest łatwiejsze w zarządzaniu (więc będzie to jedyne źródło prawdy - skąd wszystko inne jest synchronizowane). Podejście do zapisu online będzie wymagało, aby użytkownicy nie mogli najpierw pisać offline - będą pisać w trybie offline, otrzymując poprawną odpowiedź z formularza online.
Może najpierw czytać offline, a gdy tylko sieć będzie dostępna, pobrać dane z online i zaktualizować lokalną bazę danych, a następnie zaktualizować interfejs użytkownika ...
Jednym ze sposobów uniknięcia konfliktu unikatowych identyfikatorów byłoby użycie kombinacji unikalnego identyfikatora użytkownika + nazwy tabeli lub identyfikatora tabeli + identyfikatora wiersza (wygenerowanego przez sqlite) ... a następnie użycie z nią zsynchronizowanej kolumny flagi logicznej ... ale nadal rejestrację należy najpierw przeprowadzić online, aby uzyskać unikalny identyfikator, na którym zostaną wygenerowane wszystkie inne identyfikatory ... tutaj problem będzie również występował, jeśli zegary nie są zsynchronizowane - o czym ktoś wspomniany powyżej ...
źródło