Rezolvarea conflictelor de sincronizare este un mecanism care determină starea coerentă a datelor la modificări simultane pe diferite dispozitive fără conexiune la rețea. În sistemele mobile distribuite, conflictele apar atunci când doi clienți modifică același obiect offline, iar la restabilirea conexiunii serverul primește două versiuni diferite. Conform datelor IEEE ICDCS, 2024, până la 12% din sesiunile de replicare în aplicațiile mobile conțin cel puțin un conflict. Strategia de rezolvare determină care versiune a datelor va fi acceptată și cum va afecta aceasta integritatea informației.
Principalele puncte
Rezolvarea conflictelor este procesul de aducere a datelor distribuite la o stare coerentă unică după detectarea modificărilor contradictorii. În sistemele centralizate, conflictele nu apar: serverul procesează cererile secvențial. În aplicațiile mobile cu mod offline, clientul modifică datele local și se sincronizează cu serverul mai târziu. Dacă doi clienți au modificat același obiect, serverul primește două versiuni cu același identificator dar conținut diferit.
Conflictele sunt inevitabile în replicarea slab cuplată (eventual consistency), când sistemul sacrifică coerența imediată în favoarea disponibilității și performanței. Conform cercetătorilor de la Princeton University (Aggarwal et al., GEO paper, KDD 2024), sistemele cu replicare întârziată demonstrează o performanță cu 28% mai mare la sarcinile de vârf, dar necesită mecanisme de rezolvare a conflictelor pentru funcționarea corectă.
Strategia de rezolvare este un algoritm pe care sistemul îl aplică automat la detectarea unui conflict. Diferite baze de date și framework-uri implementează strategii diferite: Firebase Realtime Database folosește LWW, CouchDB adaugă suport Merge, iar Figma și Notion construiesc arhitectura pe CRDT.
Cauza principală a conflictelor este modificarea simultană a aceluiași resource de către doi sau mai mulți clienți care lucrează cu copia locală a datelor. Scenariu tipic: utilizatorul A modifică o sarcină în Trello offline, în același timp utilizatorul B schimbă descrierea aceleiași sarcini pe un alt dispozitiv. Ambii își salvează versiunile local. Când dispozitivele se conectează la rețea, serverul primește două valori diferite pentru același câmp.
Factori suplimentari includ întârzierile de rețea și partiționarea rețelei (network partition). în bazele de date distribuite care folosesc protocolul Raft sau Paxos, un conflict poate apărea când liderul clusterului este temporar indisponibil și cererile sunt procesate de diferite noduri. Conform lucrării Amazon DynamoDB whitepaper (2025), aproximativ 0,3% din toate operațiile de scriere în sistemele NoSQL scalabile duc la conflicte detectabile.
Conflictele apar și din cauza structurii incorecte a datelor. Dacă aplicația stochează un contor de operații sau o listă de participanți, doi clienți offline pot executa operații care sunt secvențial incompatibile. De exemplu, clientul A adaugă un element la sfârșitul listei, iar clientul B șterge un element din mijloc — la sincronizare serverul nu știe ce acțiune să aplice prima.
Last Write Wins (LWW) — strategia în care dintre versiunile concurente este selectată înregistrarea cu cel mai recent marcaj temporal. Sistemul compară timestamp-ul fiecărei versiuni și acceptă cea mai nouă, aruncând-o pe cea veche. Acesta este un mecanism determinist: cu același set de marcaje, rezultatul este întotdeauna același, ceea ce elimină incertitudinea. LWW este implementat în Firebase Realtime Database, Apache Cassandra și Riak KV.
în aplicațiile mobile, LWW este deosebit de atractiv datorită simplității de implementare. Clientul nu trebuie să analizeze diferența dintre versiuni, să stocheze istoricul modificărilor sau să arate utilizatorului un dialog de selecție. Serverul ia decizia în milisecunde. Cu toate acestea, LWW are un dezavantaj fundamental — pierderea de date. Dacă doi utilizatori completează simultan câmpuri diferite ale unui formular, versiunea unuia va fi complet aruncată.
Exemplu de funcționare LWW într-o aplicație mobilă de notițe cu sincronizare prin REST API:
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
}
Funcția resolveWithLWW compară marcajele temporale și returnează versiunea curentă. La egalitate de timestamp (ce se întâmplă la frecvență mare de scriere) de obicei câștigă versiunea locală.
Merge Strategy — abordare în care sistemul nu aruncă complet una dintre versiuni, ci încearcă să combine modificările din ambele într-o stare coerentă. Aceasta este analogă îmbinării ramurilor în Git: fiecare conflict este rezolvat la nivelul câmpurilor individuale sau al operațiilor. Strategiile Merge se împart în automate (CRDT, OT) și manuale (utilizatorul alege varianta).
Cea mai cunoscută implementare este îmbinarea pe trei căi (three-way merge). Sistemul stochează trei versiuni: locală, remote și strămoșul lor comun (versiunea de bază înainte de divergență). Dacă un câmp a fost modificat doar de un client, modificarea sa este acceptată automat. Dacă ambii clienți au modificat același câmp — se înregistrează un conflict care necesită rezolvare. CouchDB și PouchDB folosesc activ acest model pentru sincronizarea documentelor.
Exemplu de implementare a îmbinării pe trei căi pentru un profil de utilizator:
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
)
}
îmbinarea pe trei căi este eficientă atunci când structura datelor este suficient de stabilă. Problemele apar la redenumirea câmpurilor, schimbarea tipurilor și operațiile cu tablouri — în aceste cazuri este necesară o logică mai complexă.
CRDT (Conflict-Free Replicated Data Type) — model matematic care garantează convergența datelor fără un coordonator central. CRDT sunt proiectate astfel încât toate operațiile sunt comutative: ordinea aplicării nu afectează rezultatul final. Acest lucru se realizează prin proprietăți algebrice: îmbinarea CRDT dă întotdeauna același rezultat indiferent de ordinea primirii modificărilor.
Principalele tipuri CRDT includ G-Counter (contor care suportă doar incrementare), PN-Counter (contor cu incrementare și decrementare), LWW-Register (registru cu versionare) și OR-Set (set care urmărește adăugarea și ștergerea). Fiecare tip garantează că la îmbinarea a două replici nu vor apărea conflicte. Conform cercetării INRIA (Marc Shapiro et al., 2024), CRDT asigură convergență deterministă pentru 95% din tipurile comune de date.
Exemplu de G-Counter — un contor care poate fi doar incrementat:
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 garantează corectitudinea îmbinării deoarece fiecare nod stochează doar propriul contor, iar merge ia maximul pentru fiecare nod. Acesta este un exemplu clasic de structură fără conflicte, utilizată în sisteme descentralizate.
Alegerea strategiei depinde de natura datelor și de scenariile de utilizare. LWW este optim pentru aplicații unde ultima versiune are întotdeauna prioritate — flux de știri, notificări, statusuri. Merge Strategy este potrivită pentru documente structurate unde fiecare câmp este independent — profiluri de utilizatori, formulare, configurații. CRDT este ideal pentru editare colaborativă, liste și contoare în sisteme distribuite.
La alegerea strategiei se evaluează trei factori: coerența datelor, performanța și complexitatea implementării. LWW oferă performanță maximă și complexitate minimă, dar poate pierde date. Merge asigură precizie ridicată, dar necesită un mecanism de detectare a modificărilor la nivel de câmpuri. CRDT garantează corectitudine matematică, dar impune limitări asupra tipurilor de date și dimensiunii metadatelor.
| Strategie | Pierdere de date | Complexitate | Performanță | Exemplu de utilizare |
|---|---|---|---|---|
| LWW | Posibilă | Scăzută | Ridicată | Flux de știri, statusuri |
| Merge | Minimă | Medie | Medie | Profiluri, documente |
| CRDT | Nicio | Ridicată | Medie-ridicată | Editare colaborativă |
în practică se aplică adesea o abordare combinată: sistemele folosesc LWW pentru metadate, Merge pentru conținutul documentelor și CRDT pentru structuri de tip listă. Firebase Firestore, de exemplu, aplică LWW pentru câmpurile de nivel superior și suportă tranzacții pentru actualizări atomice. CouchDB folosește Merge cu stocarea istoricului modificărilor. Figma și Notion construiesc arhitectura pe bază de CRDT pentru editarea multi-utilizator în timp real.
Întrebări frecvente
Rezolvarea conflictelor este un mecanism care determină care versiune a datelor este considerată corectă la modificări simultane ale aceluiași obiect pe diferite dispozitive. Sistemul aplică o strategie (LWW, Merge, CRDT) pentru selectarea sau combinarea versiunilor.
LWW selectează o versiune completă pe baza marcajului temporal, cealaltă fiind aruncată. Merge combină modificările din ambele versiuni la nivel de câmpuri individuale, ceea ce minimizează pierderea de date, dar necesită o implementare mai complexă și stocarea versiunii de bază.
CRDT se alege pentru scenarii unde pierderea de date este inacceptabilă: editare colaborativă, operații financiare, liste de sarcini. LWW este suficient pentru date necritice — statusuri, flux de știri, cache, unde ultima versiune este obiectiv corectă.
Rezolvarea incorectă a conflictelor cauzează pierderea datelor utilizatorului, ceea ce duce la recenzii negative și pierdere de utilizatori. Conform unui studiu al University of Washington (2025), 67% dintre utilizatori încetează să folosească o aplicație după două cazuri de pierdere a informațiilor introduse din cauza conflictelor de sincronizare.
CouchDB și PouchDB au suport încorporat pentru îmbinarea pe trei căi a documentelor. Firebase Firestore suportă tranzacții pentru actualizări atomice. RethinkDB și MongoDB necesită implementare la nivel de aplicație prin modelul de blocare optimistă cu versionare.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și