Test de charge d’Orbitra : 480 req/s, zéro erreur, p99 182 ms
Un tracker vit sous charge : chaque clic est une écriture, une vérification d’unicité et une redirection. C’est pourquoi, avant de taguer v1.6.3, nous avons reconstruit le pipeline d’unicité sur une base à l’échelle réelle et l’avons soumis à une charge k6 par paliers sur notre banc d’essai. Voici les chiffres.
Pourquoi ce test
v1.6.3 a rendu le filtre de doublons honnête face au NAT mobile : la clé d’unicité est devenue IP + user agent au lieu du seul IP. Derrière un même NAT d’opérateur, deux personnes distinctes entraient en collision — le second visiteur recevait un subid sans ligne de clic en base, et sa conversion n’avait rien pour s’y rattacher.
Le changement exigeait une nouvelle colonne ua_hash et un index composé sur une base qui portait déjà un volume réel. C’est le type de migration le plus risqué — alors avant le tag, nous avons rejoué exactement le chemin qu’emprunte une installation utilisateur, sur des données à l’échelle de production.
Le banc d’essai
- Conteneur cloud : 2 vCPU / 7 Go de RAM, Ubuntu 24.04. nginx 1.24 + PHP-FPM 8.3 dans la configuration d’origine laissée par
install.sh— aucun réglage manuel sur les runs de base. - SQLite en mode WAL. k6 tourne sur la même machine (~0,3 cœur de surcoût), les chiffres sont donc plutôt sous-estimés.
- Charge par paliers à taux d’arrivée constant : 60 s par palier, timeout de 5 s, redirections non suivies.
- Campagne : un flux régulier → redirection vers l’offre, fenêtre d’unicité de 24 h sur IP + User-Agent. Les uniques utilisent une IP publique aléatoire et un UA unique ; les récurrents, 50 paires IP/UA fixes.
- Trois bases : ~50 000 clics (sanité), 3,2 millions (principale) et un instantané d’avant mise à jour de 3,9 millions pour la répétition de migration (~1 million sur les dernières 24 h, ~8 500 clics par IP NAT).
- Runs en paires : v1.6.2 servait la même base à côté de la nouvelle version ; après un run tombé, on attendait que la file FPM se résorbe.
Résultats
| Run (base de 3,2 M sauf mention) | req/s | Erreurs | p99 | CPU |
|---|---|---|---|---|
| Uniques, FPM d’origine (base ~50 000) | 480 | 0 | 46 ms | 76% |
| Uniques | 480 | 0 | 75 ms | 77% |
| Visiteurs récurrents (50 paires NAT) | 480 | 0, ~1% via spool | 14 ms | 61% |
| Uniques + panneau ouvert, rapports rafraîchis toutes les 2 s | 320 | 0 | 587 ms | 81% |
| Uniques, FPM/nginx ajustés, géo activée | 560 | 0 | 187 ms | 94% |
| Uniques, surcharge délibérée | 800 | 27% de timeouts | — | 97% |
Et la répétition de migration sur l’instantané de 3,9 millions : le premier appel après la « mise à jour » a exécuté la migration 55 en 0,04 s, une passe cron a construit l’index en 4,8 s et rattrapé 1 008 085 hachages UA en 29,6 s — et le trafic NAT à 480 req/s est passé avec zéro erreur et un p99 de 182 ms, tous les subid en base. La version précédente perdait 27 775 subid dans le même scénario ; la nouvelle, zéro.
Deux détails à souligner. Même à 800 req/s — au-delà du point de rupture — chaque redirection servie est restée écrite en base : la surcharge dégrade la latence, pas la durabilité. Et la justesse des hachages a eu sa propre vérification : un échantillon de 2 000 lignes comparé au crc32 de PHP — zéro divergence.
L’économie : un clic coûte environ 2,5 ms de CPU, ce qui place le plafond d’une machine à 2 vCPU vers 550–600 req/s, limitée par le CPU. Sur 4 vCPU, la même arithmétique extrapole à ~1 000 req/s — chiffré sur le papier seulement, et étiqueté comme tel.
Ce que le test de charge a attrapé avant la sortie
La moitié de la valeur du run, ce sont les bugs qu’il a débusqués. Tous corrigés avant le tag :
- Des curseurs non fermés sur le chemin du clic provoquaient un SQLITE_BUSY_SNAPSHOT immédiat — les clics des visiteurs récurrents partaient au spool au lieu de la base.
- Le debounce était indexé sur le seul IP — les voisins de NAT perdaient des clics et recevaient un subid inexistant.
- Les filtres de dates des rapports utilisaient date(created_at, tz) et ignoraient l’index — les rapports ramassaient sur les grosses bases.
- Un INSERT du pixel comptait 23 colonnes pour 22 valeurs — les clics pixel disparaissaient en silence.
- Les lignes anciennes à hachage NULL gardaient l’effondrement NAT vivant une fenêtre d’unicité après la mise à jour.
Pourquoi ça tient
- SQLite en mode WAL, un seul fichier, zéro service en plus. Pas de ClickHouse, Redis ou MySQL qui dévorent la RAM — le goulot est l’I/O disque, et il évolue avec votre VPS.
- Une file d’écriture (spool) : si SQLite se verrouille un instant, le clic atterrit dans une file fichier qu’un cron par minute vide — la redirection du visiteur n’attend pas et le clic n’est jamais perdu.
- Vérifications d’unicité par index : chaque clic porte un hachage crc32 compact du UA, et les quatre vérifications par clic cherchent dans l’index (ip, ua_hash, created_at) au lieu de parcourir tous les clics d’un IP.
Réserves honnêtes
- Testé sur le release candidate de v1.6.3. L’architecture de stockage (SQLite, spool, index) n’a pas changé dans les versions actuelles.
- Notre banc n’est pas votre VPS : les chiffres absolus voyagent avec le matériel. Ce qui se transpose, ce sont les proportions et le mode de défaillance.
- Le chiffre à 4 vCPU est une extrapolation, pas une mesure ; nous le disons plutôt que d’arrondir vers le haut.
- Il s’agit d’un run de stress synthétique plus une répétition de migration à l’échelle réelle — pas un A/B sur trafic réel contre d’autres trackers.
Ce que cela signifie pour vous
Un VPS modeste — de la classe que la plupart des guides recommandent pour démarrer — a déjà de la marge pour des volumes quotidiens sérieux, et aucune facturation à l’événement ne vous attend au-dessus. Si vous êtes sur Keitaro parce que « SQLite ne survivra pas », voici le jeu de données à regarder.
Orbitra s’installe sur un serveur Ubuntu propre en une quinzaine de minutes — une commande, et la démo en direct est ouverte si vous voulez d’abord cliquer dans le panneau.
FAQ
Sur quel matériel le test a-t-il tourné ?
Sur un conteneur cloud de 2 vCPU et 7 Go de RAM sous Ubuntu 24.04, nginx et PHP-FPM dans la configuration d’origine laissée par install.sh, et k6 sur la même machine — les chiffres sont donc plutôt sous-estimés. Les valeurs absolues dépendent toujours de votre VPS : vous scalez le serveur, pas l’abonnement.
Ces résultats valent-ils pour la version actuelle ?
Le test a tourné sur le release candidate v1.6.3. L’architecture de stockage (SQLite + file d’écriture + index d’unicité) est la même dans les versions actuelles ; les changements depuis sont des fonctions et de l’interface.
Pourquoi SQLite et pas ClickHouse ?
Un seul fichier, mode WAL, pas de serveur de base de données séparé. À volumes bas et moyens, le goulot est l’I/O disque, pas la RAM — un VPS pas cher va déjà loin. Pour des millions de clics par jour soutenus, une architecture colonnaire est plus forte — nous le disons franchement.
La migration a-t-elle perdu des données ?
Dans le scénario des visiteurs récurrents, l’ancienne version perdait 27 775 subid ; la nouvelle, zéro. Les rapports sur 3,2 millions de clics ont correspondu à l’ancienne version ligne par ligne.
À lire aussi
Alternative à Voluum : tracker self-hosted gratuit
Voluum démarre à ~$149/mois. Orbitra est un tracker self-hosted gratuit avec cloaking intégré et 50+ intégrations CPA. Comparatif et guide de migration.
Lire l’article →Alternative à Keitaro : tracker self-hosted gratuit
Le concurrent self-hosted le plus proche — mais la licence démarre à 79 $/mois. Comparatif des fonctions et import des campagnes en un clic.
Lire l’article →