Questo articolo risponde a una domanda specifica: come valutare un'API backend in modo riproducibile, documentando il protocollo che applicheremo in Aurabase prima di pubblicare qualsiasi dato sulle prestazioni. Non risultati: un metodo. Qualsiasi misurazione già pubblicata altrove su questo sito (in particolare sulla nostra pagina Performance) che non si basa già su questo protocollo deve essere trattata come non verificata fino a nuovo avviso.
L'essenziale
Ad oggi non esistono risultati sulle prestazioni di Aurabase a seguito di un protocollo pubblicato e riproducibile: questo articolo documenta la metodologia che applicheremo per produrli, non i risultati già ottenuti. Il repository contiene già una suite di test a 3 livelli: micro-benchmark Criterion.rs su 3 crate, test di carico k6 su 8 scenari HTTP/WebSocket e uno script Python per il confronto diretto Postgres vs API con calcolo percentile. Il protocollo completo (durata della misurazione, percentili anziché medie, isolamento dell'ambiente, divulgazione di versione e data) si basa su fonti esterne verificate: PostgreSQL, Criterion.rs, k6 (Grafana), HdrHistogram, PlanetScale e Convex. Qualsiasi affermazione sulle prestazioni già pubblicata altrove su questo sito senza essere ricondotta a questo protocollo deve essere considerata non verificata.
Perché non pubblichiamo cifre nude
Convex, editore di un backend reattivo concorrente, ha preso pubblicamente le distanze da quella che il suo team tecnico chiama la "guerra dei grafici a barre" tra i fornitori di database. La sua formula è diretta: "È ridimensionamento del teatro, non ridimensionamento" - ridimensionamento del teatro, non reale ridimensionamento (stack.convex.dev/on-competitive-benchmarks, blog tecnico Stack, accesso il 23 agosto 2026).
Il suo argomento centrale: un benchmark che confronta due sistemi con diverse garanzie di coerenza, topologia o modello di prezzo spesso non testa la stessa cosa, anche quando afferma di farlo: “il benchmark in realtà non sta testando la stessa cosa”. Questa reflex ha un nome nel settore: benchmarketing, pubblicando una figura scelta per il suo effetto di marketing più che per il suo rigore metodologico.
La nostra risposta non è quella di rifiutarci di misurare: rifiutare di pubblicare un dato a tempo indeterminato sarebbe altrettanto disonesto quanto pubblicarne uno non comprovato. Si tratta di documentare innanzitutto come misureremmo, con quali strumenti e in quali condizioni, prima di affermare di aver misurato qualcosa. Questo è anche ciò che distingue un confronto utile (come il nostro Confronto Aurabase vs Appwrite, che documenta differenze architetturali verificabili) da un confronto di dati prestazionali senza un protocollo comune.
Ciò è particolarmente importante per un lead tecnico o un CTO che deve difendere una scelta di backend in un comitato tecnico: una figura non riconducibile a un metodo non sopravvive alla prima, un po' insistente, domanda. Un protocollo documentato è autodifesa: puoi mostrare lo script, la versione testata ed eseguire nuovamente il test davanti a qualcuno, se necessario.
Ciò che rende fuorviante la maggior parte dei benchmark di backend
Due trappole emergono sistematicamente: confrontare diverse topologie senza segnalarle e misurare la latenza in un modo che nasconda esattamente le pause che contano di più per l'utente.
Sul primo punto, PlanetScale documenta esplicitamente il suo vincolo di parità hardware: ogni ambiente confrontato deve funzionare con risorse di calcolo (vCPU, RAM) uguali o superiori all'istanza di riferimento, nella stessa regione cloud (planetscale.com/benchmarks, metodologia “Telescope”, accesso il 23 agosto 2026). Senza questa disciplina, un divario di latenza potrebbe semplicemente riflettere una macchina più grande, non un’architettura più veloce.
Lo stesso principio si applica allo stato della cache e alla topologia della rete. Un'istanza appena avviata (cache Postgres fredda, pool di connessioni vuoto, piano di query non ancora memorizzato nella cache) risponde strutturalmente più lentamente di un'istanza in esecuzione per un'ora con carico stabile. Una query dalla stessa regione del database risponde strutturalmente più velocemente di una query tra regioni. Due benchmark che non specificano nessuno dei due semplicemente non sono comparabili, anche se mostrano unità identiche.
Sul secondo punto, la trappola si chiama omissione coordinata. HdrHistogram, il progetto di riferimento sulla misurazione della latenza creato da Gil Tene, lo spiega in questo modo: quando un generatore di carico attende la risposta di una richiesta prima di inviare quella successiva (anello chiuso), una pausa del servizio elimina automaticamente il numero di richieste inviate durante la pausa — e quindi il numero di misurazioni ad alta latenza registrate (github.com/HdrHistogram/HdrHistogram, accesso il 23 agosto 2026). Il progetto fornisce un esempio concreto e quantificato: su un ipotetico sistema che campiona la sua latenza ogni 10 ms per 200 secondi, una singola pausa di 100 secondi nel mezzo del test è sufficiente per produrre, senza correzione, un istogramma in cui circa il 99,99% delle risposte sembra rientrare sotto 1 ms - anche se metà del tempo reale è trascorso in questa singola pausa.
Un test di carico a circuito chiuso che invia una richiesta solo dopo aver ricevuto la risposta precedente sottorappresenta sistematicamente lunghe pause. Il p99 visualizzato potrebbe essere migliore della realtà vissuta da un utente reale, non perché il sistema sia veloce, ma perché il protocollo di misurazione si è "dimenticato" di inviare le query mentre era in pausa.
Perché la media mente: p50, p95, p99
Una latenza media può sembrare eccellente quando una richiesta su venti impiega cinque volte il tempo. Questo è esattamente ciò che i percentili rivelano e ciò che la media strutturalmente nasconde.
Meccanicamente non c'è nulla di misterioso in un percentile: ordina tutte le latenze misurate in ordine crescente, quindi prendi il valore nella posizione corrispondente. Su 1000 query ordinate, p50 è il 500esimo valore, p95 il 950esimo, p99 il 990esimo. È sufficiente una sola richiesta anormalmente lenta su 1000 per far muovere il p99: è proprio la sua sensibilità a casi rari che lo rende utile, dove questa stessa richiesta isolata non ha quasi alcun effetto sulla media.
Segno rivelatore: il rapporto testuale che pgbench, lo strumento di benchmark ufficiale di PostgreSQL, visualizza per impostazione predefinita fornisce una media e una deviazione standard , non percentili (postgresql.org/docs/current/pgbench.html, accesso il 23 agosto 2026). La sua documentazione ufficiale avverte inoltre: “Non credere mai a nessun test che dura solo pochi secondi” – non credere mai a un test che dura solo pochi secondi, il che si applica tanto alla durata quanto alla metrica scelta.
k6, lo strumento di caricamento che utilizziamo per il livello 2 della nostra suite, risolve questo problema con soglie espresse in percentile: la sintassi p(95)<500 definisce un criterio pass/fail — il 95% delle richieste deve rispondere entro 500 ms — direttamente nella configurazione di test (grafana.com/docs/k6, consultato il 23 agosto 2026).
| p50 (mediana) | La metà delle query sono più veloci di questo valore | Nasconde completamente la coda di distribuzione |
|---|---|---|
| p95 | 1 query su 20 è più lenta | Area dove compaiono i primi utenti insoddisfatti |
| p99 | 1 query su 100 è più lenta | Più sensibile all'omissione coordinata se il protocollo è mal progettato |
I 3 livelli di benchmark già presenti nel nostro repository
Pubblicare una metodologia senza strumenti reali sarebbe solo un’altra forma di teatro. La cartella benchmarks/ nel repository Aurabase contiene già una suite a 3 livelli, ispirata nella sua struttura alla metodologia pubblica Supabase: gli strumenti esistono, i risultati misurati e datati non esistono ancora.
Livello 1 — Criterio dei micro-benchmark.rs
Tre crate dell'area di lavoro Cargo hanno benchmark dedicati legati alla CPU: aura-crypto (hash Argon2, JWT HS256 — generazione, convalida e firma per PostgREST, crittografia AES-GCM), aura-db-adapters (filtri di analisi e select in formato PostgREST — eq., gte., in.(), incorporamenti di relazioni) e aura-core (serializzazione JSON, risoluzione schema_name, convalida UUID).
aura-db-adapters misura specificamente il costo dell'analisi delle query in formato PostgREST: quattro casi per i filtri (simple_4, complex_10, or_group, in_large_50 con 50 valori) e quattro per select (colonne singole, *, un incorporamento di relazione, cinque incorporamenti). Questo è il tipo di costo invisibile in un test di carico globale: una regressione sull'analisi di un filtro complesso or.(...) non cambierebbe quasi nulla nel p95 di un endpoint poco utilizzato, ma diventerebbe misurabile su un endpoint con traffico elevato - da qui l'interesse a isolarlo in un micro-benchmark piuttosto che fare affidamento esclusivamente sul livello 2.
aura-core adotta un approccio diverso: invece di misurare il tempo grezzo, misura il throughput (Throughput::Bytes) sulla serializzazione e deserializzazione JSON dei messaggi interni NatsRequest/NatsResponse scambiati tra il gateway e i servizi — con tre dimensioni realistiche del payload (una richiesta minima, una richiesta con un corpo JSON nidificato, un risposta all'elenco).
Criterion.rs non si limita a cronometrare un ciclo. Innanzitutto esegue una fase di riscaldamento per riempire le cache della CPU/sistema operativo, rileva i valori anomali con una versione modificata del metodo di Tukey (senza escluderli dal set di dati), calcola gli intervalli di confidenza eseguendo il bootstrap su un numero elevato di campioni ricampionati e rileva le regressioni delle prestazioni tra due esecuzioni mediante il test statistico di Student, con una soglia di rumore configurabile, in genere ±1%, per ignorare le variazioni che non sono statisticamente significative (bheisler.github.io/criterion.rs/book/analysis.html, accesso il 23 agosto 2026).
Ogni esecuzione di Criterion genera un report HTML dettagliato in target/criterion/: distribuzioni, grafici di regressione, confronto con l'esecuzione precedente. È questa relazione, non solo un filo terminale, che una metodologia seria deve consentire di rigenerare.
Livello 2: test di carico k6
Otto script k6 coprono il gateway sul lato del piano dati: health (base di latenza), auth-flow (registrazione → login → aggiornamento → logout), crud-read e crud-write, storage (caricamento/download), realtime-ws, breakpoint (aumento del carico fino al guasto) e supabase-compare. Sette sono collegati a un target Makefile dedicato: supabase-compare.js esiste nel repository ma non ha ancora un target, uno stato di cose che questo articolo documenta così com'è anziché mascherarlo.
La configurazione condivisa definisce le soglie per tipo di operazione. Questi sono i criteri di superamento/fallimento che il test verifica ogni volta che viene eseguito, non i risultati già misurati:
| Lettura (OTTIENI) | p95 < 500 ms · p99 < 1000 ms | Configurazione k6 (benchmarks/k6/lib/config.js) |
|---|---|---|
| Scrittura (POST/PATCH) | p95 < 300 ms · p99 < 1000 ms | Configurazione k6 |
| Autenticazione (accesso/aggiornamento) | p95 < 300 ms · p99 < 1000 ms | Configurazione k6 |
| Archiviazione (caricamento/download) | p95 < 500 ms · p99 < 2000 ms | Configurazione k6 |
| Tasso di errore, tutti gli scenari | < 1 % | Configurazione k6 |
README.md nella cartella benchmarks/ documenta una soglia di lettura di p95 su < 200ms ("Supabase SLO"), mentre la soglia effettivamente applicata in benchmarks/k6/lib/config.js — quella in cui viene eseguito il test — è p(95)<500. I due file derivano l'uno dall'altro. Questo è un esempio concreto, trovato leggendo il codice sorgente di questo articolo, del perché un protocollo dovrebbe avere un'unica fonte di verità con versione anziché essere documentato in due posti: senza di essa, anche un team che cerca di essere rigoroso finisce per pubblicare soglie contrastanti.
Livello 3: confronto diretto tra PostgreSQL e API
Uno script Python (direct_vs_api.py) misura l'overhead effettivo del gateway + livello di servizio confrontando le richieste dirette psycopg2 con le chiamate HTTP sulla stessa operazione: elenco, lettura una tantum per ID, lettura filtrata e ordinata. Ogni misurazione segue un riscaldamento di 10 iterazioni prima del ciclo temporizzato, quindi calcola la media, p50, p95, p99 e un throughput in operazioni al secondo.
Un secondo script (aurabase_vs_supabase.py) applica la stessa logica di riscaldamento e calcolo percentile a un confronto testa a testa con un'istanza locale di Supabase (CLI di Supabase, localhost:54321 per impostazione predefinita): stessa macchina, stessa rete locale per entrambi, esattamente la disciplina di parità dell'ambiente che PlanetScale documenta per i propri confronti.
Uno script di orchestrazione (collect_baseline.sh, target bench-baseline di Makefile) collega i tre livelli — Criterion sulle 3 casse, un sottoinsieme degli scenari k6 (health e crud-read oggi, non tutti e 8 ancora), quindi il confronto Python — e scrive log, JSON e report HTML Criterion in una cartella con timestamp univoco: benchmarks/results/AAAAMMJJ_HHMMSS/. Questo è esattamente il riflesso di una divulgazione datata, in un unico ciclo riproducibile, che la sezione seguente formalizza in un protocollo completo.
Il protocollo che applicheremo prima di pubblicare un dato
Otto impegni, ciascuno ancorato a una pratica già documentata da uno strumento o progetto riconosciuto di terze parti, non inventato per l’occasione.
- Preriscaldamento separato dalla misurazione. Criterion.rs riempie le cache della CPU/sistema operativo prima del cronometraggio;
pgbenchconsiglia esplicitamente di non credere mai ad una corsa di pochi secondi. - Durata fissa, non un numero fisso di iterazioni. Un carico ha bisogno di tempo per convergere: questo è il ruolo di
stagesk6 e il flag-Tdipgbench. - Percentili, mai solo la media — e vigilanza attiva sull'omissione coordinata se il generatore di carico opera in un circuito chiuso.
- Ambiente documentato in dettaglio: commit git del servizio testato, versione di PostgreSQL, specifiche hardware, versione dello strumento di caricamento. PlanetScale documenta i suoi esatti parametri TPCC (
TABLES=20,SCALE=250, ~500 GB) proprio per questo motivo: senza questi dettagli nessuno può riprodurre una corsa. - Risultati con timestamp e versione, mai un singolo numero inciso su una pagina di marketing senza una data. L'attrezzatura attuale è già scritta in un file datato; sarà necessario estendere questo riflesso a qualsiasi misurazione pubblicata pubblicamente, con la regione ospitante documentata come qualsiasi altra variabile ambientale (vedi la nostra guida sulla Sovranità ospitante dell'UE, rilevante non appena una cifra dipende da una determinata regione).
- Script e dati grezzi pubblicati insieme al risultato aggregato, non solo alla media finale. PlanetScale invita addirittura i lettori a segnalare un errore metodologico in un indirizzo dedicato – una postura che troviamo sana e che vogliamo riprendere.
- Throughput pubblicizzato insieme alla latenza, non solo l'uno o l'altro. Un sistema può avere un'eccellente latenza a basso carico e crollare nel throughput all'aumentare della concorrenza: questo è esattamente ciò che lo scenario
breakpointdella nostra suite k6 (scale-to-crash) è progettato per rivelare e ciò che la misurazione del microbenchmarkThroughput::Bytesdi Criterion cattura a livello di funzione. - Gap significativo prima di annunciare un miglioramento. Una variazione di qualche percentuale tra due esecuzioni potrebbe essere un rumore di misurazione piuttosto che un guadagno reale: Criterion.rs calcola la probabilità che la differenza osservata sia dovuta al caso prima di qualificarla come regressione o miglioramento. Un dato isolato, senza questa verifica, è solo un aneddoto statistico.
Cosa non faremo
Questo elenco conta tanto quanto il protocollo positivo di cui sopra.
- Confronto di diverse topologie (istanza self-hosted e gestita, fredda e preriscaldata) senza segnalarlo esplicitamente.
- Conserva la migliore sequenza su dieci senza menzionare le altre nove.
- Pubblica una figura senza data, senza versione di servizio, senza script di riproduzione.
- Ripubblicare una figura di marketing esistente purché non sia riconducibile a questo protocollo.
- Confrontarci con un concorrente su una cifra grezza della prestazione se quel concorrente non pubblica la propria metodologia in modo equivalente: una cifra contro il silenzio non è un confronto, è uno slogan.
Una cifra come “avvio a freddo inferiore a 1 ms” è stata diffusa senza essere supportata da un benchmark riproducibile. Ora viene trattato internamente come non supportato e non deve essere letto come una caratteristica misurata del prodotto fino a quando qualsiasi misurazione datata, con metodologia pubblicata, non lo conferma. Questo è esattamente il tipo di affermazione che questo protocollo esiste per evitare che si ripeta.
Il protocollo minimo per il benchmarking di qualsiasi backend
Questo protocollo non dipende da alcuno strumento Aurabase specifico: puoi applicarlo alla tua API oggi stesso.
- Imposta il caricamento prima di lo strumento: sola lettura, scrittura, mix realistico per la tua applicazione, non un rapporto generico copiato da un altro progetto.
- Separare esplicitamente la fase di preriscaldamento dalla fase di misurazione.
- Esegui il test per un tempo sufficiente: minuti, non secondi.
- Misura in percentili (p50/p95/p99), mai solo in media.
- Verificare che il generatore di carico non sia in circuito chiuso o correggere l'omissione di coordinamento nell'analisi.
- Isola l'ambiente sottoposto a test: nessun vicino rumoroso, nessuna attività in background concorrente.
- Pubblica la versione testata, la data, le specifiche hardware e lo script, non solo il risultato finale.
Su una semplice base Postgres, questo protocollo accetta un comando pgbench — 20 client simultanei distribuiti su 4 thread, per 5 minuti, con un rapporto sullo stato di avanzamento ogni 10 secondi:
Strumenti di riferimento, per livello
Cinque strumenti, ciascuno adatto a un diverso livello dello stack: nessuno sostituisce gli altri.
| Microfono (funzione) | Criterio.rs | CPU pura, statistiche di bootstrap |
|---|---|---|
| Interrogazione SQL | pgbench | Transazione tipo TPC-B, tps e latenza |
| Carico HTTP/WS | k6 (Grafana) | Percentili, soglie di superamento/fallimento |
| OLTP su larga scala | sysbench + TPCC (metodologia del telescopio) | QPS, costo per prestazione |
| Correzione della misura | Istogramma Hdr | Compensa l'omissione coordinata |