Skalering af Immich: Sådan genkonstruerede vi reverse geocoding til massive fotobiblioteker

PixelUnion Team
5 min read
Skalering af Immich: Sådan genkonstruerede vi reverse geocoding til massive fotobiblioteker

Introduktion: Magien ved at vide “hvor”

For homelab-entusiaster og dataprivatlivsfortalere er Immich blevet en førende self-hosted løsning til foto- og videostyring. Den tilbyder et kraftfuldt, privat alternativ til cloud-baserede tjenester. En af dens mest overbevisende funktioner er et stykke baggrundsmagi: reverse geocoding. Denne proces analyserer automatisk GPS-koordinaterne indlejret i et fotos EXIF-data og beriger det med menneskelæsbar placeringkontekst – by, region og land hvor billedet blev taget.

Som bemærket i den officielle Immich-dokumentation drives denne kraftfulde evne af den omfattende GeoNames geografiske database. Det lader Immich omdanne et simpelt sæt koordinater til meningsfuld information du kan bruge til at søge og organisere dine minder.

Men hvad sker der når denne elegante, selvstændige funktion skal fungere ikke kun for en enkelt bruger, men på tværs af en massiv, multi-tenant platform? Det var skaleringsudfordringen vi stod over for hos PixelUnion, og den drev os til at genopfinde hvordan denne magi leveres.

Udfordringen: Immichs standard-geocoding i skala

For at udvikle en bedre løsning måtte vi først sætte pris på den strategiske design af Immichs standardarkitektur. Standardtilgangen er genial for sin tiltænkte målgruppe af enkeltbrugere, men dens kerne designvalg skaber forudsigelige flaskehalse når deployeret til en stor brugerbase med tusindvis af fotobiblioteker.

Sådan fungerer standard Immich-geocoding

I en standardopsætning downloader Immich GeoNames-datasættet og loader det direkte ind i en lokal PostgreSQL-databasetabel. Ifølge dokumentationen udløses denne importproces under hver minor version-opgradering, så placeringdata forbliver opdateret.

Den primære fordel ved denne arkitektur er klar: den holder al databehandling fuldstændig selvstændig på brugerens server. Det forbedrer privatliv og operationel enkelhed, da der ikke er eksterne afhængigheder for denne kernefunktion. For en typisk self-hoster der styrer deres personlige bibliotek er en databasetabel på omkring 100 MB en fuldstændig rimelig og effektiv løsning til de hurtige, lokale opslag der driver både placeringvisning og Immichs “Smart Search”-funktionalitet.

Flaskehalsen i store deployment

Denne selvstændige model begynder at bryde sammen i store, multi-bruger-miljøer som vores hos PixelUnion. Kerneproblemet er database-opsvulming. Når den enkelte ~100 MB geodata-tabel replikeres på tværs af hundredvis eller tusindvis af individuelle databaseinstanser bliver den kumulative lagringsoverhead enorm. Det medførte væsentlige operationelle udfordringer og øgede drastisk vanskelighed og omkostning ved at skalerer vores meget store Postgres-infrastruktur.

Et sekundært problem var den gentagne overhead fra import-jobbet selv. Processen med at downloade og loade datasættet, der kører efter hver Immich-opdatering, bliver en meget ineffektiv og ressourcekrævende opgave når multipliceret på tværs af hele vores deployment. Vi havde brug for en måde at centralisere denne funktion på uden at gå på kompromis med dens ydeevne.

Vores løsning: Adskillelse af geocoding med en mikrotjeneste

Vores strategiske mål var at adskille geocoding-funktionen fra den primære Immich-database. Dette arkitekturskift var designet til at levere større fleksibilitet, effektivitet og skalerbarhed uden at ændre Immichs kerne bruger-vendte funktioner. Vi sigtede mod at løse skaleringsproblemet på infrastrukturniveau mens vi holdt applikationens adfærd konsistent.

Det arkitektoniske skift fra lokal tabel til central API

Vores løsning var at erstatte den direkte databaseforespørgsel med et simpelt API-kald til en dedikeret mikrotjeneste. I stedet for at hver Immich-instans vedligeholder sin egen kopi af GeoNames-data kører vi nu en enkelt, centraliseret geocoding-mikrotjeneste inde i vores cluster. Denne tjeneste indeholder GeoNames-data og eksponerer API-endpoints til at håndtere både reverse geocoding-anmodninger og stedsøgninger for alle Immich-instanser.

Afgørende er mikrotjenesten designet til at returnere data i præcis samme format som Immich forventer fra sin interne databaseforespørgsel. Det gør arkitekturændringen fuldstændig gennemsigtig for applikationslogikken og kræver kun en mindre ændring for at rette anmodninger til det nye API i stedet for den lokale tabel.

Et teknisk blik på koden

For at implementere dette introducerede vi en ny miljøvariabel, GEODATA_API_URL, som set i vores commit til Immich-kodebasen. Denne variabel fungerer som en feature flag der fortæller en Immich-instans om den skal bruge den traditionelle databasemetode eller vores nye eksterne API til både geocoding- og søgefunktioner.

Kernelogikken, synlig i ændringerne i map.repository.ts og search.repository.ts, følger en simpel betinget tjek for hver 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)

Denne elegante ændring er kraftfuld af to grunde. For det første gør den den nye funktion til en opt-in forbedring og bevarer fuld bagudkompatibilitet for alle eksisterende Immich-brugere. For det andet giver den en ren, konfigurerbar vej for skalede deployment som vores til at aflaste hele geodata-arbejdsbyrden uden at kræve en kompleks eller invasiv forgrening af hovedapplikationen.

Indvirkningen: Målbare gevinster og en mere skalerbar Immich

Disse arkitektoniske ændringer var ikke bare teoretiske forbedringer; de resulterede i væsentlige, målbare forbedringer af vores platforms effektivitet, omkostningseffektivitet og vedligeholdelsesvenlighed.

Nøglefordele realiseret

  • Drastisk databasediæt: Den mest umiddelbare sejr var en dramatisk reduktion i størrelsen af hver Immich-databaseinstans. Ved at fjerne den ~100 MB geodata-tabel fra hver brugers database genvandt vi en massiv mængde lagring på tværs af vores cluster.
  • Forenklede opdateringer: Vores ændring eliminerer fuldstændigt geodata-import-jobbet som Immich tidligere kørte efter hver opdatering. Det sparer betydelig tid og computeressourcer under vores platformvide opdateringscykler. Det bekræftes af den nye logik i koden, der eksplicit logger at den ‘springer lokal geodata-import over’ når vores eksterne API er konfigureret.
  • Forbedret skalerbarhed: Med et mindre database-fodaftryk er hele Immich-deployment nemmere at styre, backe op og skalerer. Desuden forbedrer centralisering af logikken ydeevnen og konsistensen af både placeringdataberigelse og søgeforespørgsler på tværs af platformen og lader os understøtte flere brugere mere effektivt og omkostningseffektivt.

Åben for alle

Vi tror på open source og at give tilbage til de communities der bygger utrolige værktøjer som Immich. Denne løsning er bidraget tilbage via vores offentlige, open-source-forgrening. Du kan inspicere den præcise implementering, fra den nye miljøvariabel til de betingede API-kald, i commit’et linket nedenfor.

Se den fulde commit på GitHub

Afsluttende tanker

Vores rejse fra at identificere en kritisk skaleringsflaskehals til at implementere en robust, adskilt mikrotjenesteløsning fremhæver en almindelig udfordring i softwareteknik: en funktion der er perfekt i én skala kan blive en hindring i en anden. Ved omhyggeligt at analysere problemet og implementere en fleksibel, bagudkompatibel løsning var vi i stand til at forbedre Immichs arkitektur til vores behov mens vi bidrog med et værdifuldt valg tilbage til det bredere community. Hos PixelUnion forbliver vi forpligtet til open source og opfordrer alle i homelab- og self-hosting-communities til at udforske, tilpasse og bygge videre på disse slags løsninger.