La résolution de conflits de synchronisation est un mécanisme qui détermine l'état cohérent des données lors de modifications simultanées sur différents appareils sans connexion réseau. Dans les systèmes mobiles distribués, des conflits surviennent lorsque deux clients modifient le même objet hors ligne et, lors du rétablissement de la connexion, le serveur reçoit deux versions différentes. Selon l'IEEE ICDCS, 2024, jusqu'à 12 % des sessions de réplication dans les applications mobiles contiennent au moins un conflit. La stratégie de résolution détermine quelle version des données sera acceptée et comment elle affecte l'intégrité des informations.
Points Clés
La résolution de conflits est le processus qui consiste à ramener les données distribuées à un état cohérent unique après la détection de modifications contradictoires. Dans les systèmes centralisés, les conflits ne se produisent pas : le serveur traite les requêtes séquentiellement. Dans les applications mobiles avec mode hors ligne, le client modifie les données localement et les synchronise avec le serveur ultérieurement. Si deux clients ont modifié le même objet, le serveur reçoit deux versions avec le même identifiant mais un contenu différent.
Les conflits sont inévitables dans la réplication faiblement couplée (cohérence éventuelle), lorsque le système sacrifie la cohérence instantanée au profit de la disponibilité et des performances. Selon des chercheurs de l'Université de Princeton (Aggarwal et al., article GEO, KDD 2024), les systèmes à réplication différée présentent des performances 28 % supérieures sous des charges de pointe, mais nécessitent des mécanismes de résolution de conflits pour un fonctionnement correct.
La stratégie de résolution est un algorithme que le système applique automatiquement lors de la détection d'un conflit. Différentes bases de données et frameworks implémentent différentes stratégies : Firebase Realtime Database utilise LWW, CouchDB ajoute le support de Merge, et Figma et Notion construisent leur architecture sur CRDT.
La principale cause des conflits est la modification simultanée de la même ressource par deux clients ou plus travaillant avec une copie locale des données. Un scénario typique : l'utilisateur A modifie une tâche dans Trello hors ligne, tandis que l'utilisateur B change la description de la même tâche sur un autre appareil. Tous deux enregistrent leurs versions localement. Lorsque les appareils se connectent au réseau, le serveur reçoit deux valeurs différentes pour le même champ.
Les facteurs supplémentaires incluent les latences réseau et les partitions réseau. Dans les bases de données distribuées utilisant le protocole Raft ou Paxos, un conflit peut survenir si le leader du cluster est temporairement indisponible et que les requêtes sont traitées par différents nœuds. Selon le livre blanc d'Amazon DynamoDB (2025), environ 0,3 % de toutes les opérations d'écriture dans les systèmes NoSQL évolutifs entraînent des conflits détectables.
Les conflits surviennent également en raison de structures de données incorrectes. Si une application stocke un compteur d'opérations ou une liste de participants, deux clients hors ligne peuvent effectuer des opérations séquentiellement incompatibles. Par exemple, le client A ajoute un élément à la fin d'une liste tandis que le client B supprime un élément du milieu — lors de la synchronisation, le serveur ne sait pas quelle action appliquer en premier.
Last Write Wins (LWW) est une stratégie dans laquelle, parmi les versions concurrentes, l'entrée avec l'horodatage le plus récent est sélectionnée. Le système compare les horodatages de chaque version et accepte la plus récente, rejetant la plus ancienne. Il s'agit d'un mécanisme déterministe : avec le même ensemble d'horodatages, le résultat est toujours le même, éliminant l'incertitude. LWW est implémenté dans Firebase Realtime Database, Apache Cassandra et Riak KV.
Dans les applications mobiles, LWW est particulièrement attrayant en raison de sa simplicité d'implémentation. Le client n'a pas besoin d'analyser les différences entre les versions, de stocker l'historique des modifications ou d'afficher une boîte de dialogue de sélection à l'utilisateur. Le serveur prend la décision en millisecondes. Cependant, LWW présente un inconvénient fondamental — la perte de données. Si deux utilisateurs remplissent simultanément différents champs d'un formulaire, une version sera complètement rejetée.
Exemple de fonctionnement de LWW dans une application mobile de notes avec synchronisation via API REST :
data class Note(
val id: String,
val title: String,
val content: String,
val updatedAt: Long
)
fun resolveWithLWW(
local: Note,
remote: Note
): Note {
return if (local.updatedAt >= remote.updatedAt) local
else remote
}
La fonction resolveWithLWW compare les horodatages et retourne la version actuelle. Lorsque les horodatages sont égaux (ce qui se produit avec une fréquence d'écriture élevée), la version locale l'emporte généralement.
La stratégie de fusion est une approche dans laquelle le système ne rejette pas complètement l'une des versions, mais tente de combiner les modifications des deux dans un état cohérent. Cela est analogue à la fusion de branches dans Git : chaque conflit est résolu au niveau des champs ou opérations individuels. Les stratégies de fusion sont divisées en automatiques (CRDT, OT) et manuelles (l'utilisateur sélectionne l'option).
L'implémentation la plus connue est la fusion à trois voies (three-way merge). Le système stocke trois versions : locale, distante et leur ancêtre commun (la version de base avant la divergence). Si un seul client a modifié un champ, cette modification est acceptée automatiquement. Si les deux clients ont modifié le même champ — un conflit nécessitant une résolution est enregistré. CouchDB et PouchDB utilisent activement ce modèle pour la synchronisation de documents.
Exemple d'implémentation d'une fusion à trois voies pour un profil utilisateur :
data class Profile(
val name: String,
val email: String,
val avatarUrl: String
)
fun threeWayMerge(
base: Profile,
local: Profile,
remote: Profile
): Profile {
return Profile(
name = if (local.name != base.name) local.name
else remote.name,
email = if (local.email != base.email) local.email
else remote.email,
avatarUrl = if (remote.avatarUrl != base.avatarUrl) remote.avatarUrl
else local.avatarUrl
)
}
La fusion à trois voies est efficace lorsque la structure de données est suffisamment stable. Des problèmes surviennent lors du renommage de champs, du changement de types et des opérations sur les tableaux — dans ces cas, une logique plus complexe est nécessaire.
CRDT (Conflict-Free Replicated Data Type) est un modèle mathématique qui garantit la convergence des données sans coordinateur central. Les CRDT sont conçus pour que toutes les opérations soient commutatives : l'ordre d'application n'affecte pas le résultat final. Ceci est obtenu grâce à des propriétés algébriques : la fusion de CRDT produit toujours le même résultat indépendamment de la séquence de réception des modifications.
Les principaux types de CRDT incluent G-Counter (un compteur ne supportant que l'incrémentation), PN-Counter (un compteur avec incrémentation et décrémentation), LWW-Register (un registre avec versionnage) et OR-Set (un ensemble avec suivi d'ajout et de suppression). Chaque type garantit que la fusion de deux répliques ne produira pas de conflits. Selon les recherches de l'INRIA (Marc Shapiro et al., 2024), les CRDT fournissent une convergence déterministe pour 95 % des types de données courants.
Exemple d'un G-Counter — un compteur qui ne peut qu'être incrémenté :
class GCounter {
private val counts = mutableMapOf<String, Int>()
fun increment(nodeId: String) {
counts[nodeId] = (counts[nodeId] ?: 0) + 1
}
fun value(): Int = counts.values.sum()
fun merge(other: GCounter) {
other.counts.forEach { (node, count) ->
counts[node] = maxOf(counts[node] ?: 0, count)
}
}
}
GCounter garantit une fusion correcte car chaque nœud stocke uniquement son propre compteur, et la fusion prend le maximum par nœud. C'est un exemple classique de structure sans conflit utilisée dans les systèmes décentralisés.
Le choix de la stratégie dépend de la nature des données et des scénarios d'utilisation. LWW est optimal pour les applications où la dernière version a toujours la priorité — fils d'actualité, notifications, statuts. La stratégie de fusion convient aux documents structurés où chaque champ est indépendant — profils utilisateur, formulaires, configurations. CRDT est idéal pour l'édition collaborative, les listes et les compteurs dans les systèmes distribués.
Lors du choix d'une stratégie, trois facteurs sont évalués : la cohérence des données, les performances et la complexité d'implémentation. LWW offre des performances maximales et une complexité minimale, mais peut perdre des données. Merge offre une grande précision mais nécessite un mécanisme de détection des changements au niveau des champs. CRDT garantit une exactitude mathématique mais impose des limitations sur les types de données et la taille des métadonnées.
| Stratégie | Perte de données | Complexité | Performance | Cas d'utilisation |
|---|---|---|---|---|
| LWW | Possible | Faible | Élevée | Fil d'actualité, statuts |
| Merge | Minimale | Moyenne | Moyenne | Profils, documents |
| CRDT | Aucune | Élevée | Moyenne-Élevée | Édition collaborative |
Dans la pratique, une approche combinée est souvent utilisée : les systèmes utilisent LWW pour les métadonnées, Merge pour le contenu des documents et CRDT pour les structures de liste. Firebase Firestore, par exemple, applique LWW pour les champs de niveau supérieur et prend en charge les transactions pour les mises à jour atomiques. CouchDB utilise Merge avec stockage de l'historique des modifications. Figma et Notion construisent leur architecture sur CRDT pour l'édition multi-utilisateur en temps réel.
Foire Aux Questions
La résolution de conflits est un mécanisme qui détermine quelle version des données est considérée comme correcte lorsque le même objet est modifié simultanément sur différents appareils. Le système applique une stratégie (LWW, Merge, CRDT) pour sélectionner ou fusionner les versions.
LWW sélectionne une version complète par horodatage, l'autre est rejetée. Merge combine les modifications des deux versions au niveau des champs individuels, minimisant la perte de données mais nécessitant une implémentation plus complexe et le stockage de la version de base.
CRDT est choisi pour les scénarios où la perte de données est inacceptable : édition collaborative, opérations financières, listes de tâches. LWW est suffisant pour les données non critiques — statuts, fils d'actualité, caches, où la dernière version est objectivement correcte.
Une résolution incorrecte des conflits entraîne une perte de données utilisateur, ce qui conduit à des avis négatifs et à une attrition. Selon une étude de l'Université de Washington (2025), 67 % des utilisateurs cessent d'utiliser une application après deux cas de perte d'informations saisies en raison de conflits de synchronisation.
CouchDB et PouchDB disposent d'un support intégré pour la fusion à trois voies de documents. Firebase Firestore prend en charge les transactions pour les mises à jour atomiques. RethinkDB et MongoDB nécessitent une implémentation au niveau de l'application via le modèle de verrouillage optimiste avec versionnage.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi