Einzigartigkeit von Objekten in Server - Client sicherstellen
-
Ich würde da ganz einfach sequential GUIDs verwenden: https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential
Je nachdem wie die DB das Feld sortiert muss man evtl. die Bits in der generierten GUID ein wenig rumschieben. Davon abgesehen sollte das die Anforderungen erfüllen.
Ansonsten... wenn die Clients eine eindeutige ID haben, dann kann man natürlich auch "locally unique identifiers" + die Client ID verwenden. In dem Fall kann man aus der zusammengehängten ID halt 1:1 rauslesen welcher Client sie angelegt hat. Was u.U. unerwünscht sein könnte.
Wobei... aus sequential GUIDs kann man auch so einiges rauslesen. Also die sollte man auch nicht in jedem Fall verwenden. Falls das ein Problem ist könnte allerdings jeder Client beim Installieren eine (non-sequential) GUID erzeugen und irgendwo abspeichern. Ausgehend von dieser kann man dann entweder einfach zählen (dann muss man den Zähler halt selbst managen). Oder man könnte sich dann pro Objekt eine sequential GUID erzeugen lassen, und die finale ID ist dann die Summe der gespeicherten GUID und der sequential GUID. Das clustert dann gleicht gut wie die sequential GUID, aber man kann nicht mehr auf die lokale MAC Adresse o.Ä. rückschliessen.
-
Hallo @Leon0402,
@Leon0402 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Und die Frage ist jetzt wie ich sicherstelle, dass meine Objekte einzigartig sind
Da kommt man meines Erachtens an eine Objekt-ID nicht vorbei. Es bietet sich ein eigener Typ an, der z.B. aus drei Werten bestehen könnte, die wären:
- Eine DB-ID (falls man Objekte aus mehreren Datenbanken haben möchte).
- Eine Class-ID (falls Klassen (Typen) unterschieden werden sollen).
- Ein Zähler, der aus der Datenbank ermittelt wird. Aus der DB, weil dann Server wie Client eine eindeutige zahl bekommen.
@Leon0402 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Der Client muss sich nicht mit dem Server verbinden bzw. kann auch offline arbeiten. Er muss also neue Objekte anlegen können ohne das er in diesem Moment mit dem Server verbunden ist.
Da sehe ich ein Problem. Wie soll verhindert werden, dass ein Server und ein nicht mit dem Server verbundener Client gleichzeitig schreiben? Von Problematiken mit Locks oder Transaktionen mal abgesehen. Möglich wäre ggf.: Client kann über Server oder direkt zugreifen. Client kann nicht direkt zugreifen wenn schon anderer Client oder Server zugreift. Server kann nur zugreifen wenn kein anderer Client oder Server zugreift.
Wie löst Du den z.Z. konkurrierende Schreibzugriffe von Clients auf die Datenbank?Gruß Helmut
-
@Helmut-Jakoby sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Da sehe ich ein Problem. Wie soll verhindert werden, dass ein Server und ein nicht mit dem Server verbundener Client gleichzeitig schreiben? Von Problematiken mit Locks oder Transaktionen mal abgesehen. Möglich wäre ggf.: Client kann über Server oder direkt zugreifen. Client kann nicht direkt zugreifen wenn schon anderer Client oder Server zugreift. Server kann nur zugreifen wenn kein anderer Client oder Server zugreift.
Wie löst Du den z.Z. konkurrierende Schreibzugriffe von Clients auf die Datenbank?Ich verstehe nich so ganz, was du meinst. Also natürlich hat jeder Client seine eigene Datenbank und es gibt (erstmal) eine zentrale Server Datenbank auf dir nur der Server zugreift.
Insofern ist das einzige konkurrierende gleichzeitige Anfragen an den Server und gleichzeitiges Schreiben mehrerer Threads des Servers.Ist aus meiner Sicht hier ein anderes Problem, was aber die meisten Server Datenbanken auch schon implementieren afaik.
Vlt. willst du auch auf Synchronisierung hinaus? Also klar wenn Client A in seine lokale Datenbank schreibt und Client B auch in seine lokale Datenbank schreibt und das selbe Objekt anders verändern, dann gibt es ein Konflikt, sobald beide irgendwann zum Server pushen / pullen. Konflikt Behebung sehe ich aber auch hier als ein eigenes Problem. Der einfachste Ansatz ist hier ja: Don't care ... einfach das neuste nehmen. Oder den User fragen willste die Version oder die? etc. ... das gibt es viele recht einfache Ansätze für den Start.
-
Nur so als Idee, was spricht denn dagegen in der SQL-Datenbanktabelle eine Spalte "SYSID" o.ä. zu ergänzen, die quasi den Client angibt, der den Datensatz erfasst hat und eine "ID" Spalte, die die ID aus der Client-DB enthält?
Damit spart man sich Nummernblöcke. Den entsprechenden Entstehungsort des Datensatzes kriegt man dann über die SYSID raus.
-
@inflames2k Nichts direkt. Das ist ja quasi die Idee von @hustbaer und in gewisser Weise auch die von Nummernblöckern (Nummerblock = client id, statt hochzählen des Nummernblocks wird eine neue hochgezählte Variable hinten dran gehängt)
Die Nachteile sind halt:
- Der Client braucht ne unique id und man kann halt von objekten Rückschlüsse auf den Client führen (wobei das in meinem Fall denke ich kein Problem wäre)
- Man hat mehr Verwaltungsaufwand, weil quasi zwei verschiedene Ids
Wobei letzeres nur auf deine Idee zutrifft. So wie ich hustbaer verstanden habe, war da die Idee beides direkt in ein Feld zu mergen.
Bei deiner Idee würden mich dann auch etwas wieder Design Fragen plagen:
z.B. sollten die IDs Teil des Domain Models sein? Lokal reicht ja die ID zu Identifizierung, die SYSID wäre quasi ein Implementierungsdetail vom Server.
-
@SeppJ sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Klingt nach einem Rezept für Kollisionen. Für so etwas willst du entweder systematisch ausschließen, dass es jemals Kollisionen gibt (z.B. mein Vorschlag), oder wenn es vom Zufall abhängt, dann sollte es doch so unwahrscheinlich sein, dass eher das Universum ausbrennt als das man kollidiert (GUID).
Das ganze Vorgehen klingt nach einem Rezept für Kollisionen. Egal was für man eine ID zusammenbaut, entscheidend ist, dass die Daten gleich sein können, d.h. man wird unbedingt den Inhalt auf Gleichartigkeit prüfen müssen. Und ich habe meine Zweifel, dass IPv6 Adressen+Zeitstempel wirklich zu einer Kollision führen. Aber man kann natürlich auch die MAC+Zeitstempel nehmen.
-
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Aber man kann natürlich auch die MAC+Zeitstempel nehmen.
Womit man eine Version 1 UUID nachbaut. Dann würde ich gleich zum Original greifen.
-
@john-0 So wie ich das verstanden habe, kann man bei der GUID eigentlich davon ausgehen, dass es keine Kollisionen gibt (weil zu unwahrscheinlich).
Der unwahrscheinliche Fall, dass es eine Kollision gibt, könnte man vermutlich auch ganz gut abfangen. Die Datenbank sollte ja einen Fehler schmeißen auf Server Seite, wenn eine Objekt mit gleichem Primary Key eingefügt wird. Dann kann der Server darauf reagieren. Müsste man nur überlegen wie man dem Client mitteilt, dass er doch bitte die ID nochmal ändern soll.
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Das ganze Vorgehen klingt nach einem Rezept für Kollisionen.
Welches ganze Vorgehen? Ein Server - Client Modell mit Offline Funktionalität? Oder die eindeutigen IDs Clientseitig zu generieren? -> Das war ja nicht in den Stein gemeißelt, sondern meine Idee. Ich freue mich auch gerne über Alternative Vorschläge!
@hustbaer sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Ansonsten... wenn die Clients eine eindeutige ID haben, dann kann man natürlich auch "locally unique identifiers" + die Client ID verwenden. In dem Fall kann man aus der zusammengehängten ID halt 1:1 rauslesen welcher Client sie angelegt hat. Was u.U. unerwünscht sein könnte.
Die Idee gefällt mir schon auch sehr gut. Ob es schlimm ist, wenn man den Client rauslesen kann? -> Eher nicht. Es sollte eh eine Zuordnung zu den Benutzeraccounts (Was ja fast das selbe wie zum einzelnen Client ist) geben.
Meine nächste Frage wäre jetzt allerdings. Woher bekommen die Clients ihre eigene ID?
Was ich an dieser Stelle dazu sagen sollte: Ich möchte eigentlich, dass der Server optional ist. Somit gibt es aus meiner Sicht nur 2 Möglichkeiten:
- Der Client generiert sie selbst
- Der Client bekommt erst bei (optionaler) Registrierung seine ID
Ich vermute, dass in beiden Fällen, die ID seperat abgespeichert werden sollte und nicht für jedes Objekt. Das wären sonst ja nur Dopplungen.
Perspektisch sehe ich hier allerdings ein Problem später, was Synchronisation angeht. Sagen wir Benutzer A hat 2 Clients und legt auf beiden offline ein neues Objekt an. Beide Rezepte haben somit dieselbe ID (Gehe mal davon aus, man nutzt ihr einfach Auto Increment). Jetzt pushen beide zum Server und es gibt natürlich den Konflikt.
Lösung: Clients pullen erst (sowieso sinnvoll) und der spätere Client stellt dann fest: Oh ein neues Objekt hat die selbe ID wie eins in meiner Datenbank. Aber das in der Datenbank ist nicht auf dem Server bisher, also muss es ein anderes sein. Deswegen verschiebt dann der Client das nicht synchronisierte Objekt in der Datenbank auf eine neue unbesetze Stelle.
Das klingt potentiell nervig. Insbesondere wenn es den Konflikt direkt bei mehreren Objekten gibt, weil beide Clients länger offline waren.
Nutzt man jetzt nicht Auto Increment, sondern generiert ne zufällige (aber eher kleine) Zahl ist das Risiko minimiert, aber natürlich nicht weg.
-
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Das ganze Vorgehen klingt nach einem Rezept für Kollisionen. Egal was für man eine ID zusammenbaut, entscheidend ist, dass die Daten gleich sein können, d.h. man wird unbedingt den Inhalt auf Gleichartigkeit prüfen müssen. Und ich habe meine Zweifel, dass IPv6 Adressen+Zeitstempel wirklich zu einer Kollision führen. Aber man kann natürlich auch die MAC+Zeitstempel nehmen.
Deine Zweifel oder dein Unwissen um die Eigenschaften von MAC-Adressen sind irrelevant.
-
@Leon0402 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Das ganze Vorgehen klingt nach einem Rezept für Kollisionen.
Welches ganze Vorgehen? Ein Server - Client Modell mit Offline Funktionalität? Oder die eindeutigen IDs Clientseitig zu generieren? -> Das war ja nicht in den Stein gemeißelt, sondern meine Idee. Ich freue mich auch gerne über Alternative Vorschläge!
Die IDs auf Clientseite lösen das Problem nicht! Das Problem ist, dass durch den Offline Betrieb Kopien oder konkurrierende neue Einträge entstehen können, und Du Dir darüber Gedanken machen musst wie Du diese Konflikte löst. Eine ID auf Clientseite ist dabei überhaupt nicht hilfreich, weil sie suggeriert, dass es keinen Konflikt gäbe.
Beispiel:
Die DB enthält Adressdaten mit folgendem Eintrag
Hans Mustermann
Musterstraße 2
99999 MusterdorfNutzer A ändert den Eintrag auf
Hans Mustermann
Musterstraße 1
99998 MusterstadtNutzer B ändert den Eintrag auf
Heinz Mustermann
Musterstraße 2
99999 MusterdorfWelcher Eintrag ist denn nun korrekt? Analog besteht die Möglichkeit, dass beim offline Erzeugen neuer Einträge exakt die gleiche Problematik auftritt. Wenn der Abgleich über eine UUID erfolgt, dann gibt es keinen Konflikt, wenn der Abgleich über die Daten erfolgt, dann brauchst Du auch keine UUID.
-
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
und Du Dir darüber Gedanken machen musst wie Du diese Konflikte löst. Eine ID auf Clientseite ist dabei überhaupt nicht hilfreich, weil sie suggeriert, dass es keinen Konflikt gäbe.
Boah wenn Leute die keinen Plan haben einfach mal die Pappm hoitn würden.
-
@john-0 sagte in Einzigartigkeit von Objekten in Server - Client sicherstellen:
Die IDs auf Clientseite lösen das Problem nicht! Das Problem ist, dass durch den Offline Betrieb Kopien oder konkurrierende neue Einträge entstehen können, und Du Dir darüber Gedanken machen musst wie Du diese Konflikte löst. Eine ID auf Clientseite ist dabei überhaupt nicht hilfreich, weil sie suggeriert, dass es keinen Konflikt gäbe.
Beispiel:
Die DB enthält Adressdaten mit folgendem Eintrag
Hans Mustermann
Musterstraße 2
99999 Musterdorf
Nutzer A ändert den Eintrag auf
Hans Mustermann
Musterstraße 1
99998 Musterstadt
Nutzer B ändert den Eintrag auf
Heinz Mustermann
Musterstraße 2
99999 Musterdorf
Welcher Eintrag ist denn nun korrekt? Analog besteht die Möglichkeit, dass beim offline Erzeugen neuer Einträge exakt die gleiche Problematik auftritt. Wenn der Abgleich über eine UUID erfolgt, dann gibt es keinen Konflikt, wenn der Abgleich über die Daten erfolgt, dann brauchst Du auch keine UUID.Ich glaube du sprichst hier zwei verschiedene Thematiken an. Mir geht es nur um eine eindeutige Indendifikation der Einträge zu ermöglichen. Du schreibst in deinem Beispiel:
"den Eintrag" -> Welchen Eintrag? Woher weißt du, dass das "Der Eintrag" ist und nicht irgendein x-beliebiger ander Eintrag, der halt zufällig die selben Daten hat. Indem du eben eine ID hast, denn es gibt (wie am Anfang gesagt) keinen natural key. Es muss also eine Idenfikation geben, damit du weißt, dass irgendein Client "den Eintrag" verändert hat
Was du beschreibst sind Konflikte. Daher man hat bereits eindeutig festgestellt, dass zwei verschiedene Client zeitgleich (während sie offline waren) dieselben Daten beschrieben haben. Wie geht man damit um?
Das ist definitiv ein Problem mit vermutlich vielen Ansätzen:
- Man nimmt einfach den ersten / letzen (Don't care)
- Man fragt den Nutzer, welchen er haben möchte
- Man hat automatische oder Teil-automatische Merge Konflikt Algorithmen (siehe z.B. git)
- ....
Aber es ist ein anderes Problem und war erstmal nicht direkt meine Frage.
Daher noch mal meine Frage: Wie identifiziert man ein Objekt eindeutig in einem Multi-Client - Server Szenerario mit Offline Funktionalität. Wer generiert wann wo die dazu nötigen eindeutigen Daten (Ids)? Welche Idenfikation wird wo gespeichert?
Einige Ansätze waren:
- Der Client generiert eine eindeutige ID (per UUID). Das Objekt wird sowohl lokal als auch auf dem Server nur über diese ID identifieziert.
- Der Client generiert eine eindeutige lokale ID (z.B. Auto Increment) und kombiniert sie mit einer eindeutigen statischen Client ID, die er bei erstmaliger Registrierung bekommt. Die ID wird entweder zusammengesetzt <lokale-Id>-<Client-id> oder eben beides seperat abgespeichert auf Server Seite
- Der Client generiert eine eindeutige lokale ID (z.B. Auto Increment) und der Server generiert beim ersten hochladenen eine eindeutige globale ID, welche er dem Client mitteilt. Serverseitig wird nur nur die globale ID gespeichert, Client Seitig beides.
Zusätzlich gab es noch ein paar Ideen dazwischen. Zum Beispiel @SeppJ hatte, wenn richtig verstanden, Ansatz 2 im wesentlichen vorgeschlagen. Nur das die Client IDs partioniert werden und dann die Client ID mit der lokalen auto increment ID addiert wird (anstatt das die IDs zusammengesetzt werden).