Benchmark
La capacité, en chiffres concrets
Mesurée, pas projetée : 10 000 capteurs, chacun émettant une fois par
minute, sur un seul serveur. Le banc d’essai est livré avec le produit : chaque
chiffre ci-dessous peut être reproduit sur votre propre matériel.
La machine derrière chaque chiffre de cette page : un Intel Core i9-14900KF
(24 cœurs), 64 Go de RAM et des SSD NVMe sous Windows 11, PostgreSQL
dans Docker — la base de données, les services backend et le client de
benchmark, tous sur ce seul serveur. Pas de cluster, pas d’hôte de base de
données séparé, rien de réglé au-delà de la configuration standard des conteneurs.
Recevoir
Avant d’être écrite, une mesure doit arriver. Mesuré sur le même serveur avec le
benchmark d’ingestion en direct livré avec le produit : 10 000 capteurs
rapportant dix fois par seconde — 12 millions de mesures par passage —
à travers les vrais services MQTT, Kafka et HTTP, jusque dans le tampon partagé puis
dans le stockage, chaque passage vérifié mesure par mesure contre ce qui a été envoyé.
Chaque transport accepte les mesures par lots (un tableau JSON de mesures par message,
ou la route ingest-batch en HTTP), et c’est cette forme qui décide du
chiffre : une flotte de 10 000 capteurs à 10 Hz représente 100 000
mesures par seconde, et une seule instance d’ingestion les absorbe avec de la marge.
| Passerelles envoyant des lots |
~430 000 mesures/s |
Une instance d’ingestion, un nœud de tampon. Une passerelle qui vide chaque seconde les échantillons de ses capteurs dans un message — 12 millions de mesures reçues en moins de 30 secondes, aucune perdue |
| Plusieurs capteurs par message, une mesure chacun |
~120 000 mesures/s |
La forme naturelle d’une passerelle qui interroge ses capteurs — toujours une instance, un nœud de tampon |
| Une mesure par message |
~80 000 mesures/s |
Des appareils qui publient au fil de l’échantillonnage, via Kafka — le plafond d’un seul nœud de tampon ; le tampon est conçu pour se répartir sur plusieurs |
| Mesures perdues sur l’ensemble des passages |
0 |
Comptes, sommes et minutes échantillonnées identiques au générateur, à la mesure près — dans le tampon, puis dans la base |
Écrire
| Mesures par mois |
432 000 000 |
10 000 capteurs × une mesure par minute, densité pleine |
| Débit d’écriture soutenu |
~134 000 mesures/s |
Le chemin de stockage de production, stable pendant des heures — aucune dégradation à mesure que l’historique s’accumule |
| Stockage de long terme par mois |
≈5,3 Gio |
Historique en pleine résolution, compressé à la clôture du mois |
| Un an d’historique |
≈64 Gio |
La croissance est linéaire — dimensionner un an à l’avance est une multiplication |
| Zone de travail, mois courant |
≈12 Gio |
Les journées terminées sont compactées en arrière-plan — la zone de travail reste profonde de quelques jours au lieu de croître tout le mois |
Relire
L’autre moitié de l’histoire : la vitesse à laquelle les mesures ressortent. Même
parc, même serveur unique, mesuré contre la véritable API de requête du produit, chaque
réponse intégralement téléchargée — 3,4 millions de requêtes, pas une seule erreur.
| Valeurs en direct à l’écran |
~57 000 requêtes/s |
Chaque requête récupère les dernières valeurs de dix capteurs — plus d’un demi-million de valeurs en direct par seconde, réponse typique en 8 ms |
| Un capteur, une journée, en graphique |
~1 390 graphiques/s |
Une journée d’historique à la minute répond en ~47 ms — même pour le mois encore en cours d’écriture |
| Un mois sur cinq capteurs |
~350 graphiques/s |
Un point par capteur et par jour, précalculé au compactage de chaque journée — le mois en cours répond en ~46 ms |
| Un mois résumé par capteur |
~4 200 résumés/s |
Minimum, maximum, moyenne et nombre sur un mois clos, réponse typique en ~15 ms |
| Erreurs sur l’ensemble du banc |
0 |
3 406 032 requêtes avec jusqu’à 512 clients en parallèle — chaque réponse complète |
Tenir la distance
La vitesse pendant une minute est une chose ; la question d’un sceptique est de savoir combien de temps cela tient et si quelque chose se perd en route. Le même serveur a donc tourné trois heures d’affilée : 10 000 capteurs rapportant dix fois par seconde, plus 2 000 autres en MQTT et HTTP — environ 102 000 mesures par seconde, en continu — pendant qu’une console bien occupée l’interrogeait sans arrêt. Ensuite, chaque capteur a été relu minute par minute et comparé à ce qui avait été envoyé.
| Mesures envoyées en trois heures |
1 101 600 000 |
Aucune n’a échoué à l’envoi ; les producteurs n’ont jamais pris de retard |
| Mesures relues, exactes |
1 101 600 000 |
Chacun des 12 000 capteurs, chaque minute, nombre et somme identiques à l’envoi |
| Requêtes de la console pendant ce temps |
1 241 199 · 0 erreur |
Valeurs en direct, graphiques et questions d’Analyses, ~115 par seconde ; réponse typique 3 ms pour les valeurs en direct, 13 ms pour un graphique — identiques à la dernière heure et à la première |
| Mémoire après trois heures |
la même qu’après cinq minutes |
Rien n’a grossi dans aucun des trois services |
Pendant ces trois heures, la journée en cours d’écriture a été compactée dix fois dans sa forme de long terme, sous le flux en direct, sans qu’une seule mesure ne se perde.
Face à face : TimescaleDB — même machine, mêmes données, mêmes questions
Un second benchmark, exécuté pour cette page : 2 000 capteurs × 30 jours
d’agrégats à la minute — 86,4 millions de lignes aux valeurs identiques — ingérées
dans le moteur de LandauOne et dans TimescaleDB (dernière version, PostgreSQL 17,
compression activée, segmentation par capteur), chacun par son propre chemin de
production : l’upsert dédupliquant de LandauOne contre le COPY binaire de
TimescaleDB. Même machine que ci-dessus, les deux bases dans Docker en configuration
standard, le client en local sur le même hôte, HTTP exclu des deux côtés. Avant toute
mesure, les deux systèmes ont reçu les mêmes questions et devaient rendre des
réponses identiques — ce fut le cas, au chiffre près. Le harnais est
livré dans le dépôt (CompareBench) : chaque ligne ci-dessous est
reproductible.
| Ingestion, 86,4 M de lignes |
127 000 lignes/s |
TimescaleDB : 1 290 000 lignes/s — TimescaleDB 915 % plus rapide (10×). Un COPY brut contre un upsert qui déduplique à l’arrivée. |
| Sceller le mois (compactage vs compression) |
2 min 57 s |
TimescaleDB : 41 s — TimescaleDB 331 % plus rapide. Le scellement de LandauOne précalcule aussi chaque résumé et percentile ci-dessous. |
| Stockage, mois scellé |
1,11 Gio |
TimescaleDB : 1,43 Gio — LandauOne 22 % plus compact, résumés compris. |
| Moyenne sur le mois entier, un capteur |
0,8 ms |
TimescaleDB : 2,9 ms — LandauOne 276 % plus rapide |
| Buckets horaires sur un mois (720 points), un capteur |
21,2 ms |
TimescaleDB : 5,0 ms — TimescaleDB 325 % plus rapide. LandauOne paie un coût fixe pour ouvrir le cube du mois entier ; Timescale ne parcourt que le segment d’un capteur. |
| Buckets journaliers sur un mois (30 points), un capteur |
21,0 ms |
TimescaleDB : 4,1 ms — TimescaleDB 418 % plus rapide, pour la même raison que ci-dessus. |
| P95 du mois entier (pondéré par le nombre de mesures), un capteur |
0,8 ms |
TimescaleDB : 30,0 ms — LandauOne 3 706 % plus rapide (37×). Précalculé au scellement contre un classement à la lecture. |
| P95 par jour sur un mois (30 points), un capteur |
35,0 ms |
TimescaleDB : 49,1 ms — LandauOne 40 % plus rapide |
| Moyenne sur le mois entier, 100 capteurs |
64,8 ms |
TimescaleDB : 65,5 ms — égalité (100 lectures de résumés séquentielles contre un seul parcours groupé) |
| P95 du mois entier, 100 capteurs |
53,1 ms |
TimescaleDB : 5,53 s — LandauOne 10 330 % plus rapide (104×). L’écart qui grandit avec le parc. |
Ce que les chiffres signifient — et ce qu’ils coûtent
Là où LandauOne est devant
Les statistiques historiques sont précalculées au fil du compactage de chaque
journée et de chaque mois : la moyenne, la médiane ou le P95 d’un mois est une
lecture de ligne au lieu d’un parcours — 276 % plus rapide pour une moyenne,
37× pour un P95 isolé, 104× pour les P95 de cent capteurs, et l’écart se creuse avec
l’historique, car une réponse résumée ne devient pas plus coûteuse à mesure que les
données derrière elle grandissent. Le même mois occupe 22 % de disque en moins,
résumés compris, et les percentiles, enveloppes de pics, taux de couverture et
deltas de compteurs arrivent comme des fonctions du produit — tracés, surveillés par
alertes, rapportés et envoyés par e-mail — pas comme du SQL que vous écrivez et
maintenez.
Là où TimescaleDB est devant
TimescaleDB est une base de données généraliste, et cette généralité est bien
réelle : n’importe quel SQL sur vos lignes brutes, des jointures avec vos
propres tables, des horodatages sous la minute et un vaste écosystème qui sait lui
parler. Son ingestion en masse est environ 10× plus rapide (un COPY brut contre
l’upsert dédupliquant de LandauOne), sa passe de compression est 4× plus véloce que
le scellement plus riche de LandauOne, et les graphiques en buckets d’un capteur
isolé sur un mois scellé reviennent 4–5× plus tôt. LandauOne renonce délibérément à
cette généralité : sa surface de requête est son API — les agrégations de cette
page, à la résolution minute et au-delà — et son jeu de statistiques est fixé à ce
que le scellement précalcule. Si vos questions sont du SQL ouvert, Timescale est le
bon outil ; si ce sont les questions qu’une équipe d’exploitation pose
réellement à ses capteurs, ce moteur y répond plus vite, avec moins de disque, et
avec la console incluse.