Mettre à l'échelle Immich : Comment nous avons réingéniéré le géocodage inversé pour des bibliothèques photo massives

Introduction : La magie de savoir “Où”
Pour les passionnés de home lab et les défenseurs de la confidentialité des données, Immich est devenu une solution auto-hébergée de premier plan pour la gestion de photos et de vidéos. Il offre une alternative puissante et privée aux services basés sur le cloud. L’une de ses fonctionnalités les plus convaincantes est un peu de magie en arrière-plan : le géocodage inversé. Ce processus analyse automatiquement les coordonnées GPS intégrées dans les données EXIF d’une photo et l’enrichit avec un contexte de localisation lisible par l’homme—la ville, l’état et le pays où l’image a été capturée.
Comme indiqué dans la documentation officielle d’Immich, cette capacité puissante est alimentée par la base de données géographique complète GeoNames. Cela permet à Immich de transformer un simple ensemble de coordonnées en informations significatives que vous pouvez utiliser pour rechercher et organiser vos souvenirs.
Mais que se passe-t-il lorsque cette fonctionnalité élégante et autonome doit fonctionner non seulement pour un seul utilisateur, mais sur une plateforme multi-locataires massive ? C’était le défi de mise à l’échelle auquel nous avons été confrontés chez PixelUnion, et cela nous a poussés à réimaginer comment cette magie est livrée.
Le défi : Le géocodage par défaut d’Immich à grande échelle
Pour concevoir une meilleure solution, nous avons d’abord dû apprécier la conception stratégique de l’architecture par défaut d’Immich. L’approche standard est brillante pour son public cible d’utilisateurs individuels, mais ses choix de conception fondamentaux créent des goulots d’étranglement prévisibles lorsqu’ils sont déployés pour une grande base d’utilisateurs avec des milliers de bibliothèques photo.
Comment fonctionne le géocodage Immich standard
Dans une configuration standard, Immich télécharge le jeu de données GeoNames et le charge directement dans une table de base de données PostgreSQL locale. Selon la documentation, ce processus d’importation est déclenché lors de chaque mise à jour de version mineure, garantissant que les données de localisation restent à jour.
L’avantage principal de cette architecture est clair : elle maintient tout le traitement des données entièrement autonome sur le serveur de l’utilisateur. Cela améliore la confidentialité et la simplicité opérationnelle, car il n’y a pas de dépendances externes pour cette fonctionnalité de base. Pour un auto-hébergeur typique gérant sa bibliothèque personnelle, une table de base de données d’environ 100 Mo est une solution parfaitement raisonnable et efficace pour les recherches locales rapides qui alimentent à la fois l’affichage de la localisation et la fonctionnalité “Smart Search” d’Immich.
Le goulot d’étranglement dans les déploiements à grande échelle
Ce modèle autonome commence à s’effondrer dans des environnements multi-utilisateurs à grande échelle comme le nôtre chez PixelUnion. Le problème fondamental est le gonflement de la base de données. Lorsque cette seule table de géodonnées de ~100 Mo est répliquée sur des centaines ou des milliers d’instances de base de données individuelles, la surcharge de stockage cumulative devient immense. Cela a présenté des défis opérationnels importants, augmentant considérablement la difficulté et les coûts associés à la mise à l’échelle de notre très grande infrastructure Postgres.
Un problème secondaire était la surcharge répétitive du travail d’importation lui-même. Le processus de téléchargement et de chargement du jeu de données, qui s’exécute après chaque mise à jour d’Immich, devient une tâche très inefficace et gourmande en ressources lorsqu’elle est multipliée sur tout notre déploiement. Nous avions besoin d’un moyen de centraliser cette fonction sans compromettre ses performances.
Notre solution : Découpler le géocodage avec un microservice
Notre objectif stratégique était de découpler la fonction de géocodage de la base de données Immich principale. Ce changement architectural a été conçu pour offrir une plus grande flexibilité, efficacité et évolutivité sans modifier les fonctionnalités principales orientées utilisateur d’Immich. Nous visions à résoudre le problème de mise à l’échelle au niveau de l’infrastructure tout en gardant le comportement de l’application cohérent.
Le changement architectural de la table locale à l’API centrale
Notre solution consistait à remplacer la requête de base de données directe par un simple appel API à un microservice dédié. Au lieu que chaque instance Immich maintienne sa propre copie des données GeoNames, nous exécutons maintenant un seul microservice de géocodage centralisé dans notre cluster. Ce service détient les données GeoNames et expose des points de terminaison API pour gérer à la fois les demandes de géocodage inversé et les recherches de noms de lieux pour toutes les instances Immich.
Crucialement, le microservice est conçu pour renvoyer des données dans exactement le même format qu’Immich attend de sa requête de base de données interne. Cela rend le changement architectural complètement transparent pour la logique de l’application, nécessitant seulement une modification mineure pour diriger les demandes vers la nouvelle API au lieu de la table locale.
Un regard technique sur le code
Pour implémenter cela, nous avons introduit une nouvelle variable d’environnement, GEODATA_API_URL, comme on peut le voir dans notre commit vers la base de code Immich. Cette variable agit comme un indicateur de fonctionnalité qui indique à une instance Immich d’utiliser la méthode de base de données traditionnelle ou notre nouvelle API externe pour les fonctions de géocodage et de recherche.
La logique principale, visible dans les modifications de map.repository.ts et search.repository.ts, suit une vérification conditionnelle simple pour chaque fonction :
| |
Ce changement élégant est puissant pour deux raisons. Premièrement, il fait de la nouvelle fonctionnalité une amélioration opt-in, préservant une compatibilité descendante parfaite pour tous les utilisateurs Immich existants. Deuxièmement, il fournit un chemin propre et configurable pour les déploiements à l’échelle comme le nôtre pour décharger toute la charge de travail des géodonnées sans nécessiter un fork complexe ou invasif de l’application principale.
L’impact : Des gains mesurables et un Immich plus évolutif
Ces changements architecturaux n’étaient pas seulement des améliorations théoriques ; ils ont abouti à des améliorations significatives et mesurables de l’efficacité, de la rentabilité et de la maintenabilité de notre plateforme.
Avantages clés réalisés
- Régime drastique de la base de données : La victoire la plus immédiate a été une réduction dramatique de la taille de chaque instance de base de données Immich. En supprimant la table de géodonnées de ~100 Mo de la base de données de chaque utilisateur, nous avons récupéré une quantité massive de stockage sur notre cluster.
- Mises à jour simplifiées : Notre changement élimine complètement le travail d’importation de géodonnées qu’Immich exécutait auparavant après chaque mise à jour. Cela économise beaucoup de temps et de ressources de calcul pendant nos cycles de mise à jour à l’échelle de la plateforme. Ceci est confirmé par la nouvelle logique dans le code, qui enregistre explicitement qu’il “ignore l’importation locale de géodonnées” lorsque notre API externe est configurée.
- Évolutivité améliorée : Avec une empreinte de base de données plus petite, tout le déploiement Immich est plus facile à gérer, sauvegarder et mettre à l’échelle. De plus, la centralisation de la logique améliore les performances et la cohérence à la fois de l’enrichissement des données de localisation et des requêtes de recherche sur la plateforme, nous permettant de supporter plus d’utilisateurs plus efficacement et de manière plus rentable.
Ouvert à tous
Nous croyons en la puissance de l’open source et en redonner aux communautés qui construisent des outils incroyables comme Immich. Cette solution a été contribuée via notre fork open source public. Vous pouvez inspecter l’implémentation exacte, de la nouvelle variable d’environnement aux appels API conditionnels, dans le commit lié ci-dessous.
Voir le commit complet sur GitHub
Réflexions finales
Notre parcours de l’identification d’un goulot d’étranglement de mise à l’échelle critique à l’implémentation d’une solution de microservice robuste et découplée met en évidence un défi commun en ingénierie logicielle : une fonctionnalité qui est parfaite pour une échelle peut devenir un obstacle à une autre. En analysant soigneusement le problème et en implémentant une solution flexible et rétrocompatible, nous avons pu améliorer l’architecture d’Immich pour nos besoins tout en contribuant une option précieuse à la communauté élargie. Chez PixelUnion, nous restons engagés envers l’open source et encourageons tous ceux des communautés de home lab et d’auto-hébergement à explorer, adapter et construire sur ce type de solutions.