Aktualisiert am: 11. Juli 2025
7 Minuten Lesezeit
Erfahre, wie GitLab einen Leistungsengpass in einer 15 Jahre alten Git-Funktion aufgespürt und behoben hat, was zu einer verbesserten Effizienz führte.
Backups von Repositorys sind ein wichtiger Bestandteil jeder robusten Strategie für die Notfallwiederherstellung. Mit zunehmender Größe der Repositorys wird die Erstellung zuverlässiger Backups jedoch immer schwieriger. Das Backup unseres eigenen Rails-Repository dauerte 48 Stunden und zwang uns zu einer unmöglichen Entscheidung zwischen Backup-Häufigkeit und Systemleistung. Wir wollten dieses Thema sowohl für unsere Kund(inn)en als auch für unsere eigenen Benutzer(innen) in den Griff bekommen.
Schließlich haben wir das Problem auf eine 15 Jahre alte Git-Funktion mit O(N²)-Komplexität zurückgeführt und sie mit einer algorithmischen Änderung behoben, die die Backup-Zeiten exponentiell reduzierte. Das Ergebnis: niedrigere Kosten, weniger Risiko und Backup-Strategien, die tatsächlich mit deiner Codebase mitwachsen.
Es stellte sich heraus, dass es sich um ein Skalierungsproblem von Git handelt, das jedes große Repository betrifft. Hier erfährst du, wie wir es aufgespürt und behoben haben.
Sehen wir uns zunächst das Problem an. Wenn Unternehmen ihre Repositorys skalieren und Backups immer komplexer werden, stehen sie vor einigen Herausforderungen:
Zeitintensive Backups: Bei sehr großen Repositorys kann es mehrere Stunden dauern, bis ein Repository-Backup erstellt wird. Dies kann die Möglichkeit, regelmäßige Backups zu planen, beeinträchtigen.
Ressourcenintensität: Erweiterte Backup-Prozesse können erhebliche Serverressourcen verbrauchen, was sich möglicherweise auf andere Vorgänge auswirken kann.
Backup-Fenster: Für Teams, die rund um die Uhr arbeiten, kann es schwierig sein, angemessene Wartungsfenster für Prozesse zu finden, die so lange dauern.
Erhöhtes Ausfallrisiko: Prozesse, die über längere Zeit ausgeführt werden, sind anfälliger für Unterbrechungen durch Netzwerkprobleme, Neustarts von Servern und Systemfehler. So sind Teams manchmal dazu gezwungen, den gesamten sehr langen Backup-Prozess von Grund auf neu zu starten.
Race Conditions: Da es sehr lange dauert, ein Backup durchzuführen, kann sich das Repository während des Prozesses stark verändern. Dies kann möglicherweise zu einem ungültigen Backup führen oder das Backup unterbrechen, weil Objekte nicht mehr verfügbar sind.
Diese Herausforderungen können zu Kompromissen bei der Häufigkeit oder Vollständigkeit von Backups führen – ein inakzeptabler Kompromiss, wenn es um den Datenschutz geht. Erweiterte Backup-Fenster können Kund(inn)en zu Problemumgehungen zwingen. Einige setzen möglicherweise externe Tools ein, während andere die Backup-Häufigkeit reduzieren, was zu potenziell inkonsistenten Datenschutzstrategien im Unternehmen führen kann.
Sehen wir uns nun an, wie wir einen Leistungsengpass identifiziert, eine Lösung gefunden und diese bereitgestellt haben, um die Backup-Zeiten zu verkürzen.
Die Repository-Backup-Funktionalität von GitLab basiert auf dem Befehl git bundle create
, der einen vollständigen Snapshot eines Repository erfasst, einschließlich aller Objekte und Referenzen wie Branches und Tags. Dieses Bundle dient als Wiederherstellungspunkt, um das Repository in seinem genauen Zustand neu zu erstellen.
Die Implementierung des Befehls litt jedoch unter einer schlechten Skalierbarkeit im Zusammenhang mit der Referenzzählung, was zu einem Leistungsengpass führte. Je mehr Referenzen die Repositorys sammelten, desto mehr stieg die Verarbeitungszeit exponentiell an. In unseren größten Repositorys mit Millionen von Referenzen konnten Backup-Vorgänge mehr als 48 Stunden dauern.
Um die Grundursache dieses Leistungsengpasses zu identifizieren, haben wir ein Flammendiagramm des Befehls während der Ausführung analysiert.
Ein Flammendiagramm, das den Ausführungspfad eines Befehls durch seinen Stacktrace zeigt. Jeder Balken entspricht einer Funktion im Code. Die Breite des Balkens gibt an, wie viel Zeit der Befehl für die Ausführung innerhalb dieser bestimmten Funktion benötigt hat.
Bei der Untersuchung des Flammendiagramms von git bundle create
, das auf einem Repository mit 10 000 Referenzen ausgeführt wird, werden etwa 80 % der Ausführungszeit von der Funktion object_array_remove_duplicates()
verbraucht. Diese Funktion wurde in Git im Commit b2a6d1c686 eingeführt (bundle: allow the same ref to be given more than once, 17.01.2009).
Um diese Änderung zu verstehen, ist es wichtig zu wissen, dass git bundle create
es Benutzer(inne)n ermöglicht, anzugeben, welche Referenzen in das Bundle aufgenommen werden sollen. Für vollständige Repository-Bundles werden mit dem Flag --all
alle Referenzen gepackt.
Der Commit löste ein Problem, bei dem Benutzer(innen), die über die Befehlszeile doppelte Referenzen bereitstellten – wie z. B. git bundle create main.bundle main main
– ein Bundle erstellten, ohne die doppelte Hauptreferenz ordnungsgemäß zu verarbeiten. Das Entpacken dieses Bundles in einem Git-Repository würde fehlschlagen, da versucht würde, die gleiche Referenz zweimal zu schreiben. Der Code zum Vermeiden von Duplikaten verwendet verschachtelte for
-Schleifen, die alle Referenzen durchlaufen, um Duplikate zu identifizieren. Dieser O(N²)-Algorithmus wird in Repositorys mit einer großen Anzahl von Referenzen zu einem erheblichen Leistungsengpass, da er viel Rechenzeit verbraucht.
Um dieses Leistungsproblem zu lösen, haben wir einen Upstream-Fix für Git bereitgestellt, der die verschachtelten Schleifen durch eine Mapping-Datenstruktur ersetzt. Jede Referenz wird der Zuordnung hinzugefügt, wodurch automatisch sichergestellt wird, dass nur eine einzige Kopie jeder Referenz für die Bearbeitung gespeichert wird.
Diese Änderung verbessert die Leistung von git bundle create
drastisch und ermöglicht eine bessere Skalierbarkeit in Repositorys mit einer großen Anzahl von Referenzen. Benchmark-Tests mit einem Repository mit 10 000 Referenzen zeigen eine 6-fache Leistungssteigerung.
Benchmark 1: bundle (refcount = 100000, revision = master)
Time (mean ± σ): 14.653 s ± 0.203 s [User: 13.940 s, System: 0.762 s]
Range (min … max): 14.237 s … 14.920 s 10 runs
Benchmark 2: bundle (refcount = 100000, revision = HEAD)
Time (mean ± σ): 2.394 s ± 0.023 s [User: 1.684 s, System: 0.798 s]
Range (min … max): 2.364 s … 2.425 s 10 runs
Summary
bundle (refcount = 100000, revision = HEAD) ran
6.12 ± 0.10 times faster than bundle (refcount = 100000, revision = master)
Der Patch wurde akzeptiert und in den Git-Upstream zusammengeführt. Wir haben diesen Fix zurückportiert, damit unsere Kund(inn)en sofort davon profitieren können, ohne auf die nächste Git-Version warten zu müssen.
Die Leistungssteigerungen, die sich aus dieser Verbesserung ergeben haben, sind bahnbrechend:
Von 48 Stunden auf 41 Minuten: Das Erstellen eines Backups unseres größten Repositorys (gitlab-org/gitlab
) dauert jetzt nur noch 1,4 % der ursprünglichen Zeit.
Konsistente Leistung: Die Verbesserung funktioniert zuverlässig bei Repositorys jeder Größe.
Ressourceneffizienz: Wir haben die Serverlast während der Backup-Vorgänge deutlich reduziert.
Breitere Anwendbarkeit: Bei der Erstellung von Backups ist die Verbesserung am größten, aber auch alle Bundle-basierten Vorgänge, die mit vielen Referenzen arbeiten, profitieren davon.
GitLab-Kund(inn)en profitieren von dieser Erweiterung unmittelbar und spürbar, wenn es darum geht, wie Unternehmen die Sicherung von Repositorys und die Notfallwiederherstellung planen:
Transformierte Backup-Strategien
Bessere Geschäftskontinuität
Reduzierter betrieblicher Mehraufwand
Zukunftssichere Infrastruktur
Unternehmen können jetzt robustere Backup-Strategien umsetzen, ohne Kompromisse bei der Leistung oder Vollständigkeit einzugehen. Was früher ein schwieriger Kompromiss war, ist heute ein ganz normaler Vorgang.
Mit dem Release von GitLab 18.0 (nur in englischer Sprache verfügbar) können alle GitLab-Kund(inn)en unabhängig von ihrem Tarif diese Verbesserungen bereits in vollem Umfang für ihre Backup-Strategie und Ausführung (nur in englischer Sprache verfügbar) nutzen. Es ist keine weitere Änderung der Konfiguration erforderlich.
Dieser Durchbruch ist Teil unseres kontinuierlichen Engagements für eine skalierbare, unternehmensgerechte Git-Infrastruktur. Die Reduzierung der Zeit für die Erstellung von Backups von 48 Stunden auf 41 Minuten ist bereits ein wichtiger Meilenstein. Wir arbeiten weiter daran, Leistungsengpässe in unserem gesamten Stack zu identifizieren und zu beheben.
Wir sind besonders stolz darauf, dass diese Verbesserung in das Git-Projekt integriert wurde und nicht nur den Benutzer(inn)en von GitLab, sondern auch der gesamten Git-Community zugutekommt. Dieser kollaborative Ansatz bei der Entwicklung stellt sicher, dass Verbesserungen gründlich geprüft, umfassend getestet und für alle zugänglich gemacht werden.
Tiefgreifende Infrastrukturarbeit wie diese ist die Art, wie wir bei GitLab an die Leistung herangehen. Nimm am virtuellen Launch-Event von GitLab 18 teil, um zu sehen, welche weiteren grundlegenden Verbesserungen wir einführen werden. Registriere dich noch heute!