Ten artykuł odpowiada na konkretne pytanie — jak przetestować interfejs API zaplecza w powtarzalny sposób — poprzez udokumentowanie protokołu, który będziemy stosować w Aurabase przed opublikowaniem jakichkolwiek danych dotyczących wydajności. Nie wyniki: metoda. Wszelkie pomiary opublikowane już w innym miejscu tej witryny (w szczególności na naszej stronie Wydajność), które nie opierają się już na tym protokole, należy traktować jako niezweryfikowane do odwołania.
Najważniejsze
Jak dotąd nie istnieją żadne wyniki działania Aurabase oparte na opublikowanym, powtarzalnym protokole — ten artykuł dokumentuje metodologię, którą zastosujemy przy ich tworzeniu, a nie wyniki już uzyskane. Repozytorium zawiera już 3-poziomowy zestaw testów : mikrotesty porównawcze Criterion.rs w 3 skrzynkach, testy obciążenia k6 w 8 scenariuszach HTTP/WebSocket oraz skrypt Pythona do bezpośredniego porównania Postgres z API z obliczeniem percentyli. Kompletny protokół – czas trwania pomiaru, percentyle zamiast średnich, izolacja środowiska, ujawnienie wersji i daty – opiera się na zweryfikowanych źródłach zewnętrznych: PostgreSQL, Criterion.rs, k6 (Grafana), HdrHistogram, PlanetScale i Convex. Wszelkie twierdzenia dotyczące wydajności opublikowane już w innym miejscu tej witryny i niepowiązane z niniejszym protokołem należy uznać za niezweryfikowane.
Dlaczego nie publikujemy samych danych liczbowych
Convex, wydawca konkurencyjnego, responsywnego backendu, publicznie zdystansował się od tego, co jego zespół techniczny nazywa „wojną na wykresy słupkowe” pomiędzy dostawcami baz danych. Jego formuła jest prosta: „To teatr skalowania, a nie skalowanie” – teatr skalowania, a nie prawdziwe skalowanie (stack.convex.dev/on-competitive-benchmarks, Blog techniczny Stack, dostęp 23 sierpnia 2026).
Jego główny argument: benchmark, który porównuje dwa systemy z różnymi gwarancjami spójności, topologii lub modelu cenowego, często nie testuje tego samego, nawet jeśli tak twierdzi – „benchmark nie testuje w rzeczywistości tego samego”. Ten odruch ma swoją nazwę w branży: benchmarking, publikujący dane liczbowe wybrane ze względu na efekt marketingowy, a nie rygor metodologiczny.
Naszą odpowiedzią nie jest odmowa dokonania pomiaru — odmowa opublikowania danych liczbowych w nieskończoność byłaby równie nieuczciwa, jak opublikowanie danych bezpodstawnych. Chodzi o to, aby najpierw udokumentować, w jaki sposób byśmy mierzyli, za pomocą jakich narzędzi i w jakich warunkach, zanim będziemy twierdzić, że cokolwiek zmierzyliśmy. To także odróżnia przydatne porównanie (takie jak nasze porównanie Aurabase vs Appwrite, które dokumentuje sprawdzalne różnice w architekturze) od porównania wydajności bez wspólnego protokołu.
Jest to szczególnie ważne w przypadku kierownika technicznego lub dyrektora technologicznego, który musi bronić wyboru zaplecza w komisji technicznej: liczba, której nie można powiązać z metodą, nie przetrwa pierwszego, nieco natarczywego pytania. Udokumentowany protokół broni się sam — możesz pokazać skrypt, przetestowaną wersję i, jeśli zajdzie taka potrzeba, ponownie przeprowadzić test w obecności innej osoby.
Co sprawia, że większość testów porównawczych backendu wprowadza w błąd
Systematycznie pojawiają się dwie pułapki: porównywanie różnych topologii bez zgłaszania tego i mierzenie opóźnień w sposób, który dokładnie ukrywa pauzy, które są dla użytkownika najważniejsze.
W pierwszym punkcie PlanetScale wyraźnie dokumentuje swoje sprzętowe ograniczenie parzystości: każde porównywane środowisko musi działać na zasobach obliczeniowych (vCPU, RAM) równych lub większych niż instancja referencyjna, w tym samym regionie chmury (planetscale.com/benchmarks, metodologia „Telescope”, dostęp 23 sierpnia 2026 r.). Bez tej dyscypliny luka w opóźnieniu może po prostu odzwierciedlać większą maszynę, a nie szybszą architekturę.
Ta sama zasada dotyczy stanu pamięci podręcznej i topologii sieci. Instancja, która właśnie została uruchomiona (zimna pamięć podręczna Postgres, pusta pula połączeń, plan zapytań jeszcze nie buforowany) odpowiada strukturalnie wolniej niż instancja działająca przez godzinę przy stabilnym obciążeniu. Zapytanie z tego samego regionu co baza danych odpowiada strukturalnie szybciej niż zapytanie między regionami. Dwa testy porównawcze, które nie określają żadnego z nich, po prostu nie są porównywalne, nawet jeśli wyświetlają identyczne jednostki.
W drugim punkcie pułapka nazywa się skoordynowanym pominięciem. HdrHistogram, projekt referencyjny dotyczący pomiaru opóźnień stworzony przez Gila Tene, wyjaśnia to w ten sposób: kiedy generator obciążenia czeka na odpowiedź na żądanie przed wysłaniem kolejnego (zamknięta pętla), pauza usługi automatycznie zmniejsza liczbę żądań wysłanych podczas pauzy — a tym samym liczbę zarejestrowanych pomiarów o dużym opóźnieniu (github.com/HdrHistogram/HdrHistogram, dostęp w sierpniu 23.2026). W projekcie przedstawiono konkretny i wymierny przykład: w hipotetycznym systemie, który próbkuje opóźnienie co 10 ms przez 200 sekund, pojedyncza przerwa trwająca 100 sekund w środku testu wystarczy, aby bez korekty uzyskać histogram, na którym około 99,99% odpowiedzi wydaje się mieścić w czasie krótszym niż 1 ms – mimo że w tej pojedynczej pauzie upłynęła połowa czasu rzeczywistego.
Test obciążenia w pętli zamkniętej, który wysyła żądanie dopiero po otrzymaniu poprzedniej odpowiedzi, systematycznie nie reprezentuje długich przerw. Wyświetlany przez niego p99 może być lepszy od rzeczywistości doświadczanej przez prawdziwego użytkownika — nie dlatego, że system jest szybki, ale dlatego, że protokół pomiarowy „zapomniał” wysłać zapytania podczas pauzy.
Dlaczego średnia kłamie: p50, p95, p99
Średnie opóźnienie może wydawać się doskonałe, gdy jedno na dwadzieścia żądań trwa pięć razy dłużej. To właśnie ujawniają percentyle i to, co strukturalnie ukrywa średnia.
Mechanicznie nie ma nic tajemniczego w percentylu: posortuj wszystkie zmierzone opóźnienia w porządku rosnącym, a następnie weź wartość z odpowiedniej pozycji. Spośród 1000 posortowanych zapytań p50 to 500. wartość, p95 to 950., p99 to 990. Pojedyncze wyjątkowo powolne żądanie spośród 1000 wystarczy, aby p99 zaczął działać - właśnie jego wrażliwość na rzadkie przypadki czyni go użytecznym, gdy to samo izolowane żądanie nie ma prawie żadnego wpływu na średnią.
Znak ostrzegawczy: raport tekstowy, który pgbench — oficjalne narzędzie do testowania PostgreSQL — wyświetla domyślnie, podaje średnią i odchylenie standardowe , a nie percentyle (postgresql.org/docs/current/pgbench.html, dostęp 23 sierpnia 2026 r.). Oficjalna dokumentacja ostrzega również: „Nigdy nie wierz żadnemu testowi, który trwa tylko kilka sekund” – nigdy nie wierz testowi, który trwa tylko kilka sekund, co dotyczy zarówno czasu trwania, jak i wybranej metryki.
k6, narzędzie do ładowania, którego używamy na poziomie 2 naszego pakietu, rozwiązuje ten problem za pomocą progów wyrażonych w percentylach: składnia p(95)<500 definiuje kryterium pozytywnego/niepomyślnego — 95% żądań musi odpowiedzieć w ciągu 500 ms — bezpośrednio w konfiguracji testowej (grafana.com/docs/k6, konsultowano 23 sierpnia 2026 r.).
| p50 (mediana) | Połowa zapytań jest szybsza niż ta wartość | Całkowicie ukrywa ogon dystrybucji |
|---|---|---|
| p95 | 1 na 20 zapytań jest wolniejsze | Obszar, w którym pojawiają się pierwsi niezadowoleni użytkownicy |
| p99 | 1 na 100 zapytań jest wolniejsze | Najbardziej wrażliwy na skoordynowane pominięcie, jeśli protokół jest źle zaprojektowany |
3 poziomy benchmarku już obecne w naszym repozytorium
Publikowanie metodologii bez prawdziwych narzędzi byłoby po prostu kolejną formą teatru. Folder benchmarks/ w repozytorium Aurabase zawiera już 3-poziomowy pakiet, inspirowany swoją strukturą publiczną metodologią Supabase - narzędzia istnieją, zmierzonych i datowanych wyników jeszcze nie ma.
Poziom 1 – Mikrotesty porównawcze Criterion.rs
Trzy skrzynki obszaru roboczego Cargo mają dedykowane testy porównawcze związane z procesorem: aura-crypto (hasz Argon2, JWT HS256 — generowanie, sprawdzanie poprawności i podpis dla PostgREST, szyfrowanie AES-GCM), aura-db-adapters (filtry parsujące i select w formacie PostgREST — eq., gte., in.(), osadzanie relacji) i aura-core (serializacja JSON, rozdzielczość schema_name, sprawdzanie poprawności UUID).
aura-db-adapters specjalnie mierzy koszt analizowania zapytań w formacie PostgREST — cztery przypadki dla filtrów (simple_4, complex_10, or_group, in_large_50 z 50 wartościami) i cztery dla select (pojedyncze kolumny, *, jedno osadzenie relacji, pięć osad). Jest to rodzaj kosztu niewidocznego w globalnym teście obciążenia: regresja na podstawie analizy złożonego filtru or.(...) nie zmieniłaby prawie nic w p95 mało używanego punktu końcowego, ale stałaby się mierzalna na punkcie końcowym o dużym ruchu - stąd zainteresowanie wyizolowaniem go w mikrotestie porównawczym, zamiast polegania wyłącznie na poziomie 2.
aura-core przyjmuje inne podejście: zamiast mierzyć surowy czas, mierzy przepustowość (Throughput::Bytes) serializacji i deserializacji JSON wewnętrznych komunikatów NatsRequest/NatsResponse wymienianych między bramą a usługami — z trzema realistycznymi rozmiarami ładunku (żądanie minimalne, żądanie z zagnieżdżoną treścią JSON, odpowiedź na liście 50-liniowej).
Criterion.rs nie tylko mierzy czas pętli. Najpierw przeprowadza fazę rozgrzewania w celu wypełnienia pamięci podręcznej procesora/systemu operacyjnego, wykrywa wartości odstające za pomocą zmodyfikowanej wersji metody Tukeya (bez wykluczania ich ze zbioru danych), oblicza przedziały ufności poprzez ładowanie początkowe na dużej liczbie ponownie próbkowanych próbek i wykrywa regresje wydajności między dwoma przebiegami za pomocą testu statystycznego Studenta z konfigurowalnym progiem szumu — zwykle ± 1% — w celu zignorowania odchyleń, które nie są statystycznie istotne (bheisler.github.io/criterion.rs/book/analytic.html, dostęp: 23 sierpnia 2026 r.).
Każde uruchomienie kryterium generuje szczegółowy raport HTML w formacie target/criterion/ — rozkłady, wykresy regresji, porównanie z poprzednim przebiegiem. To właśnie tę relację, a nie tylko linię końcową, poważna metodologia musi umożliwić regenerację.
Poziom 2 — testowanie obciążenia k6
Osiem skryptów k6 obejmuje bramę po stronie płaszczyzny danych: health (linia bazowa opóźnienia), auth-flow (rejestracja → logowanie → odświeżenie → wylogowanie), crud-read i crud-write, storage (przesyłanie/pobieranie), realtime-ws, breakpoint (wzrost obciążenia aż do awarii) i supabase-compare. Siedem z nich jest podłączonych do dedykowanego celu Makefile — supabase-compare.js istnieje w repozytorium, ale nie ma jeszcze celu. Stan rzeczy ten artykuł dokumentuje jako taki, a nie go ukrywa.
Konfiguracja udostępniona definiuje progi według typu operacji. Są to kryteria pozytywne/negatywne, które test sprawdza przy każdym uruchomieniu — a nie wyniki, które zostały już zmierzone:
| Czytanie (GET) | p95 < 500 ms · p99 < 1000 ms | Konfiguracja k6 (benchmarks/k6/lib/config.js) |
|---|---|---|
| Pisanie (POST/PATCH) | p95 < 300 ms · p99 < 1000 ms | Konfiguracja k6 |
| Autoryzacja (zaloguj się/odśwież) | p95 < 300 ms · p99 < 1000 ms | Konfiguracja k6 |
| Pamięć (przesyłanie/pobieranie) | p95 < 500 ms · p99 < 2000 ms | Konfiguracja k6 |
| Poziom błędów, wszystkie scenariusze | < 1 % | Konfiguracja k6 |
README.md w folderze benchmarks/ dokumentuje próg odczytu p95 w < 200ms („Supabase SLO”), podczas gdy próg faktycznie zastosowany w benchmarks/k6/lib/config.js — tym, który jest uruchamiany w teście — to p(95)<500. Obydwa pliki pochodzą od siebie. Jest to konkretny przykład, znaleziony podczas czytania kodu źródłowego tego artykułu, pokazujący, dlaczego protokół powinien mieć jedno źródło prawdy w jednej wersji, a nie być dokumentowany w dwóch miejscach: bez niego nawet zespół, który stara się zachować rygorystyczność, kończy się publikowaniem sprzecznych progów.
Poziom 3 — Bezpośrednie porównanie PostgreSQL z API
Skrypt Pythona (direct_vs_api.py) mierzy rzeczywisty narzut bramy + warstwy usług, porównując bezpośrednie żądania psycopg2 z wywołaniami HTTP w ramach tej samej operacji — lista, jednorazowy odczyt według identyfikatora, filtrowany i sortowany odczyt. Każdy pomiar następuje po 10 iteracjach rozgrzewania przed pętlą czasową, następnie oblicza średnią, p50, p95, p99 i przepustowość operacji na sekundę.
Drugi skrypt (aurabase_vs_supabase.py) stosuje tę samą logikę rozgrzewania i obliczania percentyli do bezpośredniego porównania z lokalną instancją Supabase (Supabase CLI, domyślnie localhost:54321) — ta sama maszyna, ta sama sieć lokalna dla obu, dokładnie taka sama dyscyplina parzystości środowiska, którą PlanetScale dokumentuje dla własnych porównań.
Skrypt orkiestracji (collect_baseline.sh, cel bench-baseline z Makefile) łączy trzy poziomy — kryterium na 3 skrzyniach, podzbiór scenariuszy k6 (health i crud-read dzisiaj, jeszcze nie wszystkie 8), następnie porównanie Pythona — i zapisuje dzienniki, raporty JSON i kryteria HTML w folderze z unikalnym znacznikiem czasu: benchmarks/results/AAAAMMJJ_HHMMSS/. Jest to dokładnie odruch datowanego ujawnienia w pojedynczej powtarzalnej serii, który poniższa sekcja formalizuje w pełnym protokole.
Protokół zastosujemy przed opublikowaniem ryciny
Osiem zobowiązań, każde zakotwiczone w praktyce udokumentowanej już przez uznane narzędzie lub projekt strony trzeciej – nie wymyślone na tę okazję.
- Podgrzewanie wstępne niezależnie od pomiaru. Criterion.rs wypełnia pamięć podręczną procesora/systemu operacyjnego przed synchronizacją;
pgbenchwyraźnie zaleca, aby nigdy nie wierzyć biegowi trwającemu zaledwie kilka sekund. - Stały czas trwania, a nie stała liczba iteracji. Obciążenie potrzebuje czasu na osiągnięcie zbieżności — taka jest rola
stagesk6 i flagi-Tpgbench. - Percentyle, nigdy tylko średnia — i aktywna czujność w przypadku skoordynowanych pominięć, jeśli generator obciążenia działa w pętli zamkniętej.
- Środowisko szczegółowo udokumentowane: zatwierdzenie git testowanej usługi, wersja PostgreSQL, specyfikacja sprzętu, wersja narzędzia ładującego. PlanetScale dokumentuje dokładne parametry TPCC (
TABLES=20,SCALE=250, ~500 GB) właśnie z tego powodu — bez tych szczegółów nikt nie będzie w stanie odtworzyć przebiegu. - Wyniki ze znacznikiem czasu i wersją, na stronie marketingowej nigdy nie jest wygrawerowana żadna liczba bez daty. Obecne oprzyrządowanie jest już zapisane w przestarzałym pliku; konieczne będzie rozszerzenie tego odruchu na wszelkie publicznie publikowane pomiary, z regionem przyjmującym udokumentowanym jak każdą inną zmienną środowiskową (zobacz nasz przewodnik na temat suwerenności UE przyjmującej, istotne, gdy liczba zależy od danego regionu).
- Skrypty i surowe dane publikowane są wraz z wynikami zbiorczymi, a nie tylko końcową średnią. PlanetScale zaprasza nawet czytelników do zgłaszania błędu metodologicznego pod dedykowanym adresem – postawy, którą uważamy za zdrową i którą chcemy wznowić.
- Reklamowana przepustowość wraz z opóźnieniami, a nie tylko jedno lub drugie. System może charakteryzować się doskonałymi opóźnieniami przy niskim obciążeniu i spadkiem przepustowości wraz ze wzrostem współbieżności — właśnie to ma ujawnić scenariusz
breakpoint(skalowalność do awarii) naszego pakietu k6 i co wychwytuje pomiar mikrobenchmarkuThroughput::Bytesfirmy Criterion na poziomie funkcji. - Znacząca luka przed ogłoszeniem poprawy. Kilkuprocentowa różnica między dwoma seriami może oznaczać szum pomiarowy, a nie rzeczywisty zysk — Criterion.rs oblicza prawdopodobieństwo, że zaobserwowana różnica jest wynikiem przypadku, zanim zakwalifikuje ją jako regresję lub poprawę. Wyodrębniona liczba, bez tej weryfikacji, jest jedynie statystyczną anegdotą.
Czego nie zrobimy
Ta lista liczy się tak samo, jak powyższy protokół pozytywny.
- Porównywanie różnych topologii (instancja hostowana samodzielnie i zarządzana, instancja zimna i wstępnie podgrzewana) bez jawnego zgłaszania tego.
- Zachowaj najlepszy wynik z dziesięciu, nie wspominając o pozostałych dziewięciu.
- Publikuj rycinę bez daty, bez wersji serwisowej, bez skryptu reprodukcji.
- Opublikuj ponownie istniejące dane marketingowe, o ile nie są powiązane z niniejszym protokołem.
- Porównywanie się z konkurentem na podstawie surowych wyników, jeśli ten konkurent nie publikuje własnej metodologii w równoważny sposób — liczba kontra cisza nie jest porównaniem, to slogan.
Rozpowszechniano informację typu „zimny start krótszy niż 1 ms” bez poparcia powtarzalnym punktem odniesienia. Obecnie jest ona traktowana wewnętrznie jako nieobsługiwana i nie powinna być odczytywana jako zmierzona cecha produktu, dopóki nie potwierdzą tego żadne datowane pomiary z opublikowaną metodologią. Jest to dokładnie ten rodzaj twierdzenia, że protokół ten ma zapobiegać jego powtarzaniu.
Minimalny protokół do testowania dowolnego backendu
Protokół ten nie jest zależny od żadnego konkretnego narzędzia Aurabase — możesz go już dziś zastosować do własnego API.
- Ustaw obciążenie przed narzędziem: tylko do odczytu, do zapisu, realistyczny miks dla Twojej aplikacji — a nie ogólny współczynnik skopiowany z innego projektu.
- Należy wyraźnie oddzielić fazę podgrzewania od fazy pomiaru.
- Uruchom test wystarczająco długo — minuty, a nie sekundy.
- Mierz w percentylach (p50/p95/p99), nigdy samodzielnie.
- Sprawdź, czy generator obciążenia nie znajduje się w pętli zamkniętej, lub popraw pominięcie koordynacji w analizie.
- Izoluj testowane środowisko — bez hałaśliwych sąsiadów i bez konkurencyjnych zadań w tle.
- Opublikuj testowaną wersję, datę, specyfikację sprzętu i skrypt — a nie tylko wynik końcowy.
Na czystej bazie Postgres protokół ten wymaga jednego polecenia pgbench — 20 równoczesnych klientów rozproszonych w 4 wątkach przez 5 minut, z raportem postępu co 10 sekund:
Narzędzia referencyjne według poziomu
Pięć narzędzi, każde dostosowane do innego poziomu stosu — żadne nie zastępuje pozostałych.
| Mikrofon (funkcja) | Kryterium.rs | Czysty procesor, statystyki bootstrap |
|---|---|---|
| Zapytanie SQL | pgbench | Transakcja typu TPC-B, tps i opóźnienie |
| Obciążenie HTTP/WS | k6 (Grafana) | Percentyle, progi pozytywne/negatywne |
| OLTP na dużą skalę | sysbench + TPCC (metodologia teleskopu) | QPS, koszt wydajności |
| Korekta pomiaru | HdrHistogram | Kompensuje skoordynowane zaniedbania |