Synchronisation mobile avec Couchbase Sync Gateway
Mikael Dautrey
Cet article a été initialement publié sur le blog ISITIX, sous le titre “Synchronisation mobile avec Couchbase Sync Gateway”. Les liens vers la documentation Couchbase ont été mis à jour en Fevrier 2022.
La synchronisation des données d’une base Couchbase Mobile vers une base Couchbase centrale est un mécanisme simple à mettre en place, au moyen de la sync gateway, mais complexe à appréhender du fait des mécanismes sous-jacents et de leur implantation dans l’architecture Couchbase.
Ce document cite et réordonne des informations présentées sur le site Couchbase. Il apporte une vue synthétique sur les mécanismes de synchronisation de Couchbase Mobile et permet de mieux comprendre certains comportements inattendus qui peuvent surprendre le développeur d’applications mobiles s’appuyant sur Couchbase Sync Gateway, des champs ajoutés, la présence apparente de doublons dans les bases, etc…
Champs spécifiques à la gestion des révisions
Les documents comportent des champs précédés par un « _ ». Ces champs sont des champs techniques réservés pour le bon fonctionnement de la SyncGateway. Ces champs sont utilisés pour gérer les révisions et construire l’arbre de révision :
properties with a leading underscore (_ is the character to denote properties reserved for Couchbase) are kept to construct the revision tree.
Le champ _rev
Pour le bon fonctionnement du système, tout document doit comporter un numéro de révision :
Every document has a special field called _rev that contains the revision ID. The revision ID is assigned automatically each time the document is saved. Every time a document is updated, it gets a different and unique revision ID.
Le champ révision est utilisé pour permettre la synchronisation des données. Il ne doit en aucun cas être utilisé pour mettre en place une gestion de version (qui permettrait de revenir en arrière sur des modifications réalisées, etc…) :
Keep in mind that Couchbase Lite is not a version control system and you must not use the versioning feature in your application. They’re there only to help with concurrency and resolving conflicts during replication.
La valeur du champ révision doit cependant être correctement gérée dans l’application client pour assurer le bon fonctionnement du système :
When you save an update to an existing document, you must include its current revision ID. If the revision ID you provide isn’t the current one, the update is rejected. When this happens, it means some other endpoint snuck in and updated the document before you. You need to fetch the new version, reconcile any changes, incorporate the newer revision ID, and try again.
Dans le cas contraire, des problèmes de fonctionnement de l’application risque d’être rencontrés.
Les mécanismes fonctionnant en tâche de fond de la synchronisation
- Arbre de synchronisation
- Résolution de conflit
- Pruning
- Compaction
- Tombstone
The reason that tombstone revisions exist is so that deletes can be sync’d to other databases. If revisions were simply deleted with a naive approach, then there would be no easy way to sync up with other databases that contained the revision.
There is a special field in a revision’s JSON called _deleted which determines whether the revision is a tombstone revision or not. A consequence of this fact is that tombstone revisions can hold arbitrary amounts of metadata, which can be useful for an application. If the full metadata of the document is preserved in the tombstone revision, then a document could easily be restored to it’s last known good state after it’s been deleted at some point.Les deux autres mécanismes suppriment les données qui ne sont plus utiles à la gestion de révision. Le pruning supprime toutes les révisions au-delà de la profondeur maximale de révision. La compaction supprime le contenu des champs des révisions antérieures à la dernière révision validée.
Compaction is defined as the process of purging the JSON bodies of non-leaf revisions. As shown on the diagram below, only properties with a leading underscore (_ is the character to denote properties reserved for Couchbase) are kept to construct the revision tree.Le fonctionnement de la synchronisation est détaillé dans les documents suivants :
Accès aux documents
- En REST sur la Sync_Gateway : la sync gateway fournit une API REST qui permet de consulter les données du bucket central. Les spécifications de cet API sont disponibles ici.
- En passant par la base couchbase lite locale, et en écrivant et en lisant les données depuis le client mobile selon la méthode décrite ici
The app’s job is to make the UI reflect what’s in the local database, and to reflect user actions by making changes to local documents. If it does that, replication will Just Work without much extra effort.En clair, les modifications depuis le client doivent être réalisées dans la base locale sans (trop) se préoccuper de la synchronisation qui jouent en arrière-plan.
Structure des documents
- A document ID
- A current revision ID (which changes every time the document is updated)
- A history of past revision IDs (usually linear, but will form a branching tree if the document has or has had conflicts)
- A body in the form of a JSON object, i.e. a set of key/value pairs
- Zero or more named binary attachments
Expiration d’un document
- Utiliser la méthode ExpireAfter pour définir un temps minimum au-delà le document est expiré et sera supprimé de la base locale
- Utiliser la méthode Purge pour supprimer un document de la base locale
Note: As with the existing explicit purge mechanism, this applies only to the local database; it has nothing to do with replication. The expiration time is not propagated when the document is replicated. The purge of the document does not cause it to be deleted on any other database. If the document is later updated on a remote database that the local database pulls from, the new revision will be pulled and the document will reappear.
Pourquoi cette méthode génère-t-elle apparemment des doublons ?
Une fois le document expiré en local et supprimé, si l’on souhaite recréer un document avec le même identifiant sur la base locale, la méthode GetDocument(docId) retourne null, puisqu’elle ne trouve pas le document en local (voir remarque au paragraphe précédent).
On construit un nouveau document avec le même ID mais un numéro de révision à 0 qui rentre en conflit avec le document existant en central lors de la prochaine synchronisation. Si la résolution de conflit n’est pas prévue au niveau de l’application, le conflit est alors résolu en appliquant la stratégie de résolution par défaut.
Cette stratégie par défaut est expliquée dans ce document.
Enfin, le problème de la gestion des documents purgés est mentionné ici.
Les apports de la version 1.5 de la sync gateway
- Possibilité d’écrire directement dans le bucket central
- Meilleure séparation des données de synchronisation.