Immich skalieren: Wie wir Reverse Geocoding für massive Fotobibliotheken neu entwickelt haben

PixelUnion Team
6 min read
Immich skalieren: Wie wir Reverse Geocoding für massive Fotobibliotheken neu entwickelt haben

Einführung: Die Magie zu wissen “Wo”

Für Home-Lab-Enthusiasten und Datenschutz-Befürworter ist Immich zu einer führenden selbst gehosteten Lösung für Foto- und Videoverwaltung geworden. Es bietet eine leistungsstarke, private Alternative zu cloudbasierten Diensten. Eine der überzeugendsten Funktionen ist ein Stück Hintergrundmagie: Reverse Geocoding. Dieser Prozess analysiert automatisch die GPS-Koordinaten, die in den EXIF-Daten eines Fotos eingebettet sind, und reichert es mit menschenlesbarem Standortkontext an—die Stadt, den Bundesstaat und das Land, in dem das Bild aufgenommen wurde.

Wie in der offiziellen Immich-Dokumentation erwähnt, wird diese leistungsstarke Funktion von der umfassenden GeoNames-Geografiedatenbank angetrieben. Dies ermöglicht es Immich, einen einfachen Satz von Koordinaten in aussagekräftige Informationen umzuwandeln, die Sie zum Suchen und Organisieren Ihrer Erinnerungen verwenden können.

Aber was passiert, wenn diese elegante, eigenständige Funktion nicht nur für einen einzelnen Benutzer, sondern über eine massive, Multi-Tenant-Plattform funktionieren muss? Dies war die Skalierungsherausforderung, der wir bei PixelUnion gegenüberstanden, und sie zwang uns, neu zu überdenken, wie diese Magie geliefert wird.

Die Herausforderung: Immich’s Standard-Geocoding in großem Maßstab

Um eine bessere Lösung zu entwickeln, mussten wir zunächst das strategische Design von Immich’s Standard-Architektur schätzen. Der Standardansatz ist brillant für seine Zielgruppe von Einzelbenutzern, aber seine Kern-Design-Entscheidungen schaffen vorhersehbare Engpässe, wenn sie für eine große Benutzerbasis mit Tausenden von Fotobibliotheken eingesetzt werden.

Wie Standard-Immich-Geocoding funktioniert

In einer Standardkonfiguration lädt Immich den GeoNames-Datensatz herunter und lädt ihn direkt in eine lokale PostgreSQL-Datenbanktabelle. Laut Dokumentation wird dieser Importprozess bei jedem Minor-Versions-Upgrade ausgelöst, um sicherzustellen, dass die Standortdaten auf dem neuesten Stand bleiben.

Der primäre Vorteil dieser Architektur ist klar: Sie hält die gesamte Datenverarbeitung vollständig eigenständig auf dem Server des Benutzers. Dies verbessert die Privatsphäre und die operative Einfachheit, da es keine externen Abhängigkeiten für diese Kernfunktion gibt. Für einen typischen Self-Hoster, der seine persönliche Bibliothek verwaltet, ist eine Datenbanktabelle von etwa 100MB eine perfekt vernünftige und effiziente Lösung für die schnellen, lokalen Lookups, die sowohl die Standortanzeige als auch Immich’s “Smart Search”-Funktionalität antreiben.

Der Engpass bei großen Bereitstellungen

Dieses eigenständige Modell beginnt in groß angelegten, Multi-User-Umgebungen wie unserer bei PixelUnion zusammenzubrechen. Das Kernproblem ist Datenbank-Bloat. Wenn diese einzelne ~100MB Geodaten-Tabelle über Hunderte oder Tausende von individuellen Datenbankinstanzen repliziert wird, wird der kumulative Speicher-Overhead immens. Dies stellte erhebliche operative Herausforderungen dar und erhöhte die Schwierigkeit und die Kosten, die mit der Skalierung unserer sehr großen Postgres-Infrastruktur verbunden sind, dramatisch.

Ein sekundäres Problem war der repetitive Overhead des Import-Jobs selbst. Der Prozess des Herunterladens und Ladens des Datensatzes, der nach jedem Immich-Update läuft, wird zu einer sehr ineffizienten und ressourcenintensiven Aufgabe, wenn er über unsere gesamte Bereitstellung multipliziert wird. Wir brauchten einen Weg, diese Funktion zu zentralisieren, ohne ihre Leistung zu beeinträchtigen.

Unsere Lösung: Geocoding mit einem Microservice entkoppeln

Unser strategisches Ziel war es, die Geocoding-Funktion von der primären Immich-Datenbank zu entkoppeln. Diese Architekturverschiebung wurde entwickelt, um mehr Flexibilität, Effizienz und Skalierbarkeit zu liefern, ohne Immich’s Kern benutzerorientierte Funktionen zu ändern. Wir zielten darauf ab, das Skalierungsproblem auf Infrastrukturebene zu lösen, während das Verhalten der Anwendung konsistent bleibt.

Die Architekturverschiebung von lokaler Tabelle zu zentraler API

Unsere Lösung bestand darin, die direkte Datenbankabfrage durch einen einfachen API-Aufruf an einen dedizierten Microservice zu ersetzen. Anstatt dass jede Immich-Instanz ihre eigene Kopie der GeoNames-Daten verwaltet, betreiben wir jetzt einen einzigen, zentralisierten Geocoding-Microservice innerhalb unseres Clusters. Dieser Service hält die GeoNames-Daten und stellt API-Endpunkte bereit, um sowohl Reverse-Geocoding-Anfragen als auch Ortsnamensuchen für alle Immich-Instanzen zu behandeln.

Entscheidend ist, dass der Microservice so konzipiert ist, dass er Daten im exakt gleichen Format zurückgibt, das Immich von seiner internen Datenbankabfrage erwartet. Dies macht die Architekturänderung für die Anwendungslogik vollständig transparent und erfordert nur eine geringfügige Änderung, um Anfragen an die neue API statt an die lokale Tabelle zu richten.

Ein technischer Blick auf den Code

Um dies zu implementieren, führten wir eine neue Umgebungsvariable GEODATA_API_URL ein, wie in unserem Commit zur Immich-Codebasis zu sehen. Diese Variable fungiert als Feature-Flag, die einer Immich-Instanz mitteilt, ob sie die traditionelle Datenbankmethode oder unsere neue externe API für sowohl Geocoding- als auch Suchfunktionen verwenden soll.

Die Kernlogik, sichtbar in den Änderungen an map.repository.ts und search.repository.ts, folgt einer einfachen bedingten Prüfung für jede Funktion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// In map.repository.ts
IF GEODATA_API_URL is configured:
   call reverseGeocodeViaApi(point, GEODATA_API_URL)
ELSE:
   call reverseGeocodeViaDatabase(point)

// In search.repository.ts
IF GEODATA_API_URL is configured:
   call searchPlacesViaApi(placeName, GEODATA_API_URL)
ELSE:
   call searchPlacesViaDatabase(placeName)

Diese elegante Änderung ist aus zwei Gründen mächtig. Erstens macht sie die neue Funktion zu einer Opt-in-Verbesserung, die perfekte Rückwärtskompatibilität für alle bestehenden Immich-Benutzer erhält. Zweitens bietet sie einen sauberen, konfigurierbaren Weg für skalierte Bereitstellungen wie unsere, um die gesamte Geodaten-Workload zu entlasten, ohne einen komplexen oder invasiven Fork der Hauptanwendung zu erfordern.

Die Auswirkungen: Messbare Gewinne und ein skalierbareres Immich

Diese Architekturänderungen waren nicht nur theoretische Verbesserungen; sie führten zu erheblichen, messbaren Verbesserungen der Effizienz, Kosteneffektivität und Wartbarkeit unserer Plattform.

Realisierte Hauptvorteile

  • Drastische Datenbank-Diät: Der unmittelbarste Sieg war eine dramatische Reduzierung der Größe jeder Immich-Datenbankinstanz. Durch das Entfernen der ~100MB Geodaten-Tabelle aus der Datenbank jedes Benutzers haben wir eine massive Menge an Speicherplatz über unserem Cluster zurückgewonnen.
  • Vereinfachte Updates: Unsere Änderung eliminiert vollständig den Geodaten-Import-Job, den Immich zuvor nach jedem Update ausführte. Dies spart erhebliche Zeit und Rechenressourcen während unserer plattformweiten Update-Zyklen. Dies wird durch die neue Logik im Code bestätigt, die explizit protokolliert, dass sie “lokalen Geodaten-Import überspringt”, wenn unsere externe API konfiguriert ist.
  • Verbesserte Skalierbarkeit: Mit einem kleineren Datenbank-Footprint ist die gesamte Immich-Bereitstellung einfacher zu verwalten, zu sichern und zu skalieren. Darüber hinaus verbessert die Zentralisierung der Logik die Leistung und Konsistenz sowohl der Standortdatenanreicherung als auch der Suchabfragen über die Plattform, was es uns ermöglicht, mehr Benutzer effizienter und kosteneffektiver zu unterstützen.

Offen für alle

Wir glauben an die Kraft von Open Source und daran, den Gemeinschaften etwas zurückzugeben, die unglaubliche Tools wie Immich bauen. Diese Lösung wurde über unseren öffentlichen, Open-Source-Fork zurückgespendet. Sie können die genaue Implementierung, von der neuen Umgebungsvariablen bis zu den bedingten API-Aufrufen, im unten verlinkten Commit überprüfen.

Vollständigen Commit auf GitHub ansehen

Abschließende Gedanken

Unsere Reise von der Identifizierung eines kritischen Skalierungsengpasses bis zur Implementierung einer robusten, entkoppelten Microservice-Lösung hebt eine häufige Herausforderung in der Softwareentwicklung hervor: Eine Funktion, die für eine Skala perfekt ist, kann bei einer anderen zu einem Hindernis werden. Durch sorgfältige Analyse des Problems und Implementierung einer flexiblen, rückwärtskompatiblen Lösung konnten wir Immich’s Architektur für unsere Bedürfnisse verbessern und gleichzeitig eine wertvolle Option an die breitere Gemeinschaft zurückgeben. Bei PixelUnion bleiben wir Open Source verpflichtet und ermutigen alle in den Home-Lab- und Self-Hosting-Gemeinschaften, diese Art von Lösungen zu erkunden, anzupassen und darauf aufzubauen.