W maju opublikowałem tu szczery benchmark tej strony i jej bliźniaczki na WordPressie. WordPress wygrał wtedy 6,4× średnio i prawie 8× w medianie, a ja zakończyłem obietnicą: jeśli znajdzie się konfiguracja, która zbliży EmDasha do WordPressa bez przepisywania połowy warstwy danych, opublikuję ciąg dalszy. To jest ten ciąg dalszy.
Pełna wersja po angielsku, z wykresami i całą metodologią, jest na blogu SHIFT64: EmDash Earned a Second Chance. Tuning It Is Another Story. Tutaj opisuję to samo po polsku, z naciskiem na to, co zmieniłem na stronie, którą właśnie czytasz.
W skrócie
- Niecache'owana strona EmDasha potrzebuje dziś 170 ms czasu serwera (mediana) zamiast 547 ms wiosną. To 3,2× szybciej.
- WordPress potrzebuje 78 ms, więc różnica spadła z prawie 8× do 2,2×.
- Z cache'em stron, czyli w wersji, którą dostaje większość czytelników, EmDash odpowiada w 28 ms.
- Object cache w Workers KV to dwie linijki konfiguracji. Ciepła strona renderuje się wtedy w 12 ms, z jednym zapytaniem do bazy zamiast dziesięciu.
- Największa poprawka to jedna linijka w konfiguracji. Większość pozostałych milisekund ukryła się w ustawieniach treści, nie w kodzie.
„Podłoga architektury” okazała się kolejką
Wiosną pisałem, że około 320 ms to podłoga, której nie ruszę bez replik odczytu D1. Myliłem się co do przyczyny. Strona robiła 12–16 zapytań do bazy, a EmDash wykonywał je ściśle jedno po drugim, po około 25 ms każde. Sama strona wpisu czekała więc ponad 300 ms na bazę.
Winne były D1 sessions. Gdy są włączone, warstwa bazy EmDasha puszcza zapytania jednego żądania po kolei, nawet jeśli strona startuje kilka naraz. Dla przeglądarek EmDash dodatkowo z wyprzedzeniem pobiera menu i widgety, które ustawiają się w kolejce przed zapytaniami samej strony. Ta strona nie ma replik odczytu, więc sesje nie dawały jej nic.
Wyłączyłem sesje i sprawiłem, że każda strona startuje niezależne zapytania razem: jedna linijka w konfiguracji i kilka wywołań Promise.all. HTML został identyczny. Mediana czasu renderu (Server-Timing EmDasha) przed i po:
- Strona główna: 296 ms → 67 ms
- Wszystkie wpisy: 300 ms → 66 ms
- Wpis: 320 ms → 63 ms
- Kategoria: 356 ms → 50 ms
Pole minowe: bylines
Dwa z największych kosztów nie siedziały w moim kodzie, tylko w ustawieniach treści, które w panelu wyglądają niewinnie.
- Wpisy bez przypisanego byline’a. Wpis z autorem, ale bez jawnego byline’a, uruchamia fallback: dwa dodatkowe zapytania na każdej stronie, która go listuje. Tak było z 5 z 18 moich wpisów. Przypisanie byline’ów zdjęło kolejne 30–50 ms z każdej listy wpisów. Wybór byline’a jest w bocznym panelu edytora i łatwo go przeoczyć.
- Puste własne pola byline’ów. Szukając tego wyboru, dodałem dwa pola byline’a, „Stanowisko” i „Link do X”, i zostawiłem je puste. Samo to dołożyło 4–7 zapytań na każdej stronie i wypchnęło czas serwera z powrotem do 130–200 ms. Gdy istnieje choć jedno pole, EmDash czyta ich wartości przy każdym ładowaniu byline’ów, nawet gdy wartości nie ma. Usunięcie pól przywróciło dobre liczby.
- Sprawdzanie wersji pól. Nawet bez żadnych pól EmDash sprawdza przy każdym żądaniu numer wersji pól byline’ów: jedno zapytanie więcej, za każdym razem.
Panel admina przed żadną z tych rzeczy nie ostrzega. Znalazłem je tylko dlatego, że liczyłem zapytania na każdej stronie.
Astro 7 i darmowy plan Workers
Sam EmDash jest budowany i testowany na Astro 7, więc zaktualizowałem stronę. Build skrócił się z 40 do 14 sekund. Jedyna widoczna usterka to białe znaki: nowy domyślny tryb Astro 7 skleił „18 artykułów” w „18artykułów”, dopóki nie ustawiłem compressHTML: true.
Mniej widoczna zmiana: Astro 7 nie wysyła nic, dopóki nie wyrenderuje wszystkich asynchronicznych komponentów strony. Sekcja komentarzy sama pobiera swoje dane, więc pierwszy bajt wpisu przychodził około 40 ms później. Wcześniejsze uruchomienie zapytań o komentarze odzyskało połowę tej straty.
Potem strona zaczęła się sypać. Przez pięć minut, do czasu wycofania zmian, do 60% niecache'owanych żądań kończyło się pustym błędem 503. Darmowy plan Workers daje 10 ms CPU na żądanie, a render strony EmDasha potrzebuje 10–24 ms. Cloudflare toleruje sporadyczne przekroczenia, ale mój własny benchmark, około 1000 niecache'owanych wejść w niecałą godzinę, przekroczył granicę. Rozwiązanie to płatny plan za 5 dolarów miesięcznie albo dużo łagodniejsze testy.
Zgłoszenia do EmDasha
5 października zgłosiłem do EmDasha cztery problemy z wydajnością. Reakcja była szybka:
- #3905 : komentarze liczone i listowane dwoma zapytaniami po kolei. Bot EmDasha otworzył poprawkę 46 minut po zgłoszeniu, a maintainer zmergował ją po czterech dniach. Trafi do wydania po 1.2.0.
- #3915 : sesja D1 wykonuje zapytania pojedynczo. Poprawka jest w przeglądzie ( #3937 ).
- #3903 : wersja pól bylinów czytana z bazy przy każdym żądaniu. Otwarte.
- #3904 : wpisy bez tagów odpytywane ponownie. Na to wysłałem własną poprawkę, #4088 . Bierze brakujące tagi z danych, które EmDash już załadował, i oszczędza jedno zapytanie na stronie głównej i liście wpisów. W moim teście lokalnym to 4 zamiast 5 zapytań i 52 zamiast 75 ms. Czeka na przegląd maintainera.
Rewanż: trzy doby z tego samego VPS-a
Metoda jak wiosną: ten sam VPS OVH w Warszawie, te same 13 stron i ta sama miara, czyli czas do pierwszego bajtu minus DNS, TCP i TLS. Pomiary szły co 15 minut od 6 do 9 października: 317 przebiegów, 24 726 żądań i ani jednego błędu. Mediana czasu serwera:
- EmDash, pełny render: 170 ms (wiosną 547 ms; p95 348 ms)
- EmDash, trafienie w cache stron: 28 ms (p95 51 ms)
- EmDash z object cache w KV: 136 ms (p95 218 ms)
- WordPress z object cache, bez cache stron: 78 ms (wiosną 68 ms; p95 160 ms)
Jedno zastrzeżenie na korzyść WordPressa: emdash.pl to ręcznie napisany motyw z object cache, ustawiony przez kogoś, kto robi to zawodowo. Jego 78 ms to prawdopodobnie najlepsze 5% stron na WordPressie. Typowa instalacja z page builderem i kilkudziesięcioma wtyczkami jest najpewniej wolniejsza, często dużo.
Co jeszcze pokazały dane:
- Cron nie miał wpływu. Sprawdziłem, czy cron EmDasha odpalany co minutę, którego wiosną nie było, nie rozgrzewa sztucznie bazy. Nie: pełny render trwał 174 ms z nim i 170 ms bez niego.
- Zimne starty bolą wszystkich podobnie. Pierwsze żądanie po 15 minutach ciszy kosztowało +54 ms na EmDashu i +64 ms na WordPressie.
- EmDash zwalnia w ciągu europejskiego dnia. Mediana rośnie ze 146 ms w nocy do 183 ms po południu (UTC). WordPress stoi w miejscu, więc to raczej obciążenie D1.
- Ogony prawie się nie ruszyły. p99 EmDasha to 938 ms, najgorszy przypadek 2,7 s. Mediana to inna historia, ale rzadkie przestoje D1 zostały.
KV: dwie linijki, których wiosną nie miałem
EmDash potrafi trzymać wyniki zapytań w Workers KV. Włączenie tego to dwie linijki:
// astro.config.mjs, plus przestrzeń KV podpięta jako CACHE w wrangler.jsonc
emdash({ objectCache: kvCache({ binding: "CACHE", defaultTtl: 86400 }) }) Postawiłem dokładną kopię tej strony z tą jedną zmianą pod kv.emdashcms.pl i mierzyłem ją obok głównej strony i WordPressa. Object cache zapisuje w KV całe wyniki zapytań, razem z bylinami, i czyści je przy zmianie treści. Wiosną tej funkcji nie było: weszła w EmDash 0.22.0 22 czerwca 2026.
- Pierwsze wejście na stronę (zimny KV): render 102 ms, czas serwera 155 ms, 1 zapytanie do D1
- Drugie wejście w ciągu minuty (ciepły KV): render 12 ms, czas serwera 67 ms, 1 zapytanie do D1
- Dla porównania, bez object cache: render 103 ms, czas serwera 170 ms, 9–10 zapytań
Na ciepło EmDash renderuje szybciej niż WordPress i ląduje mniej więcej na jego czasie serwera. KV trzyma wartość gorącą w danej lokalizacji przez około minutę, więc przy stałym ruchu większość żądań trafi na ciepły cache. Moje pomiary szły co 15 minut, dlatego połowa z nich płaciła za zimny odczyt.
Dwie rzeczy, o których trzeba pamiętać:
- Na darmowym planie podnieś TTL (
defaultTtl). KV pozwala tam na 1000 zapisów dziennie, a domyślny godzinny TTL nadpisuje każde zapytanie co godzinę. - Wybierz object cache albo cache stron, nie oba. Gdy skonfigurowany jest cache stron, EmDash pomija object cache przy renderze strony, żeby nie odbudować wyczyszczonej strony z danych sprzed minuty.
Dla mnie to wynik, który robi z EmDasha uczciwy wybór. Ciepła strona ląduje na poziomie dobrze ustawionego WordPressa, a nadal nie ma serwera: nic do łatania, żadnego PHP ani wtyczek do aktualizowania i żadnego VPS-a, do którego ktoś mógłby się włamać. Do tego to ustawienie, które w nowym projekcie włączam w pięć minut, zamiast tygodniami polować na pojedyncze zapytania.
Uczciwie: to jeszcze nie jest łatwy stack
Każdą milisekundę z tego artykułu odzyskałem, licząc zapytania samodzielnie. Nic nie wywaliło się głośno. Każdy koszt chował się w czymś, co wygląda niewinnie:
- domyślne ustawienie szablonu (D1 sessions): około 250 ms na stronę,
- dwa puste pola w panelu admina: do 90 ms,
- aktualizacja frameworka (Astro 7): 40 ms na stronach wpisów,
- limit planu (10 ms CPU): pięć minut błędów 503.
WordPress ma dwadzieścia lat odpowiedzi na swoje pułapki: wtyczki cache'ujące, Query Monitor, firmy hostingowe, które widziały już wszystko. Przy EmDashu trzeba umieć czytać nagłówki Server-Timing i pamiętać, że każdy nowy rodzaj danych to kolejna podróż do D1. Trzeba też pilnować strony po starcie, bo jedno niewinne ustawienie potrafi cofnąć całą pracę. Zanim EmDash będzie tak prosty jak WordPress, potrzebuje bezpiecznych ustawień domyślnych, ostrzeżeń w panelu i jednej udokumentowanej drogi do cache'owania.
Co zmieniłem na tej stronie
- Wyłączone D1 sessions i równoległe zapytania na każdej stronie.
- Każdy wpis ma przypisany byline, bez pustych pól bylinów.
- Astro 7 i adapter Cloudflare 14.
- Własny cache stron na brzegu sieci. Od 10 października trzyma strony przez 7 dni i czyści się przy każdej publikacji, edycji, komentarzu, zmianie w mediach i deployu.
- Kopia testowa z object cache w KV pod kv.emdashcms.pl.
Co dalej
Zostaję przy EmDashu. Dałem mu drugą szansę i ją wykorzystał: dla mnie stoi teraz na tej samej półce co WordPress, jako narzędzie, które mogę wybrać do prawdziwego projektu klienta. Najwięcej upraszcza object cache w KV. Zamiast pilnować każdego zapytania, dostaję szybkie strony z jednej linijki konfiguracji i bez serwera do utrzymania.
Dlatego będę dalej rozwijał tę stronę i postaram się wykorzystać EmDasha z KV w swoich projektach. Najbliższe kroki:
- aktualizacja do EmDasha 1.2,
- decyzja, czy główna strona przechodzi na object cache w KV, czy zostaje przy cache'u stron,
- kolejne poprawki wysyłane do EmDasha, zaczynając od #3903 .
Jedno się nie zmieniło. Jeśli zespół potrafi pracować w Gicie, zwykłe Astro z plikami Markdown nadal jest lepszą drogą: statyczna strona nie ma czego renderować, cache'ować ani pilnować. Ale wiele firm nie przepuści treści przez Gita, a ich redaktorzy potrzebują panelu. Dla nich EmDash jest dziś realną opcją, o ile ktoś pilnuje zapytań.
Pełny artykuł i dane
- Pełny artykuł po angielsku na SHIFT64: EmDash Earned a Second Chance. Tuning It Is Another Story.
- Techniczny deep-dive ze wszystkimi poprawkami i liczbami
- Repozytorium benchmarku z surowymi wynikami z października i skryptami
- Wiosenny benchmark na tej stronie: Postawiłem emdashcms.pl i emdash.pl, zrobiłem 4 732 pomiarów
Brak komentarzy