Bau DataBridge: Synchronisierung von 20 unabhängigen 4D-Systemen mit einem zentralen MySQL-Backend
Einige Softwareprojekte sind glamourös. Dies ist nicht. Es lebt im Hintergrund, arbeitet, während alle anderen schlafen, und wird nur bemerkt, wenn es versagt. Das ist genau der Grund, warum es wichtig ist.
Wir entwickeln derzeit unsere DataBridge-Schicht: eine Synchronisierungsmaschine, die rund 20 unabhängige 4D-Installationen mit einem zentralen MySQL-Backend verbindet, das die Website und verwandte Online-Dienste versorgt. Die eigentliche Herausforderung besteht darin, es sicher, wiederholt und vorhersehbar in einer Live-Produktionsumgebung zu tun, in der Benutzer arbeiten, Aufzeichnungen wechseln, Verbindungen verschwinden können und keine Maschine zur Quelle des Chaos werden darf.
Im Mittelpunkt dieser Arbeit steht eine Klasse, die die DBS-Struktur erweitert. Sie fungiert als Orchesterleiter für die Synchronisierung. Sie weiß, ob Synchronisation aktiv ist, wo der entfernte Endpunkt wohnt, ob Trigger aktiviert sind, ob ein Synchronisierungszyklus bereits ausgeführt wird, was der letzte HTTP-Fehler war und welche Aufzeichnungen sich geändert haben. Es hält auch eine Sammlung von Ereignislisten so offen Windows innerhalb der 4D Anwendung kann reagieren, wenn Remote-Änderungen ankommen. Mit anderen Worten, es ist nicht nur eine Transport-Schicht. Es ist auch die Koordinationsschicht zwischen der Datenbank, dem Netzwerk und der Benutzeroberfläche.
Die Architektur folgt einem einfachen, aber disziplinierten Modell. Lokale Änderungen werden zuerst durch Trigger erfasst. Wenn eine Aufzeichnung erstellt, modifiziert oder gelöscht wird, versucht der Trigger nicht sofort, mit dem Remote-Server zu synchronisieren. Stattdessen schreibt er einen Eintrag in eine lokale RecordSync-Schlange. Diese Entscheidung ist wichtig. Es entkoppelt die Datenbankbearbeitung von der Netzwerkkommunikation, was bedeutet, dass ein Benutzer, der eine Aufzeichnung speichert, nicht auf einen Remote-Server, einen HTTP-Anruf oder ein vorübergehendes Verbindungsproblem warten muss. Das lokale System bleibt reaktionsfähig und die Synchronisierung wird zu einer asynchronen Hintergrundverantwortung und nicht zu einem blockierenden Vorfeldproblem.
Sobald die Hintergrund-Sync-Schleife aufwacht, beginnt sie damit, zu testen, ob der entfernte Endpunkt erreichbar ist. Wenn die Verbindung gesund ist, führt die Brücke zwei verschiedene Phasen durch. Zuerst schiebt sie lokale Warteschlangeänderungen nach außen. Dann bringt sie entfernte Änderungen zurück. Dies sind absichtlich getrennte Flüsse. Einer behandelt den ausgehenden Absicht von der lokalen 4D-Maschine; der andere behandelt den eingehenden Zustand vom zentralen Backend. Diese Verantwortlichkeiten zu unterscheiden, macht den Code leichter zu begründen und macht Fehlverhalten viel leichter zu kontrollieren.
Die Lokal-zu-Remote-Phase liest in Reihenfolge angeordnet Reihen von RecordSync, erstellt eine Nutzlast und sendet sie in Chargen. Jede Nutzlast enthält den Namen der Tabelle, den Aufzeichnungszustand, primäre Schlüsselinformationen und gegebenenfalls die serialisierten Entitätsdaten selbst. Löschungen benötigen nur Identität und Zustand. Erstellungen und Modifikationen erfordern einen vollständigen Objekt-Snapshot. Sobald eine Charge erfolgreich bestätigt wurde, werden die entsprechenden Warteschlangen entfernt. Wenn der Versand fehlschlägt, werden sie absichtlich an Ort und Stelle gelassen, damit der nächste Zyklus sie erneut ausprobieren kann. Dies ist keine auffällige Technik, aber es ist die Art, die Systeme ehrlich hält.
Die eingehende Seite ist genauso vorsichtig. Die Brücke fragt den Server, wie viele Änderungen nach der letzten bekannten Sequenznummer warten, holt sie in Blöcken und wiederholt sie einzeln in den lokalen 4D Datenspeicher. Jede eingehende Änderung wird als erstellt, modifiziert oder gelöscht klassifiziert. Neue Aufzeichnungen werden erstellt, wenn sie noch nicht existieren. Modifizierte Aufzeichnungen werden in die passende Entität neu geladen. Nach der Verarbeitung wird die lokale gespeicherte Sequenznummer fortgeschritten, damit die Maschine genau weiß, wo sie sich im Stream befindet.
Dies klingt einfach, bis man den ältesten Feind aller Synchronisationsmotoren trifft: Rekursion. Wenn eine ferngesteuerte Modifikation lokal geschrieben wird und diese Schreibung eine neue Ausgangsänderung auslöst, kann das System in eine endlose Echokammer spiralen. Die Brücke verwendet daher einen TriggerKey, um Aufzeichnungen zu markieren, die derzeit aus der ferngesteuerten Synchronisation angewendet werden. Wenn der passende lokalen Auslöser losläuft, erkennt er, dass die Veränderung von der Brücke selbst entstanden ist und ignoriert sie.
Ein weiteres ruhiges, aber wesentliches Detail ist das Sperren. In einer echten Anwendung haben Benutzer möglicherweise bereits eine Aufzeichnung geöffnet, wenn ein Remote-Update eintrifft. Anstatt eine Speicherung zu zwingen, Daten zu überschreiben oder in einen Sperrkonflikt zu stürzen, versucht die Brücke zuerst, die Entität zu sperren. Wenn sie nicht kann, protokolliert sie die Situation und lässt das Element für einen späteren Zyklus zurück. Dies ist eine bewusste Entwurfsentscheidung: Verzögern Sie sicher, anstatt vorzugeben, dass Gleichzeitige Probleme nicht existieren.
Die Implementierung setzt auch Energie in die Beobachtbarkeit ein. Die Synchronisationsschicht schreibt Fortschrittsupdates in ein Palettenfenster, verfolgt verarbeitete Aufzeichnungen, speichert HTTP-Fehler und protokolliert jedes signifikante Ereignis in eine Synchronisierungsprotokolldatei. Entwickler, die an Hintergrundinfrastruktur arbeiten, kennen diese Wahrheit gut: Wenn etwas um 03:12 Uhr morgens schief geht, ist der Unterschied zwischen einer fünfminütigen Behebung und einer vierstündigen Untersuchung in der Regel die Qualität der Logging.
Neben der normalen inkrementellen Synchronisierung umfasst die Brücke auch Betriebswerkzeuge. Sie kann komplette Tabellen in das Remote-Backend schieben, Remote-Tabellen zurück in 4D bringen, Remote-Tabellen erstellen und lokale und Remote-Strukturen vergleichen. Das macht sie nicht nur für die tägliche Synchronisierung, sondern auch für die Einrichtung, Migration, Diagnose und kontrollierte Wiederherstellungsszenarien nützlich. Eine Synchronisierungsmaschine wird viel wertvoller, wenn sie das System nicht nur erklären, sondern auch bewegen kann.
Für Entwickler befindet sich dieses Projekt in einem interessanten Raum zwischen klassischer Geschäftssoftware und Distributed Systems Engineering. Auf der einen Seite gibt es 4D: reif, lokal, transaktionell, vertrauenswürdig. Auf der anderen Seite gibt es eine zentrale MySQL-gestützte Webplattform, die eine Konsistenz zwischen vielen Maschinen und vielen Nutzern erwartet. DataBridge existiert in der engen Passage zwischen diesen Welten. Es übersetzt nicht nur Daten, sondern auch Timing, Zustand, Ausfall, Wiederversuche, Sequenz und Vertrauen.
Es gibt noch viel Arbeit vor uns. Synchronisierungsmotoren sind nie wirklich fertig; sie werden im Laufe der Zeit verfeinert, gehärtet und neue Edge-Fälle gelehrt. Aber jede Verbesserung bringt das System näher an das, was Entwickler tatsächlich von der Infrastruktur wollen: etwas Zuverlässiges, das man vergessen kann. Letztendlich ist das das höchste Kompliment, das ein solcher Bauteil erhalten kann. Nicht Applaus, sondern Schweigen.