7 points par GN⁺ 2025-12-27 | 2 commentaires | Partager sur WhatsApp
  • Plusieurs gestionnaires de paquets ont utilisé Git comme une base de données pour profiter de la gestion de versions et de la collaboration, mais à mesure que l’échelle augmente, ils se heurtent à des problèmes de performances et de maintenance
  • Cargo, Homebrew et CocoaPods, entre autres, ont finalement migré vers des index basés sur HTTP ou des CDN en raison de la croissance de la taille des index Git, de la lenteur des mises à jour et de l’inefficacité dans les environnements CI
  • vcpkg continue de fonctionner sur la base de hachages d’arbres Git, ce qui provoque des échecs de build et des contournements complexes dans les environnements en shallow clone
  • Le système de modules Go a introduit GOPROXY et une base de données de sommes de contrôle (sumdb) afin d’éliminer la dépendance à Git et d’améliorer la sécurité comme la vitesse
  • Git est excellent pour la collaboration sur le code, mais il apparaît de façon répétée qu’il est mal adapté aux requêtes sur les métadonnées de paquets et à la gestion de registres à grande échelle

Les échecs répétés des tentatives d’utiliser Git comme base de données

  • Git est attractif grâce à ses avantages comme l’historique des versions, l’architecture distribuée et l’hébergement gratuit, mais son utilisation comme base de données se heurte à des limites de montée en charge
  • Plusieurs gestionnaires de paquets ont adopté Git comme index, mais avec le temps les dégradations de performances et la charge d’infrastructure se sont aggravées

Cargo

  • L’index de crates.io a commencé comme un dépôt Git, et tous les clients effectuaient un clone complet
    • À mesure que le dépôt grossissait, un goulot d’étranglement de performance dans libgit2 est apparu pendant l’étape de delta resolution
    • Dans les environnements CI, l’index complet était téléchargé à chaque build, entraînant un gaspillage important
  • Via la RFC 2789, le protocole sparse HTTP a été introduit afin de ne récupérer via HTTPS que les métadonnées nécessaires
    • En avril 2025, 99 % des requêtes utilisent le mode sparse
    • L’index Git existe toujours, mais la majorité des utilisateurs n’y accèdent plus

Homebrew

  • GitHub a demandé à Homebrew de cesser d’utiliser les shallow clones, en signalant que les mises à jour étaient des « opérations très coûteuses »
    • Le dossier .git de homebrew-core approche 1 Go, et les mises à jour subissent des lenteurs liées à la delta resolution
  • En février 2023, avec Homebrew 4.0.0, la mise à jour des taps a basculé vers un téléchargement au format JSON
    • La suppression de git fetch a accéléré les mises à jour, et la fréquence des mises à jour automatiques est passée de 5 minutes à 24 heures

CocoaPods

  • Le gestionnaire de paquets CocoaPods pour iOS/macOS a vu son dépôt Specs, composé de plusieurs centaines de milliers de podspecs, devenir excessivement volumineux
    • Le clonage et les mises à jour prenaient plusieurs minutes, et l’essentiel du temps CI était consommé par les opérations Git
  • GitHub a appliqué une CPU rate limit, en désignant les shallow clones comme cause de la charge serveur
  • L’équipe a mis en place des mesures temporaires comme l’arrêt des fetch automatiques, le passage au clone complet et le sharding du dépôt
  • À partir de la version 1.8, le projet est passé à une distribution HTTP basée sur CDN, économisant environ 1 Go d’espace disque côté utilisateur et améliorant fortement la vitesse d’installation

Nixpkgs

  • Nix évite déjà le clonage Git côté client en utilisant des channels basés sur des tarballs
    • Les expressions de paquets sont fournies en HTTP depuis S3 et un CDN
  • Cependant, l’infrastructure de GitHub est sous pression à cause d’un dépôt de 83 Go et de 20 000 forks
    • En novembre 2025, GitHub a signalé des échecs de consensus entre réplicas et des erreurs lors des opérations de maintenance
    • Le clone local fait 2,5 Go, mais l’ensemble du réseau de forks exerce une pression sur l’espace de stockage de GitHub

vcpkg

  • Le gestionnaire de paquets C++ de Microsoft, vcpkg, utilise des hachages d’arbres Git pour le versionnement
    • Avec builtin-baseline, il faut l’historique complet pour reproduire les ports à un commit donné
  • Dans les environnements en shallow clone (GitHub Actions, DevContainers), cela provoque des échecs de build
    • La solution consiste à définir fetch-depth: 0, ce qui impose le téléchargement de l’historique complet
  • En raison de la structure des hachages d’arbres Git, le suivi des commits est impossible, et cette limite structurelle ne peut pas être corrigée
  • Le projet ne prend toujours en charge que des registres basés sur des dépôts Git, sans alternative HTTP ni CDN

Système de modules Go

  • L’équipe d’ingénierie de Grab a réduit le temps de go get de 18 minutes à 12 secondes après l’introduction d’un proxy de modules
  • L’ancienne méthode obligeait à cloner le dépôt complet de chaque dépendance pour pouvoir lire go.mod
  • L’équipe Go s’inquiétait de la dépendance aux outils VCS et des vulnérabilités de sécurité
  • Depuis Go 1.13, GOPROXY est la valeur par défaut, et les sources des modules ainsi que go.mod sont fournis en HTTP
    • sumdb (base de données de sommes de contrôle) garantit l’intégrité et la pérennité des modules

Problèmes généraux quand Git est utilisé comme base de données

  • Le wiki basé sur Git (Gollum) devient lent pour la navigation dans les répertoires et le chargement des pages sur de gros dépôts
    • GitLab prévoit d’abandonner Gollum
  • Le CMS basé sur Git (Decap) atteint la limite de 5 000 requêtes de l’API GitHub
    • Les performances se dégradent au-delà d’environ 10 000 entrées, et les nouveaux utilisateurs avec un cache vide provoquent une explosion des requêtes
  • Les outils GitOps (ArgoCD) rencontrent des problèmes de dépassement d’espace disque lors du clonage des dépôts
    • Un seul commit invalide l’intégralité du cache, et les gros monorepos nécessitent un dimensionnement séparé

Pourquoi Git est structurellement mal adapté comme base de données

  • Limites des répertoires : plus le nombre de fichiers augmente, plus cela ralentit
    • CocoaPods devait gérer 16 000 répertoires, ce qui générait d’énormes objets d’arbre, problème résolu par un sharding fondé sur le hachage
  • Problème de sensibilité à la casse : Git distingue les majuscules/minuscules, mais macOS et Windows non
    • Azure DevOps a ajouté une fonction de blocage côté serveur pour éviter les conflits
  • Limite de longueur des chemins : la limite de 260 caractères de Windows provoque des erreurs git status
  • Absence de fonctions de base de données :
    • Pas de contraintes CHECK/UNIQUE, pas de verrouillage, pas d’index, pas de migrations
    • Chaque gestionnaire de paquets doit construire son propre système de validation et d’indexation

Conclusion

  • Git est excellent pour la collaboration sur le code source, mais il est mal adapté aux requêtes sur les métadonnées de paquets et à la gestion de registres à grande échelle
  • La plupart des gestionnaires de paquets finissent par migrer vers des index basés sur HTTP ou des bases de données
  • Les avantages de Git (historique des versions, workflow de PR) sont attractifs, mais il échoue comme substitut à une base de données
  • Lors de la conception d’un nouveau gestionnaire de paquets, même si un index Git paraît séduisant, on atteint les mêmes limites que dans les cas de Cargo, Homebrew, CocoaPods, vcpkg et Go

2 commentaires

 
GN⁺ 2025-12-27
Commentaires sur Hacker News
  • Cela ressemble à une forme de tragédie des biens communs. GitHub est gratuit et offre beaucoup d’excellentes fonctionnalités, donc tout le monde veut l’utiliser. Mais ce type de décision se produit toujours quand il existe des externalités.
    L’externalité qui me paraît la plus importante, c’est le temps des utilisateurs. La plupart des entreprises de logiciels ne se préoccupent que du coût du temps d’ingénierie et ignorent le temps des utilisateurs. Elles se concentrent sur le développement de fonctionnalités, mais n’optimisent pas le temps d’interaction utilisateur. Par exemple, si je passe une heure à rendre une application plus rapide d’une seconde, un million d’utilisateurs économisent au total 277 heures par an. Mais comme le temps utilisateur est une externalité, ce genre d’optimisation est rarement fait
    Au final, les utilisateurs téléchargent plus de données que nécessaire et attendent inutilement, tandis que les développeurs ne sont pas tenus responsables de ce gaspillage

    • Je ne sais pas exactement ce que signifie l’expression « software house », mais dans la plupart des produits logiciels grand public sur lesquels j’ai travaillé, des métriques comme la vitesse de démarrage ou la latence étaient suivies de près. C’est du bon sens depuis des décennies. On entend souvent, par exemple, qu’Amazon perd des millions de dollars à cause de quelques millisecondes de chargement en plus sur une page
    • C’est dans la même logique que l’idée selon laquelle la vitesse est aussi une fonctionnalité. Mais le temps utilisateur dépend fortement non seulement des performances, mais aussi de la conception de l’interface
    • Je ne pense pas que ce soit une « tragédie des biens communs ». GitHub appartient à Microsoft, donc s’ils l’acceptent, c’est qu’ils estiment pouvoir en supporter le coût. Un vrai bien commun n’appartient à personne et bénéficie à tout le monde
    • Quand on réfléchit profondément à ce problème, on repense à cette phrase d’Alan Kay : « si vous prenez vraiment le logiciel au sérieux, vous devez aussi fabriquer votre propre matériel ». Le chargement via le réseau est intrinsèquement une mauvaise expérience utilisateur. Si on respecte vraiment les utilisateurs, il faut construire des applications local-first (native-first). Mais très peu d’entreprises respectent l’expérience utilisateur à ce point
    • Le texte d’Andy Hertzfeld « Saving Lives » est intéressant à ce sujet — on y trouve cette anecdote : « Le démarrage du Macintosh est beaucoup trop lent. Il faut le rendre plus rapide ! »
  • Je travaille sur un Cargo/UV pour le C. C’est un excellent article, et je m’y reconnais beaucoup.
    Quand on démarre, opérer un registre est vraiment difficile. Il ne faut pas seulement écrire du code, garantir la qualité de l’outil et faire grandir la communauté, mais aussi penser à une infrastructure capable d’absorber du trafic mondial. Dans ce contexte, une solution basée sur git est séduisante
    Mais le vrai problème, c’est le sparse checkout. On veut versionner les manifestes de paquets avec git, mais il faut suivre des commits arbitraires, ce qui est inefficace. En pratique, cela impose de pousser deux commits, ce qui rend la chose irréaliste
    À mon avis, l’approche de Conan est la plus pragmatique. Au lieu d’une reproductibilité parfaite, elle met de la logique conditionnelle dans le manifeste. Elle permet aussi d’associer des manifestes à des plages de versions. Ce n’est pas parfait, mais c’est un compromis pragmatique et utile.
    Bien sûr, la vraie solution serait d’utiliser une base de données, mais comme personne ne va payer à votre place les serveurs et la maintenance, c’est difficile en pratique

    • Si on change de perspective, la plupart des gestionnaires de paquets qui ont réussi ont commencé avec une base Git, puis ont migré vers une structure plus efficace quand c’est devenu nécessaire
    • L’approche de l’AUR d’Arch Linux mérite aussi d’être envisagée. Chaque paquet possède son propre dépôt git indépendant, qui ne contient que le manifeste. Cela permet d’éviter les problèmes de monorepo et le cauchemar des références croisées
    • Gérer un dépôt via un simple backend HTTP comme S3 est aussi séduisant. On peut commencer sur un serveur unique, puis chercher un sponsor et migrer vers le cloud si le projet devient populaire.
      Si le problème est l’argent et l’indépendance, une approche P2P est aussi possible. En revanche, sans cache CI, le trafic peut exploser
    • S’il n’y a pas encore beaucoup d’utilisateurs, préparer dès le départ une infrastructure mondiale est prématuré
    • Il n’est pas nécessaire d’exposer toutes les données d’historique aux utilisateurs. On peut rendre l’état du HEAD en fichiers statiques via un post-commit hook et le servir comme avec GitHub Pages.
      La structure de miroirs des distributions Linux comme Debian, Fedora ou openSUSE peut aussi servir d’inspiration
  • Cet article mélange deux problèmes. L’un est d’utiliser git comme base de données d’index de paquets, l’autre est de récupérer le code de chaque paquet via git. Ce sont deux sujets distincts.
    On peut avoir l’index dans git et les paquets en zip/tar, ou l’inverse. Dans le cas de Go, il n’y a même pas d’index du tout

    • L’auteur semble un peu confus. Je suis d’accord avec l’idée qu’« il ne faut pas que tous les utilisateurs répliquent la base de données », mais cela ne veut pas dire qu’on ne peut pas utiliser le graphe git comme encodage de données.
      Les détails sur le backend de GitHub ou les 20 000 forks ne sont pas essentiels. On peut faire des consultations clé-valeur efficaces sans arbre de travail git.
      L’idée que « réécrire l’historique git revient à faire une migration de base de données » est aussi étrange. Autant faire tourner un Postgres, non ?
    • Le point central de l’article n’est pas le code lui-même, mais le processus qui consiste à récupérer les fichiers go.mod. C’est pourquoi la solution adoptée a été d’héberger séparément les go.mod
    • Il est possible avec git de ne récupérer qu’un seul fichier si nécessaire, mais cela reste structurellement maladroit
  • L’approche « utilisons la solution la plus simple tant qu’elle fonctionne, et corrigeons plus tard si ça casse » est réaliste.
    Julia fonctionne aussi de cette manière, et avec un volume de paquets d’environ un septième de celui de Rust, cela ne pose pas encore de problème.
    On pourrait améliorer les choses en ne téléchargeant que le fichier racine Registry.toml, puis uniquement les paquets nécessaires. Ce n’est pas un gros problème

    • Julia utilise le registre git uniquement comme ledger officiel, et les clients réels passent par le Pkg Protocol
    • On pourrait qualifier cette approche d’esprit FAFO (essayons et voyons ce qui casse). C’est pragmatique, mais personnellement je n’aime pas trop ça
    • À mon avis, cette attitude est contraire à l’éthique. La logique du « faisons simple d’abord, on corrigera plus tard » finit toujours par accumuler de la dette technique.
      La culture du « Move fast and break things » est précisément ce qui nous a donné les logiciels lents et pleins de bugs d’aujourd’hui
    • Quand on corrige les problèmes plus tard, le coût augmente de manière exponentielle. On finit par conclure : « tant pis, utilisons-le tel quel, même un peu cassé ». Le cas de vcpkg cité dans l’article en est un bon exemple
    • Il y a un exemple où quelqu’un semble avoir manipulé intentionnellement un UUID, et le simple fait que ce soit possible m’inquiète un peu
  • Je suis d’accord avec la conclusion : « Git est une excellente base de données pour démarrer un gestionnaire de paquets »

    • Mais le client ne devrait pas recevoir l’intégralité du dépôt ; il vaut mieux intercaler un cache ou une couche de base de données. Dans les environnements CI/CD, l’efficacité est particulièrement importante
    • Nixpkgs a aussi réussi grâce à Git. Les problèmes d’échelle sont un luxe dont on se soucie plus tard
    • Mais avant de faire l’éloge de Git, il vaudrait mieux jeter au moins un œil à la recherche sur les bases de données
    • Git peut aussi devenir un cauchemar pour la supply chain. On pourrait revivre l’affaire Leftpad chaque semaine
    • Git est un très mauvais choix de base de données pour un gestionnaire de paquets. Si tout le monde l’utilise, c’est surtout parce que GitHub l’héberge gratuitement
  • Mon point de vue, c’est : « au final, ça a marché ». Pour l’exploitation au début, c’était largement suffisant, et les problèmes d’échelle ont pu être traités plus tard

    • Mais certains projets ne parviennent plus à sortir de git à cause de limites architecturales
    • Si on commence avec un store basé sur le système de fichiers comme git, il devient presque impossible de changer de protocole plus tard. Il faut penser API-first dès le départ
    • Au contraire, il y a peut-être encore moyen de mieux exploiter git. Dire simplement qu’il faut abandonner git sans proposer d’alternative, c’est une conclusion incomplète
    • Il y a aussi cette plaisanterie ironique : « ce n’est pas monté en charge de 0 à mille milliards d’utilisateurs, donc c’est nul »
  • Il y a ici un biais du survivant (survivorship bias). Si l’index git de Cargo a grossi au point de devenir un problème, c’est justement parce que Cargo a réussi.
    La plupart des petits projets utilisent très bien git comme protocole de distribution de données.
    Quand l’avenir en termes d’échelle est incertain au début, il est raisonnable d’utiliser git et GitHub pour se concentrer sur le problème essentiel

    • Il faut se méfier d’une optimisation prématurée. Cargo comme Homebrew ont grandi en choisissant la voie simple, et les problèmes de montée en charge n’ont été que de « bons problèmes » à résoudre plus tard
  • Chaque fois que je vois sur la page d’accueil de HN un article du type « ce que vous faites en ce moment est faux », ça me rend humble.
    Ça m’est arrivé plusieurs fois aussi. Cette fois, c’était un article sur PG Notify.
    Mais aujourd’hui, je développe seul, et je ne sais même pas si mon projet réussira, donc distribuer des plugins via git reste l’option la plus réaliste.
    Cela dit, si un problème de montée en charge apparaît plus tard, je reviendrai à cet article

    • On peut quand même éviter dès maintenant quelques pièges. Une dépendance à GitHub et le vendor lock-in peuvent être des problèmes encore plus graves
  • Personnellement, j’héberge mon code sur Forgejo. Il est protégé par mTLS sans exposition externe.
    Mais les modules Go demandent un certificat, donc ils ne reconnaissent pas mon instance Forgejo.
    Même avec SSH, il faut apparemment un accès HTTPS, donc j’ai fini par utiliser une copie locale via une directive replace. C’est assez pénible

    • Si on ajoute .git à la fin du chemin du module et qu’on configure $GOPRIVATE, on peut utiliser l’authentification des commandes git sans requête HTTPS. Voir la documentation officielle
    • On peut aussi télécharger via HTTPS si on ajoute le certificat TLS (CA) de l’instance au magasin de confiance
    • Dire qu’« un accès HTTP est nécessaire » n’est pas exact. Un proxy local suffit
    • Avec le DNS et les certificats Tailscale, on peut obtenir des certificats Let’s Encrypt sans exposition externe
  • Beaucoup de petits projets, pas seulement les gestionnaires de paquets, crowdsourcent leurs données dans des dépôts git.
    La plupart restent à petite échelle et ne rencontrent donc pas les limites techniques.
    En revanche, cette structure augmente la barrière à l’entrée pour les non-développeurs. Pour un gestionnaire de paquets, cela peut passer, mais pour des projets plus généralistes, c’est un vrai problème
    Pour aider sur ce genre de sujet, j’ai créé une bibliothèque open source appelée Datatig.
    Le support de présentation associé est disponible ici. À l’avenir, je compte m’appuyer sur cet article pour y ajouter aussi du contenu sur la montée en charge

 
lamanus 2025-12-28

On utilise git parce que c’est plus simple plutôt que de créer un système séparé pour recevoir les contributions des contributeurs. On parle de limites, mais ça ne me convainc pas vraiment, et je ne vois absolument aucune alternative aux problèmes concrets.