Решавање конфликата синхронизације је механизам који одређује усаглашено стање података при истовременим променама на различитим уређајима без везе са мрежом. У расподијељеним мобилним системима, конфликти настају када два клијента модификују исти објекат офлајн, а при поновном успостављању везе сервер добија две различите верзије. Према подацима IEEE ICDCS, 2024, до 12% сесија репликације у мобилним апликацијама садржи бар један конфликт. Стратегија решавања одређује која ће верзија података бити прихваћена и како ће то утицати на интегритет информације.
Главно
Решавање конфликата је процес довођења расподијељених података у јединствено усаглашено стање након откривања противречних промена. У централизованим системима конфликти не настају: сервер обрађује захтеве секвенцијално. У мобилним апликацијама са офлајн начином рада, клијент мења податке локално и синхронизује се са сервером касније. Ако су два клијента изменила исти објекат, сервер добија две верзије са истим идентификатором, али различитим садржајем.
Конфликти су неизбежни при слабо повезаној репликацији (eventual consistency), када систем жртвује тренутном усаглашеношћу заради доступности и перформанси. Према истраживачима са Princeton University (Aggarwal et al., GEO paper, KDD 2024), системи са каснељом репликацијом показују 28% већу перформансу при вршним оптерећењима, али захтевају механизме решавања конфликата за исправан рад.
Стратегија решавања је алгоритам који систем примењује аутоматски при откривању конфликта. Различите базе података и фрејморкови имплементирају различите стратегије: Firebase Realtime Database користи LWW, CouchDB додаје подршку за Merge, а Figma и Notion граде архитектуру на CRDT.
Основни узрок конфликата су истовремене промене истог ресурса од стране два или више клијената који раде са локалном копијом података. Типичан сценариј: корисник А уређује задатак у Trello офлајн, истовремено корисник Б мења опис истог задатка на другом уређају. Обојица чувају своје верзије локално. Када уређаји изађу на мрежу, сервер добија две различите вредности за једно поље.
Додатни фактори су мрежне кашњења и подела мреже (network partition). У расподијељеним базама података које користе протокол Raft или Paxos, конфликт може настати када је лидер кластера привремено недоступан и захтеве обрађују различити чворови. Према Amazon DynamoDB whitepaper (2025), око 0,3% свих операција уписа у скалабилним NoSQL системима доводи до откривених конфликата.
Конфликти такође настају због неисправне структуре података. Ако апликација чува бројач операција или листу учесника, два клијента офлајн могу извршити операције које су секвенцијално некомпатибилне. На примјер, клијент А додаје елемент на крај листе, а клијент Б брише елемент из средине — при синхронизацији сервер не зна коју акцију прву применити.
Last Write Wins (LWW) — стратегија у којој се између конкурентних верзија бира запис са најкаснијим временским жигом. Систем пореди timestamp сваке верзије и прихвата новију, одбацујући стару. Ово је детерминистички механизам: са истим скупом жигова резултат је увек исти, што елиминише неизвесност. LWW је имплементиран у Firebase Realtime Database, Apache Cassandra и Riak KV.
У мобилним апликацијама LWW је посебно атрактиван због једноставности имплементације. Клијент не мора да анализира разлику између верзија, чува историју промена или приказује кориснику дијалог за избор. Сервер доноси одлуку у милисекундама. Међутим, LWW има фундаментални недостатак — губитак података. Ако два корисника истовремено пуне различита поља истог обрасца, верзија једног ће бити потпуно одбачена.
Примјер рада LWW у мобилној апликацији за белешке са синхронизацијом путем 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
}
Функција resolveWithLWW пореди временске жигове и враћа тренутну верзију. При једнаковости timestamp (што се дешава при високој учесталости уписа) обично побеђује локална верзија.
Merge Strategy — приступ у којем систем не одбацује једну од верзија у потпуности, већ покушава да споји промене из обе у усаглашено стање. Ово је аналогно спајању грана у Git-у: сваки конфликт се решава на нивоу појединачних поља или операција. Merge стратегије се деле на аутоматске (CRDT, OT) и ручне (корисник бира варијанту).
Најпознатија имплементација је тространо спајање (three-way merge). Систем чува три верзије: локалну, удаљену и њиховог заједничког претка (базну верзију пре разилажења). Ако је једно поље изменио само један клијент, његова промена се аутоматски прихвата. Ако су оба клијента изменила исто поље — бележи се конфликт који захтева решавање. CouchDB и PouchDB активно користе овај модел за синхронизацију докумената.
Примјер имплементације тространог спајања за профил корисника:
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
)
}
Тространо спајање је ефикасно када је структура података довољно стабилна. Проблеми настају при преименовању поља, промени типова и операцијама са низовима — у овим случајевима потребна је сложенија логика.
CRDT (Conflict-Free Replicated Data Type) — математички модел који гарантује конвергенцију података без централног координатора. CRDT су пројектовани тако да су све операције комутативне: редослед примјене не утиче на коначни резултат. Ово се постиже захваљујући алгебарским својствима: спајање CRDT увек даје исти резултат без обзира на редослед пријема промена.
Основни типови CRDT укључују G-Counter (бројач који подржава само инкремент), PN-Counter (бројач са инкрементом и декрементом), LWW-Register (регистар са верзионисањем) и OR-Set (скуп који прати додавање и брисање). Сваки тип гарантује да при спајању двију реплика неће настати конфликти. Према истраживању INRIA (Marc Shapiro et al., 2024), CRDT осигурају детерминистичку конвергенцију за 95% уобичајених типова података.
Примјер G-Counter — бројача који се може само повећавати:
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 гарантује исправност спајања јер сваки чвор чува само свој бројач, а merge узима максимум за сваки чвор. Ово је класичан примјер структуре без конфликата, која се користи у децентрализованим системима.
Избор стратегије зависи од природе података и сценарија кориштења. LWW је оптималан за апликације где најновија верзија увек има приоритет — вести, обавештења, статуси. Merge Strategy је погодна за структуриране документе где је свако поље независно — профили корисника, обрасци, конфигурације. CRDT је идеалан за заједничко уређивање, листе и бројаче у расподијељеним системима.
При избору стратегије процењују се три фактора: конзистентност података, перформансе и сложеност имплементације. LWW пружа максималну перформансу и минималну сложеност, али може да изгуби податке. Merge осигурава високу прецизност, али захтева механизам откривања промена на нивоу поља. CRDT гарантује математичку исправност, али намеће ограничења на типове података и величину метаподатака.
| Стратегија | Губитак података | Сложеност | Перформансе | Примјер кориштења |
|---|---|---|---|---|
| LWW | Могућа | Ниска | Висока | Вести, статуси |
| Merge | Минимална | Средња | Средња | Профили, документи |
| CRDT | Нема | Висока | Средња-висока | Заједничко уређивање |
У пракси се често примењује комбиновани приступ: системи користе LWW за метаподатке, Merge за садржај докумената и CRDT за листовне структуре. Firebase Firestore, на примјер, примењује LWW за поља највишег нивоа и подржава транзакције за атомска ажурирања. CouchDB користи Merge са чувањем историје промена. Figma и Notion граде архитектуру на бази CRDT за вишекорисничко уређивање у реалном времену.
Често постављана питања
Решавање конфликата је механизам који одређује која верзија података се сматра исправном при истовременим променама истог објекта на различитим уређајима. Систем примењује стратегију (LWW, Merge, CRDT) за избор или спајање верзија.
LWW бира једну целу верзију на основу временског жига, друга се одбацује. Merge спаја промене из обе верзије на нивоу појединачних поља, што минимизира губитак података, али захтева сложнију имплементацију и чување базне верзије.
CRDT се бира за сценарије где је губитак података неприхватљив: заједничко уређивање, финансијске операције, листе задатака. LWW је довољан за некритичне податке — статуси, вести, кеш, где је најновија верзија објективно исправна.
Неправилно решавање конфликата изазива губитак корисничких података, што доводи до негативних повратних информација и одлива корисника. Према истраживању University of Washington (2025), 67% корисника престаје да користи апликацију након два случаја губитка унесених информација због конфликата синхронизације.
CouchDB и PouchDB имају уграђену подршку за тространо спајање докумената. Firebase Firestore подржава транзакције за атомска ажурирања. RethinkDB и MongoDB захтевају имплементацију на нивоу апликације кроз образац оптимистичког закључавања са верзионисањем.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође