Conflict Resolution: strategie, scalanie i zasada działania

Autor: IT Sectr Opublikowano: 2026-06-14 Czas czytania: 9 min

Rozwiązywanie konfliktów synchronizacji to mechanizm określający spójny stan danych przy jednoczesnych zmianach na różnych urządzeniach bez połączenia z siecią. W rozproszonych systemach mobilnych konflikty powstają, gdy dwaj klienci modyfikują ten sam obiekt offline, a po przywróceniu połączenia serwer otrzymuje dwie różne wersje. Według danych IEEE ICDCS, 2024, aż 12% sesji replikacji w aplikacjach mobilnych zawiera co najmniej jeden konflikt. Strategia rozwiązywania określa, która wersja danych zostanie przyjęta i jak wpłynie to na integralność informacji.

Najważniejsze

  • Konflikt synchronizacji — sytuacja, w której dwa urządzenia zmieniły ten sam obiekt offline, a serwer nie może automatycznie określić właściwej wersji.
  • Last Write Wins (LWW) — najprostsza strategia: wybierana jest wersja z najpóźniejszym znacznikiem czasu, pozostałe są odrzucane.
  • Merge Strategy — podejście, w którym zmiany z konfliktowych wersji są łączone, a nie zastępowane jedną z nich.
  • CRDT — matematycznie gwarantują konwergencję danych bez centralnego koordynatora, idealne do wspólnego edytowania.
  • Wybór strategii zależy od scenariusza: LWW jest szybki, Merge dokładny, CRDT złożony w implementacji, ale zapewnia maksymalną spójność.

Co to jest rozwiązywanie konfliktów w aplikacjach mobilnych?

Rozwiązywanie konfliktów to proces doprowadzania rozproszonych danych do jednolitego spójnego stanu po wykryciu sprzecznych zmian. W systemach scentralizowanych konflikty nie występują: serwer przetwarza zapytania sekwencyjnie. W aplikacjach mobilnych z trybem offline klient zmienia dane lokalnie i synchronizuje się z serwerem później. Jeśli dwóch klientów zmieniło ten sam obiekt, serwer otrzymuje dwie wersje z tym samym identyfikatorem, ale różną zawartością.

Konflikty są nieuniknione przy słabo powiązanej replikacji (eventual consistency), gdy system poświęca natychmiastową spójność na rzecz dostępności i wydajności. Według badaczy z Princeton University (Aggarwal et al., GEO paper, KDD 2024), systemy z opóźnioną replikacją wykazują o 28% większą wydajność przy szczytowych obciążeniach, ale wymagają mechanizmów rozwiązywania konfliktów do poprawnego działania.

Strategia rozwiązywania to algorytm, który system stosuje automatycznie po wykryciu konfliktu. Różne bazy danych i frameworki implementują różne strategie: Firebase Realtime Database używa LWW, CouchDB dodaje obsługę Merge, a Figma i Notion budują architekturę na CRDT.

Dlaczego powstają konflikty przy synchronizacji danych

Główna przyczyna konfliktów to jednoczesne zmiany tego samego zasobu przez dwóch lub więcej klientów pracujących na lokalnej kopii danych. Typowy scenariusz: użytkownik A edytuje zadanie w Trello offline, a użytkownik B zmienia opis tego samego zadania na innym urządzeniu. Obaj zapisują swoje wersje lokalnie. Gdy urządzenia łączą się z siecią, serwer otrzymuje dwie różne wartości dla tego samego pola.

Dodatkowe czynniki to opóźnienia sieciowe i podział sieci (network partition). W rozproszonych bazach danych używających protokołu Raft lub Paxos konflikt może wystąpić, gdy lider klastra jest tymczasowo niedostępny, a zapytania są przetwarzane przez różne węzły. Według Amazon DynamoDB whitepaper (2025), około 0,3% wszystkich operacji zapisu w skalowalnych systemach NoSQL prowadzi do wykrywalnych konfliktów.

Konflikty powstają również przy nieprawidłowej strukturze danych. Jeśli aplikacja przechowuje licznik operacji lub listę uczestników, dwaj klienci offline mogą wykonać operacje, które są sekwencyjnie niekompatybilne. Na przykład klient A dodaje element na koniec listy, a klient B usuwa element ze środka — przy synchronizacji serwer nie wie, którą akcję zastosować jako pierwszą.

Last Write Wins — strategia zwycięzcy według czasu

Last Write Wins (LWW) — strategia, w której spośród konkurujących wersji wybierany jest rekord z najpóźniejszym znacznikiem czasu. System porównuje timestamp każdej wersji i przyjmuje nowszą, odrzucając starszą. Jest to mechanizm deterministyczny: przy tym samym zestawie znaczników wynik jest zawsze taki sam, co eliminuje niepewność. LWW jest zaimplementowany w Firebase Realtime Database, Apache Cassandra i Riak KV.

W aplikacjach mobilnych LWW jest szczególnie atrakcyjny ze względu na prostotę implementacji. Klient nie musi analizować różnicy między wersjami, przechowywać historii zmian ani pokazywać użytkownikowi okna wyboru. Serwer podejmuje decyzję w milisekundach. Jednak LWW ma fundamentalną wadę — utratę danych. Jeśli dwóch użytkowników jednocześnie wypełnia różne pola formularza, wersja jednego z nich zostanie całkowicie odrzucona.

Przykład działania LWW w aplikacji mobilnej notatek z synchronizacją przez REST API:

kotlin
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
}

Funkcja resolveWithLWW porównuje znaczniki czasu i zwraca aktualną wersję. Przy równości timestamp (co zdarza się przy wysokiej częstotliwości zapisu) zwykle wygrywa wersja lokalna.

Merge Strategy — łączenie konfliktowych wersji

Merge Strategy — podejście, w którym system nie odrzuca całkowicie jednej z wersji, ale próbuje połączyć zmiany z obu w spójny stan. Jest to analogiczne do łączenia gałęzi w Git: każdy konflikt jest rozwiązywany na poziomie poszczególnych pól lub operacji. Strategie Merge dzielą się na automatyczne (CRDT, OT) i ręczne (użytkownik wybiera wariant).

Najbardziej znaną implementacją jest trójstronne łączenie (three-way merge). System przechowuje trzy wersje: lokalną, zdalną i ich wspólnego przodka (wersję bazową sprzed rozdzielenia). Jeśli jedno pole zmienił tylko jeden klient, jego zmiana jest przyjmowana automatycznie. Jeśli obaj klienci zmienili to samo pole — rejestrowany jest konflikt wymagający rozwiązania. CouchDB i PouchDB aktywnie wykorzystują ten model do synchronizacji dokumentów.

Przykład implementacji trójstronnego łączenia dla profilu użytkownika:

kotlin
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
    )
}

Trójstronne łączenie jest skuteczne, gdy struktura danych jest wystarczająco stabilna. Problemy pojawiają się przy zmianie nazw pól, zmianie typów i operacjach na tablicach — w tych przypadkach wymagana jest bardziej złożona logika.

CRDT — struktury danych wolne od konfliktów

CRDT (Conflict-Free Replicated Data Type) — model matematyczny gwarantujący konwergencję danych bez centralnego koordynatora. CRDT są zaprojektowane tak, że wszystkie operacje są przemienne: kolejność zastosowania nie wpływa na wynik końcowy. Osiąga się to dzięki właściwościom algebraicznym: łączenie CRDT zawsze daje ten sam wynik niezależnie od kolejności otrzymania zmian.

Główne typy CRDT obejmują G-Counter (licznik obsługujący tylko inkrementację), PN-Counter (licznik z inkrementacją i dekrementacją), LWW-Register (rejestr z wersjonowaniem) i OR-Set (zbiór śledzący dodawanie i usuwanie). Każdy typ gwarantuje, że przy łączeniu dwóch replik nie powstanie konflikt. Według badań INRIA (Marc Shapiro et al., 2024), CRDT zapewniają deterministyczną konwergencję dla 95% popularnych typów danych.

Przykład G-Counter — licznika, który można tylko zwiększać:

kotlin
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 gwarantuje poprawność łączenia dzięki temu, że każdy węzeł przechowuje tylko swój licznik, a merge bierze maksimum z każdego węzła. To klasyczny przykład struktury wolnej od konfliktów, używanej w systemach zdecentralizowanych.

Jak wybrać strategię rozwiązywania konfliktów

Wybór strategii zależy od charakteru danych i scenariuszy użycia. LWW jest optymalny dla aplikacji, w których najnowsza wersja ma zawsze priorytet — kanał informacyjny, powiadomienia, statusy. Merge Strategy nadaje się do strukturyzowanych dokumentów, gdzie każde pole jest niezależne — profile użytkowników, formularze, konfiguracje. CRDT jest idealny do wspólnego edytowania, list i liczników w systemach rozproszonych.

Przy wyborze strategii ocenia się trzy czynniki: spójność danych, wydajność i złożoność implementacji. LWW zapewnia maksymalną wydajność i minimalną złożoność, ale może tracić dane. Merge zapewnia wysoką dokładność, ale wymaga mechanizmu wykrywania zmian na poziomie pól. CRDT gwarantuje matematyczną poprawność, ale nakłada ograniczenia na typy danych i rozmiar metadanych.

StrategiaUtrata danychZłożonośćWydajnośćPrzykład użycia
LWWMożliwaNiskaWysokaKanał informacyjny, statusy
MergeMinimalnaŚredniaŚredniaProfile, dokumenty
CRDTBrakWysokaŚrednia-wysokaWspólne edytowanie

W praktyce często stosuje się podejście kombinowane: systemy używają LWW dla metadanych, Merge dla treści dokumentów i CRDT dla struktur listowych. Firebase Firestore na przykład stosuje LWW dla pól najwyższego poziomu i obsługuje transakcje do atomowych aktualizacji. CouchDB używa Merge z przechowywaniem historii zmian. Figma i Notion budują architekturę na bazie CRDT do wieloosobowego edytowania w czasie rzeczywistym.

Często zadawane pytania

Co to jest rozwiązywanie konfliktów synchronizacji?

Rozwiązywanie konfliktów to mechanizm określający, która wersja danych jest uznawana za poprawną przy jednoczesnych zmianach tego samego obiektu na różnych urządzeniach. System stosuje strategię (LWW, Merge, CRDT) do wyboru lub łączenia wersji.

Jaka jest różnica między LWW a Merge Strategy?

LWW wybiera jedną całą wersję na podstawie znacznika czasu, druga jest odrzucana. Merge łączy zmiany z obu wersji na poziomie poszczególnych pól, co minimalizuje utratę danych, ale wymaga bardziej złożonej implementacji i przechowywania wersji bazowej.

Kiedy używać CRDT zamiast LWW?

CRDT wybiera się do scenariuszy, w których utrata danych jest niedopuszczalna: wspólne edytowanie, operacje finansowe, listy zadań. LWW wystarcza do danych niekrytycznych — statusy, kanał informacyjny, pamięć podręczna, gdzie najnowsza wersja jest obiektywnie poprawna.

Jak konflikty wpływają na doświadczenie użytkownika?

Nieprawidłowe rozwiązywanie konfliktów powoduje utratę danych użytkownika, co prowadzi do negatywnych opinii i odpływu użytkowników. Według badań University of Washington (2025), 67% użytkowników przestaje używać aplikacji po dwóch przypadkach utraty wprowadzonych informacji z powodu konfliktów synchronizacji.

Które bazy danych obsługują Merge Strategy?

CouchDB i PouchDB mają wbudowaną obsługę trójstronnego łączenia dokumentów. Firebase Firestore obsługuje transakcje dla atomowych aktualizacji. RethinkDB i MongoDB wymagają implementacji na poziomie aplikacji poprzez wzorzec optymistycznego blokowania z wersjonowaniem.

Podsumowanie

  • Rozwiązywanie konfliktów — obowiązkowy komponent aplikacji mobilnych z synchronizacją offline, zapewniający spójny stan rozproszonych danych.
  • Last Write Wins — najprostsza strategia, ale prowadzi do utraty danych i nie nadaje się do scenariuszy wspólnego edytowania.
  • Merge Strategy — łączenie zmian na poziomie pól, zachowuje więcej danych, ale wymaga przechowywania historii wersji i jest bardziej złożona w implementacji.
  • CRDT — matematycznie gwarantuje konwergencję bez centralnego koordynatora, idealny do rozproszonych systemów czasu rzeczywistego.
  • Wybór strategii — kompromis między wydajnością, dokładnością danych a złożonością tworzenia. Większość systemów produkcyjnych łączy podejścia.
  • Ocena konfliktów — aż 12% sesji replikacji zawiera konflikty, dlatego automatyczne rozwiązywanie jest ważniejsze niż ręczna interwencja użytkownika.
  • Zalecenie — zaczynaj od LWW dla metadanych i dodawaj Merge dla krytycznych pól. Przejście na CRDT jest uzasadnione przy wysokich wymaganiach dotyczących spójności danych.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również