Sincronización de bases de datos cliente-servidor


Estoy buscando algunas estrategias generales para sincronizar datos en un servidor central con aplicaciones cliente que no siempre están en línea.

En mi caso particular, tengo una aplicación de teléfono android con una base de datos sqlite y una aplicación web PHP con una base de datos MySQL.

Los usuarios podrán agregar y editar información en la aplicación del teléfono y en la aplicación web. Necesito asegurarme de que los cambios realizados en un lugar se reflejen en todas partes, incluso cuando el teléfono está no es capaz de comunicarse inmediatamente con el servidor.

No me preocupa cómo transferir datos del teléfono al servidor o viceversa. Estoy mencionando mis tecnologías particulares solo porque no puedo usar, por ejemplo, las funciones de replicación disponibles para MySQL.

Sé que el problema de sincronización de datos cliente-servidor ha existido durante mucho, mucho tiempo y quisiera información - artículos, libros, consejos, etc. - sobre los patrones para manejar el problema. Me gustaría conocer estrategias generales para lidiar con la sincronización para comparar fortalezas, debilidades y compensaciones.

Author: Jonas, 2010-08-04

5 answers

Lo primero que tiene que decidir es una política general sobre qué lado se considera "autorizado" en caso de cambios conflictivos.

Es decir: supongamos que el Registro #125 se cambia en el servidor el 5 de enero a las 10 pm y el mismo registro se cambia en uno de los teléfonos (llamémoslo Cliente A) el 5 de enero a las 11 pm. La última sincronización fue el 3 de enero. Luego, el usuario se vuelve a conectar, digamos, el 8 de enero.

Identificar lo que necesita ser cambiado es "fácil" en el sentido de que tanto el cliente como el servidor sabe la fecha de la última sincronización, por lo que cualquier creado o actualizado (ver más abajo para más información sobre esto) desde la última sincronización debe conciliarse.

Entonces, supongamos que el único registro cambiado es #125. Usted decide que una de las dos automáticamente "gana" y sobrescribe la otra, o necesita soportar una fase de conciliación donde un usuario puede decidir qué versión (servidor o cliente) es la correcta, sobrescribiendo la otra.

Esta decisión es extremadamente importante y usted debe ponderar el "papel" de los clientes. Especialmente si hay un conflicto potencial no solo entre el cliente y el servidor, sino en caso de que diferentes clientes puedan cambiar el mismo registro(s).

[Suponiendo que #125 puede ser modificado por un segundo cliente (Cliente B) existe la posibilidad de que el Cliente B, que aún no se ha sincronizado, proporcione otra versión del mismo registro, lo que hace que la resolución de conflictos anterior sea discutible]

Con respecto al punto " creado o actualizado" anterior... ¿cómo puede ¿identifica correctamente un registro si se ha originado en uno de los clientes (suponiendo que esto tenga sentido en su dominio del problema)? Supongamos que tu aplicación administra una lista de contactos comerciales. Si el Cliente A dice que tiene que agregar un John Smith recién creado, y el servidor tiene un John Smith creado ayer por el Cliente D... ¿crea dos registros porque no puede estar seguro de que no sean personas diferentes? ¿Le pedirás al usuario que reconcilie este conflicto también?

¿Tienen los clientes la "propiedad" de un subconjunto de datos? Es decir, si el Cliente B está configurado para ser la "autoridad" en los datos para el Área #5, ¿puede el Cliente A modificar/crear registros para el Área #5 o no? (Esto facilitaría la resolución de conflictos, pero puede resultar inviable para su situación).

Para resumir los principales problemas son:

  • Cómo definir "identidad" teniendo en cuenta que los clientes separados pueden no haber accedido al servidor antes de crear un nuevo registro.
  • La situación anterior, no importa cómo sofisticada la solución, puede resultar en la duplicación de datos, por lo que debe prever cómo resolver periódicamente estos y cómo informar a los clientes que lo que consideraban como "Registro #675" en realidad se ha fusionado con/reemplazado por el Registro #543
  • Decida si los conflictos se resolverán mediante fiat (por ejemplo, "La versión del servidor siempre supera a la del cliente si la primera se ha actualizado desde la última sincronización") o mediante intervención manual
  • En el caso de fiat , especialmente si decida que el cliente tiene prioridad, también debe tener cuidado de cómo tratar con otros clientes aún no sincronizados que pueden tener algunos cambios más por venir.
  • Los elementos anteriores no tienen en cuenta la granularidad de sus datos (para hacer las cosas más fáciles de describir). Basta con decir que en lugar de razonar a nivel de "Registro", como en mi ejemplo, puede encontrar más apropiado registrar el cambio a nivel de campo, en su lugar. O para trabajar en un conjunto de registros (por ejemplo, Registro de persona + Registro de direcciones + Registro de contactos) a la vez que tratan su agregado como una especie de "Registro Meta".

Bibliografía:

(Los tres últimos son del ACM biblioteca digital, ni idea de si usted es un miembro o si se puede obtener a través de otros canales).

Del sitio del Dr. Dobbs :

  • Creación de aplicaciones con SQL Server CE y SQL RDA por Bill Wagner 19 de mayo de 2004 (Mejores prácticas para el diseño de una aplicación tanto para el escritorio y PC móvil - Windows/. NET)

Desde arxiv.org:

  • Un tipo de datos JSON replicado sin conflictos - el documento describe una implementación de CRDT JSON (Los tipos de datos replicados sin conflictos-CRDT-son una familia de estructuras de datos que admiten modificaciones concurrentes y que garantizan la convergencia de dichas actualizaciones concurrentes).
 75
Author: p.marino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-21 11:23:02

Si alguien está tratando con un problema de diseño similar y necesita sincronizar los cambios en varios dispositivos Android, recomiendo verificar Google Cloud Messaging for Android (GCM).

Estoy trabajando en una solución donde los cambios realizados en un cliente deben propagarse a otros clientes. Y acabo de implementar una prueba de implementación de concepto (servidor y cliente) y funciona como un encanto.

Básicamente, cada cliente envía cambios delta al servidor. Por ejemplo, id de recurso ABCD1234 ha cambiado de valor 100 a 99.

El servidor valida estos cambios delta contra su base de datos y aprueba el cambio (el cliente está sincronizado) y actualiza su base de datos o rechaza el cambio (el cliente no está sincronizado).

Si el cambio es aprobado por el servidor, el servidor notifica a otros clientes (excluyendo al que envió el cambio delta) a través de GCM y envía un mensaje de multidifusión con el mismo cambio delta. Los clientes procesan este mensaje y actualizan su base.

¡Lo bueno es que estos cambios se propagan casi instantáneamente!!! si esos dispositivos están en línea. Y no necesito implementar ningún mecanismo de votación en esos clientes.

Tenga en cuenta que si un dispositivo está fuera de línea demasiado tiempo y hay más de 100 mensajes esperando en la cola de GCM para la entrega, GCM descartará esos mensajes y enviará un mensaje especial cuando los dispositivos vuelvan a estar en línea. En ese caso, el cliente debe realizar una sincronización completa con el servidor.

Comprobar también este tutorial para comenzar con la implementación del cliente CGM.

 5
Author: jogo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-16 12:12:09

Le recomendaría que tenga una columna timestamp en cada tabla y cada vez que inserte o actualice, actualice el valor de la marca de tiempo de cada fila afectada. Luego, itera sobre todas las tablas comprobando si la marca de tiempo es más reciente que la que tiene en la base de datos de destino. Si es más reciente, compruebe si tiene que insertar o actualizar.

Observación 1: tenga en cuenta las eliminaciones físicas ya que las filas se eliminan de la base de datos de origen y debe hacer lo mismo en la base de datos del servidor. Puedes resuelva esto evitando eliminaciones físicas o registrando todas las eliminaciones en una tabla con marcas de tiempo. Algo como esto: DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp) Entonces, tienes que leer todas las nuevas filas de la tabla DeletedRows y ejecutar un delete en el servidor usando table_name, pk_column y pk_column_value.

Observación 2: tenga en cuenta FK ya que la inserción de datos en una tabla que está relacionada con otra tabla podría fallar. Debe desactivar cada FK antes de la sincronización de datos.

 5
Author: Francisco Goldenstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-28 08:02:33

Esto responde a los desarrolladores que están usando el framework Xamarin (ver https://stackoverflow.com/questions/40156342/sync-online-offline-data )

Una forma muy sencilla de lograr esto con el marco de xamarin es usar la sincronización de datos sin conexión de Azure, ya que permite empujar y extraer datos del servidor bajo demanda. Las operaciones de lectura se realizan localmente, y las operaciones de escritura se empujan bajo demanda; Si la conexión de red se interrumpe, las operaciones de escritura se ponen en cola hasta que la conexión restaurado, luego ejecutado.

La implementación es bastante simple:

1) cree una aplicación móvil en azure portal (puede probarlo de forma gratuita aquí https://tryappservice.azure.com/)

2) conecte su cliente a la aplicación móvil. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3) el código para configurar su repositorio local:

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) a continuación, para empujar y tirar de sus datos para asegurarse de que tenemos la últimos cambios:

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/

 4
Author: Ben Ishiyama-Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:28

Le sugiero que también eche un vistazo a Simétricas. es una biblioteca de replicación SQLite disponible para sistemas Android. puede usarlo para sincronizar su base de datos de cliente y servidor, también sugiero tener bases de datos separadas en el servidor para cada cliente. Tratar de mantener los datos de todos los usuarios en una base de datos mysql no siempre es la mejor idea. Especialmente si los datos del usuario van a crecer rápidamente.

 0
Author: Hossein Shahdoost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-06 11:56:38