Đồng bộ hóa cơ sở dữ liệu máy khách-máy chủ


82

Tôi đang tìm kiếm một số chiến lược chung để đồng bộ hóa dữ liệu trên máy chủ trung tâm với các ứng dụng khách không phải lúc nào cũng trực tuyến.

Trong trường hợp cụ thể của tôi, tôi có một ứng dụng điện thoại Android với cơ sở dữ liệu sqlite và một ứng dụng web PHP với cơ sở dữ liệu MySQL.

Người dùng sẽ có thể thêm và chỉnh sửa thông tin trên ứng dụng điện thoại và trên ứng dụng web. Tôi cần đảm bảo rằng các thay đổi được thực hiện ở một nơi được phản ánh ở mọi nơi ngay cả khi điện thoại không thể liên lạc ngay với máy chủ.

Tôi không quan tâm đến việc làm thế nào để chuyển dữ liệu từ điện thoại đến máy chủ hoặc ngược lại. Tôi đang đề cập đến các công nghệ cụ thể của mình chỉ vì tôi không thể sử dụng, ví dụ, các tính năng sao chép có sẵn cho MySQL.

Tôi biết rằng sự cố đồng bộ hóa dữ liệu máy khách-máy chủ đã xảy ra từ rất lâu và tôi muốn có thông tin - bài báo, sách, lời khuyên, v.v. - về các mẫu để xử lý sự cố. Tôi muốn biết về các chiến lược chung để giải quyết vấn đề đồng bộ hóa để so sánh điểm mạnh, điểm yếu và sự đánh đổi.

Câu trả lời:


93

Điều đầu tiên bạn phải quyết định là một chính sách chung về việc bên nào được coi là "có thẩm quyền" trong trường hợp có những thay đổi mâu thuẫn.

Tức là: giả sử Bản ghi số 125 được thay đổi trên máy chủ vào 10 giờ tối ngày 5 tháng 1 và bản ghi tương tự được thay đổi trên một trong các điện thoại (hãy gọi là Máy khách A) vào lúc 11 giờ đêm ngày 5 tháng 1. Lần đồng bộ cuối cùng là vào ngày 3 tháng 1. Sau đó, người dùng kết nối lại vào ngày 8 tháng 1.

Việc xác định những gì cần thay đổi là "dễ dàng" theo nghĩa là cả máy khách và máy chủ đều biết ngày của đồng bộ cuối cùng, vì vậy bất kỳ thứ gì được tạo hoặc cập nhật (xem bên dưới để biết thêm về điều này) kể từ đồng bộ cuối cùng cần được điều chỉnh.

Vì vậy, giả sử rằng bản ghi được thay đổi duy nhất là # 125. Bạn có thể quyết định rằng một trong hai phiên bản tự động "thắng" và ghi đè phiên bản kia hoặc bạn cần hỗ trợ giai đoạn điều hòa trong đó người dùng có thể quyết định phiên bản nào (máy chủ hoặc máy khách) là phiên bản chính xác, ghi đè phiên bản còn lại.

Quyết định này là cực kỳ quan trọng và bạn phải cân nhắc "vai trò" của khách hàng. Đặc biệt nếu có xung đột tiềm ẩn không chỉ giữa máy khách và máy chủ, mà trong trường hợp các máy khách khác nhau có thể thay đổi (các) bản ghi giống nhau.

[Giả sử rằng # 125 có thể được sửa đổi bởi một ứng dụng khách thứ hai (Ứng dụng khách B) thì có khả năng là Ứng dụng khách B, chưa được đồng bộ hóa, sẽ cung cấp một phiên bản khác của cùng một bản ghi, khiến cho việc giải quyết xung đột trước đó trở nên sôi nổi]

Về điểm " đã tạo hoặc cập nhật " ở trên ... làm cách nào bạn có thể xác định đúng một bản ghi nếu nó được bắt nguồn từ một trong các ứng dụng khách (giả sử điều này có ý nghĩa trong miền sự cố của bạn)? Giả sử ứng dụng của bạn quản lý một danh sách các liên hệ công việc. Nếu Khách hàng A nói rằng bạn phải thêm một John Smith mới được tạo và máy chủ có một John Smith được tạo ngày hôm qua bởi Khách hàng D ... bạn có tạo hai bản ghi vì bạn không thể chắc chắn rằng chúng không phải là những người khác nhau? Bạn sẽ yêu cầu người dùng hòa giải xung đột này chứ?

Khách hàng có "quyền sở hữu" một tập hợp con dữ liệu không? Tức là nếu Khách hàng B được thiết lập để trở thành "thẩm quyền" về dữ liệu cho Khu vực số 5 thì Khách hàng A có thể sửa đổi / tạo bản ghi cho Khu vực số 5 hay không? (Điều này sẽ giúp giải quyết xung đột dễ dàng hơn, nhưng có thể không khả thi đối với tình huống của bạn).

Tóm lại, các vấn đề chính là:

  • Cách xác định "danh tính" khi xem xét rằng các máy khách tách rời có thể không truy cập vào máy chủ trước khi tạo bản ghi mới.
  • Tình huống trước đó, bất kể giải pháp phức tạp đến đâu, có thể dẫn đến việc trùng lặp dữ liệu, vì vậy bạn phải thấy trước cách giải quyết các vấn đề này theo định kỳ và cách thông báo cho khách hàng rằng những gì họ coi là "Bản ghi # 675" đã thực sự được hợp nhất với / thay thế bởi Bản ghi # 543
  • Quyết định xem xung đột sẽ được giải quyết bằng fiat (ví dụ: "Phiên bản máy chủ luôn chiếm ưu thế của máy khách nếu phiên bản cũ đã được cập nhật kể từ lần đồng bộ cuối cùng") hoặc bằng cách can thiệp thủ công
  • Trong trường hợp fiat , đặc biệt nếu bạn quyết định rằng ứng dụng khách được ưu tiên, bạn cũng phải quan tâm đến cách đối phó với các ứng dụng khách khác, chưa được đồng bộ hóa có thể có một số thay đổi sắp tới.
  • Các mục trước đây không tính đến mức độ chi tiết của dữ liệu của bạn (để làm cho mọi thứ đơn giản hơn để mô tả). Chỉ cần nói rằng thay vì lập luận ở cấp "Bản ghi", như trong ví dụ của tôi, bạn có thể thấy thích hợp hơn để ghi lại sự thay đổi ở cấp trường. Hoặc để làm việc trên một tập hợp các bản ghi (ví dụ: Bản ghi cá nhân + Bản ghi địa chỉ + Bản ghi danh bạ) tại một thời điểm coi tổng hợp của chúng như một loại "Bản ghi Meta".

Thư mục:

(Ba mục cuối cùng là từ thư viện kỹ thuật số ACM, không biết bạn có phải là thành viên hay không hay bạn có thể lấy chúng qua các kênh khác).

Từ trang Dr.Dobbs :

  • Tạo ứng dụng với SQL Server CE và SQL RDA bởi Bill Wagner ngày 19 tháng 5 năm 2004 (Các phương pháp hay nhất để thiết kế ứng dụng cho cả máy tính để bàn và máy tính di động - Windows / .NET)

Từ arxiv.org:

  • Loại dữ liệu JSON được sao chép không có xung đột - bài báo mô tả việc triển khai JSON CRDT (Các kiểu dữ liệu được sao chép không có xung đột - CRDT - là một họ cấu trúc dữ liệu hỗ trợ sửa đổi đồng thời và đảm bảo sự hội tụ của các bản cập nhật đồng thời như vậy).

Cảm ơn về câu trả lời của bạn. Tôi rất muốn đọc về các giải pháp thường được sử dụng / khả thi (ưu, nhược điểm, so sánh) cho các vấn đề bạn phác thảo.
Scott Saunders

Tôi cho rằng bạn đã kiểm tra Wikipedia và những thứ họ liên kết đến, phải không?
p.marino

3
+1 Đây là một bài đăng tuyệt vời với thông tin rất quan trọng về vấn đề đó. Một điểm còn thiếu: đồng bộ hóa các bản ghi đã xóa.
Stefan Steinegger

7
Tôi có xu hướng coi "đã xóa" là một trường hợp đặc biệt của "đã cập nhật", đặc biệt là vì đối với loại tình huống này, tôi có xu hướng ủng hộ "xóa logic" thay vì "xóa vật lý". Vì vậy, đối với tôi "đã xóa" ở phía chủ hoặc phía nô lệ có nghĩa là "cờ boolean bị xóa đặc biệt đã bị lật" hơn bất cứ điều gì khác.
p.marino

Cảm ơn. Tôi đã thêm một liên kết nữa đến một bài viết khác (dr.dobbs) và sẽ cập nhật thư mục nếu tôi có thể tìm thấy thứ khác.
p.marino

9

Tôi khuyên bạn nên có một cột dấu thời gian trong mỗi bảng và mỗi khi bạn chèn hoặc cập nhật, hãy cập nhật giá trị dấu thời gian của mỗi hàng bị ảnh hưởng. Sau đó, bạn lặp lại tất cả các bảng để kiểm tra xem dấu thời gian có mới hơn dấu thời gian bạn có trong cơ sở dữ liệu đích hay không. Nếu nó mới hơn, hãy kiểm tra xem bạn có phải chèn hoặc cập nhật hay không.

Quan sát 1: lưu ý về việc xóa vật lý vì các hàng bị xóa khỏi nguồn db và bạn phải thực hiện tương tự tại máy chủ db. Bạn có thể giải quyết vấn đề này bằng cách tránh xóa vật lý hoặc ghi lại mọi lần xóa trong một bảng có dấu thời gian. Một cái gì đó như thế này: DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)Vì vậy, bạn phải đọc tất cả các hàng mới của bảng DeletedRows và thực hiện xóa tại máy chủ bằng cách sử dụng table_name, pk_column và pk_column_value.

Quan sát 2: lưu ý về FK vì việc chèn dữ liệu vào bảng liên quan đến bảng khác có thể không thành công. Bạn nên hủy kích hoạt mọi FK trước khi đồng bộ hóa dữ liệu.


3
đồng hồ phải được đồng bộ
tofutim

6

Nếu bất kỳ ai đang gặp vấn đề về thiết kế tương tự và cần đồng bộ hóa các thay đổi trên nhiều thiết bị Android, tôi khuyên bạn nên kiểm tra Google Cloud Messaging dành cho Android (GCM).

Tôi đang làm việc trên một giải pháp trong đó các thay đổi được thực hiện trên một ứng dụng khách phải được phổ biến cho các khách hàng khác. Và tôi vừa triển khai một bằng chứng về việc triển khai khái niệm (máy chủ & máy khách) và nó hoạt động như một sự quyến rũ.

Về cơ bản, mỗi máy khách sẽ gửi các thay đổi delta đến máy chủ. Ví dụ: id tài nguyên ABCD1234 đã thay đổi từ giá trị 100 thành 99.

Máy chủ xác nhận các thay đổi delta này dựa trên cơ sở dữ liệu của nó và chấp thuận thay đổi (máy khách đang đồng bộ) và cập nhật cơ sở dữ liệu của nó hoặc từ chối thay đổi (máy khách không đồng bộ).

Nếu thay đổi được máy chủ chấp thuận, thì máy chủ sẽ thông báo cho các máy khách khác (ngoại trừ người đã gửi thay đổi delta) qua GCM và gửi tin nhắn multicast mang cùng một thay đổi delta. Khách hàng xử lý thông báo này và cập nhật cơ sở dữ liệu của họ.

Điều thú vị là những thay đổi này được lan truyền gần như ngay lập tức !!! nếu các thiết bị đó trực tuyến. Và tôi không cần thực hiện bất kỳ cơ chế bỏ phiếu nào trên những khách hàng đó.

Lưu ý rằng nếu một thiết bị ngoại tuyến quá lâu và có hơn 100 tin nhắn đang chờ gửi trong hàng đợi GCM, GCM sẽ hủy tin nhắn đó và sẽ gửi một tin nhắn đặc biệt khi thiết bị trực tuyến trở lại. Trong trường hợp đó, máy khách phải đồng bộ hoàn toàn với máy chủ.

Ngoài ra, hãy xem hướng dẫn này để bắt đầu triển khai ứng dụng khách CGM.


5

điều này trả lời cho các nhà phát triển đang sử dụng khung Xamarin (xem /programming/40156342/sync-online-offline-data )

Một cách rất đơn giản để đạt được điều này với khuôn khổ xamarin là sử dụng Đồng bộ hóa dữ liệu ngoại tuyến của Azure vì nó cho phép đẩy và kéo dữ liệu từ máy chủ theo yêu cầu. Các hoạt động đọc được thực hiện cục bộ và các hoạt động ghi được đẩy theo yêu cầu; Nếu kết nối mạng bị ngắt, các thao tác ghi sẽ được xếp hàng đợi cho đến khi kết nối được khôi phục, sau đó được thực thi.

Cách thực hiện khá đơn giản:

1) tạo ứng dụng Di động trong cổng azure (bạn có thể dùng thử miễn phí tại đây https://tryappservice.azure.com/ )

2) kết nối khách hàng của bạn với ứng dụng di động. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3) mã để thiết lập kho lưu trữ cục bộ của bạn:

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) sau đó đẩy và kéo dữ liệu của bạn để đảm bảo chúng tôi có những thay đổi mới nhất:

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

Tôi đề nghị bạn cũng hãy xem Symmetricds . nó là một thư viện sao chép SQLite có sẵn cho các hệ thống Android. bạn có thể sử dụng nó để đồng bộ hóa cơ sở dữ liệu máy khách và máy chủ của mình, tôi cũng khuyên bạn nên có các cơ sở dữ liệu riêng trên máy chủ cho từng máy khách. Cố gắng giữ dữ liệu của tất cả người dùng trong một cơ sở dữ liệu mysql không phải lúc nào cũng là ý tưởng tốt nhất. Đặc biệt nếu dữ liệu người dùng đang tăng nhanh.


0

Hãy gọi nó là sự cố Đồng bộ hóa CUDR (Tôi không thích CRUD - vì Tạo / Cập nhật / Xóa được ghi và nên được ghép nối với nhau)

Vấn đề cũng có thể được nhìn nhận từ góc độ ghi đầu tiên hoặc ghi trực tuyến . Cách tiếp cận ghi-ngoại tuyến có vấn đề với xung đột mã định danh duy nhất và cũng có nhiều cuộc gọi mạng cho cùng một giao dịch làm tăng rủi ro (hoặc chi phí) ...

Cá nhân tôi thấy cách tiếp cận viết-trực tuyến-đầu tiên dễ quản lý hơn (vì vậy nó sẽ là nguồn chân lý duy nhất - từ đó mọi thứ khác được đồng bộ hóa). Cách tiếp cận ghi trực tuyến sẽ yêu cầu không cho phép người dùng viết ngoại tuyến trước - họ sẽ viết ngoại tuyến bằng cách viết trực tuyến biểu mẫu phản hồi ok.

Anh ta có thể đọc ngoại tuyến trước và ngay khi có mạng, lấy dữ liệu từ trực tuyến và cập nhật cơ sở dữ liệu cục bộ rồi cập nhật ui ....

Một cách để tránh xung đột mã nhận dạng duy nhất là sử dụng kết hợp id người dùng duy nhất + tên bảng hoặc id bảng + id hàng (được tạo bởi sqlite) ... và sau đó sử dụng cột cờ boolean được đồng bộ hóa với nó .. nhưng vẫn đăng ký phải được thực hiện trực tuyến trước tiên để có được id duy nhất mà tất cả các id khác sẽ được tạo ... ở đây vấn đề cũng sẽ xảy ra nếu đồng hồ không được đồng bộ hóa - mà ai đó đã đề cập ở trên ...


Tiếp tục ghi ẩn cách tiếp cận sẽ có một vấn đề về ứng dụng gỡ bỏ cài đặt, tất cả dữ liệu không được tải lên trực tuyến sẽ bị xóa
DragonFire
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.