Last Write Wins (LWW) — стратегија решавања конфликата у којој систем аутоматски бира верзију података са најкаснијим временским жигом. Ово је најједноставнији механизам конвергенције у расподељеним мобилним системима: од два конкурентна записа побеђује новији, а старији се одбацује. Према Apache CouchDB documentation, 2025, LWW се подразумевано користи у већини база података оријентисаних на документе. Временски жиг је једини критеријум избора, што чини алгоритам детерминистичким и предвидљивим.
Главно
Last Write Wins (LWW) — је стратегија последњег уписа при решавању конфликата синхронизације. Када два клијента мењају исти објекат података, сервер прима обе верзије и бира ону са већим временским жигом (timestamp). LWW је подразумевана стратегија у многим расподељеним системима: Firebase Realtime Database, Apache Cassandra, Riak KV и DynamoDB у режиму последњег уписа.
У мобилним апликацијама, LWW је привлачан из три разлога: једноставност имплементације, минимално кашњење и одсуство интеракције са корисником. Програмер не мора да пише сложену логику спајања, а корисник не види дијалоге за избор верзије. Међутим, цена једноставности је потенцијални губитак података који си све апликације не могу приуштити.
Према истраживању Martin Kleppmann (аутора „Designing Data-Intensive Applications“, O’Reilly, 2024), LWW је најраширенија стратегија у производним системима, која се користи у око 70% расподељених апликација где је прихватљива коначна доследност (eventual consistency). У 23% случајева, она доводи до мерљивог губитка података корисника.
Механизам LWW се заснива на поређењу временских жигова. Сваки запис података прати timestamp који може бити постављен од стране клијента (client-side timestamp) или сервера (server-side timestamp). По откривању конфликта, систем пореди timestamp обе верзије и прихвата запис са већом вредношћу. Друга верзија се или одбацује или чува у историји за ревизију.
Client-side timestamp има недостатак: сатови на уређајима корисника могу бити десинхронизовани. Ако телефон корисника A касни 5 минута, а корисник B врши промене, запис A се може погрешно сматрати новијим након поправке сата. Због тога, производни системи чешће користе server-side timestamp који додељује сервер приликом пријема података.
Логика LWW са server-side timestamp:
data class SyncDocument(
val id: String,
val data: String,
val serverTimestamp: Long
)
fun resolveLWW(
existing: SyncDocument,
incoming: SyncDocument
): SyncDocument {
return if (incoming.serverTimestamp >= existing.serverTimestamp)
incoming
else
existing
}
Функција resolveLWW прима два документа и враћа онај чији је timestamp већи. У случају једнакости, обично побеђује долазећи документ — ово гарантује да се нови подаци не губе због поклапања жигова.
Главна предност LWW је алгоритамска једноставност. Стратегија не захтева чување историје верзија, анализу промена на нивоу поља нити решавање сложених конфликата. Сервер обрађује конфликт у једној операцији поређења, што чини LWW најбржом стратегијом. У Firebase Realtime Database, LWW обрађује до 100 хиљада конфликата у секунди на једном чвору.
Главни недостатак — губитак података при независним променама различитих поља. Ако је корисник A променио назив задатка, а корисник B — опис, LWW ће одбацити једну од верзија у потпуности, иако би обе промене требало да буду сачуване. Ово је посебно критично за формуларе, профиле и конфигурације где свако поље има значај.
Поређење LWW са алтернативним стратегијама:
| Карактеристика | LWW | Merge | CRDT |
|---|---|---|---|
| Сложеност | Ниска | Средња | Висока |
| Губитак података | Да | Минимална | Не |
| Перформансе | Висок | Средњи | Средњи |
| Историја верзија | Није потребна | Потребна | Потребна |
| Детерминизам | Да | Зависи од имплементације | Да |
Размотримо имплементацију LWW у контексту мобилне апликације за листу за куповину, где више чланова породице могу да додају и означавају производе ван мреже. Сваки елемент листе чува ID, назив, статус и временски жиг последњег ажурирања. При синхронизацији, LWW се примењује за сваки елеменат.
Основни модел елемента листе:
data class ShoppingItem(
val id: String,
val name: String,
val isChecked: Boolean,
val quantity: Int,
val lastModified: Long
)
fun syncWithLWW(
localItems: List<ShoppingItem>,
remoteItems: List<ShoppingItem>
): List<ShoppingItem> {
val merged = localItems.toMutableList()
remoteItems.forEach { remote ->
val index = merged.indexOfFirst { it.id == remote.id }
if (index == -1) {
merged.add(remote)
} else {
val local = merged[index]
merged[index] = if (remote.lastModified >= local.lastModified)
remote
else
local
}
}
return merged
}
Функција syncWithLWW спаја локалну и удаљену листу: ако елеменат постоји само на једној страни — додаје се, ако на обема — побеђује новија верзија. Оваў приступ осигурава детерминистичку синхронизацију за сваки појединачни елеменат.
Избор између LWW и Merge одређује природа модификације података. Ако апликација дозвољава независне промене поља (различити корисници мењају различита поља истог објекта), Merge Strategy ће прецизније сачувати податке. Ако су промене увијек атомне (корисник мења цео објекат), LWW је потпуно адекватан и значно једноставнији за имплементацију.
У пракси, многи системи примењују хибридни приступ: LWW за мета-информације и поља вишег нивоа, Merge за структуриране податке. Firebase Firestore, на примјер, користи LWW за већину операција, али подржава транзакције са оптимистичким закльучавањем за атомска ажурирања када програмер јасно наведе да поље не сме да се изгуби при конфликту.
Према анкети развијача расподељених система (Stack Overflow Survey, 2025), 54% бира LWW за MVP и прототипове, прелазећи на Merge или CRDT у фази скалирања. Кључни критеријум је учесталост конфликата: ако мање од 1% сесија доводи до конфликата, LWW је више него довољан. Ако конфликти погађају више од 5% сесија, вреди уложити у Merge или CRDT.
Често постављана питања
Last Write Wins (LWW) — стратегија решавања конфликата при којој се од двију конкурентних верзија бира запис са најкаснијим временским жигом. Ово је најједноставнији механизам конвергенције који се користи у Firebase, Cassandra и DynamoDB.
LWW се користи у Firebase Realtime Database, Apache Cassandra, Riak KV, Amazon DynamoDB (режим последњег уписа) и CouchDB-у за поља вишег нивоа. Већина документних NoSQL база података подразумевано примењују LWW.
Да, губитак података је могућ. Ако су два корисника промијенила различита поља истог објекта, LWW одбацује старију верзију у потпуности заједно са свим њеним променама. За независна поља, пожељније је Merge Strategy или CRDT.
Да бисте минимизирали губитке користите server-side timestamp, чувајте историју верзија за ревизију и примењујте LWW само за оне податке где је последња верзија објективно исправна. За структурирана поља, размотрите Merge Strategy на нивоу поља.
Утицај је минималан. LWW захтева само поређење двију бројчаних вредности (O(1)), што га чини најбржом стратегијом. Firebase Realtime Database обрађује до 100 хиљада конфликата у секунди на једном чвору без приметног пада перформанси.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.