Optymalizacja strony

Kolejny wpis, który przeleżał wiele czasu jako szkic. Nie znalazłem na niego czasu, a teraz sprawdziłem i dobrze się zestarzał, więc opublikuję to, co mam, choć nie pociągnąłem do końca tematu, którym jest optymalizacja stron WWW, tym razem bardziej od strony serwera, niż WordPressa, o którym wtedy napisałem.

Na początek polecam wpis Yzoji o optymalizacji bloga. I komentarze do niego. Tak, wpis jest sprzed trzech lat. Tak, jest aktualny, a wszystko co tu znajdziesz powstało właśnie wtedy. Raczej postaram się napisać uzupełnienie, niż powtarzać rady z tamtego wpisu.

Efekty

Nie mam niestety porównania sprzed wprowadzania zmian, ale żeby było wiadomo o czym rozmawiamy. Efekty optymalizacji strony bloga, wg PageSpeed Insights, przedstawiają się następująco:

Wynik optymalizacji strony wg PageSpeed dla desktop - performance 100%
Wynik dla desktop
Wynik optymalizacji strony wg PageSpeed wynik dla mobile - performance 9%
Wynik dla mobile

Kompresja

Na przyspieszenie działania bloga pomogło zmniejszenie poziomu kompresji w nginx. Tak, dobrze czytacie, zmniejszenie, nie zwiększenie. Dlaczego? Otóż tekst kompresuje się dobrze tak czy inaczej. A różnice w szybkości działania kompresji gzip są znaczne. Czyli mamy mininalnie większą ilość przesyłanych danych, ale odpowiedź jest wysyłana znacznie szybciej! Być może to kwestia relatywnie słabego VPSa, ale skoro nie widać różnicy, po co przepłacać? W każdym razie w konfiguracji nginx mam:

gzip_comp_level 1;

Lazy loading

Kolejną rzeczą, która przyspieszyła działanie tego bloga było wyłączenie lazy loading. Było o tym u Yzoji, ale warto powtórzyć, bo znowu, jest to nieintuicyjne. W dodatku wszyscy mantrują, że włączenie lazy loadingu jest dobre dla szybkości ładowania. No i teoretycznie mają rację. Ale nie jest to prawdą na stronach, gdzie ilość załączanych grafik jest niewielka. Więc jak mam jedną czy w porywach dwie skromne grafiki na wpis, to lazy loading tylko spowolni ładowanie. Gdyby grafik było więcej lub były większe – pewnie włączenie lazy loadingu mógłoby pomagać.

Google

Wyłączenie zabawek Google. Firma ta prezentuje pewną dwumyślność. Z jednej strony chce, by strona działała szybko. Z drugiej strony, sama dostarcza rozwiązania, które fatalnie wpływają na wydajność strony i stwarzają problemy w ich własnym scoringu! Google Analytics – wydajnościowe zło. Fonty Google – kolejne wydajnościowe zło. Google AdSense też drastycznie pogorszy szybkość działania strony.

Rozwiązanie, jeśli nie chcemy całkiem pozbywać się Google? W przypadku AdSense można zrezygnować z wyświetlania reklam wszędzie i ograniczyć ich obecność do wpisów, na których jest największy ruch. Taki kompromis – strony z reklamami będą ładować się dłużej, ale większość stron będzie działać szybko. Oczywiście wiąże się to z rezygnacją z reklam na głównej. Nieco upierdliwe, bo oznacza to ręczne zarządzanie kodem JS odpowiedzialnym za wyświetlanie reklam na poziomie konkretnych wpisów, ale dla mnie OK. Zamiast Google Analytics polecam Matomo. Z fontów Google zrezygnowałem, zamiast tego pewnie można serwować je lokalnie.

Klucz RSA

Kolejna nieoczywista sprawa – rozmiar klucza wykorzystywanego przy SSL/TLS. Miałem podejście security is our priority i klucz RSA o długości 4096 bitów. Tyle tylko, że póki co 2048 bity są także uznawane za bezpieczne. No i na tym blogu nie ma nic wrażliwego. Najbardziej wrażliwe jest hasło, które przesyłam przy logowaniu, więc zmniejszyłem rozmiar klucza i… Pomogło to skrócić czas nawiązywania połączenia z serwerem. Znowu, może kwestia stosunkowo słabego VPSa. Przy tej okazji polecę jeszcze wpis o tym jak zrobić sobie certyfikat SSL/TLS z oceną A+ na nginx.

Jak widać, optymalizacja stron WWW nie jest oczywista i warto do tematu podejść kompleksowo.

Pretekst

Od jakiegoś czasu szukałem pretekstu, żeby pobawić się maszynkami z Ampere A1 od Oracle. Poza tym, w zadaniach przetestowanie Cloudflare na blogu wisiało… prawie 5 lat. I jeszcze na dodatek gorącym tematem jest AI, często reprezentowana ostatnio przez ChatGPT. Ale jakoś na nic nie było czasu i potrzeby.

Zatem wpadłem na pomysł, żeby postawić bloga, który będzie WordPressem, stojącym na VMce z arm64, za Cloudflare, a treść dostarczać będzie głównie AI. Trzy pieczenie na jednym ogniu. W sumie cztery, bo jeszcze sprawdzę indeksowanie tego tworu i zarobię miliony na reklamach. Poznajcie blog everything about coffee.

Przyznam, że było trudniej, niż się spodziewałem. Najpierw był problem z wyborem domeny. Stwierdziłem bowiem, że taki eksperyment wymaga stosownej separacji. W domenach raczej nie siedzę, więc znalezienie czegoś sensownego w niewielkich pieniądzach było trudne. Stanęło na tym, że analogicznie jak na głównej domenie niech się składa w jedno słowo. I tak powstał coffee express. Bez es. W sumie także bez e w środku, bo byłyby aż trzy kolejno, ale to już wybór, nie ograniczenie techniczne.

Domena

Wydawać by się mogło, że kupno domeny w 2023 jest proste, szybkie i przyjemne. Sprostuję, nie jest. A przynajmniej nie jest, jeśli korzysta się z TLD .es a kupuje w OVH. Rejestrator ma teraz dziwne wymagania, panel OVH ma dziwne pola i komunikaty. Ostatecznie udało się, po kontakcie z supportem OVH. Dwukrotnym.

Hosting

Jeśli chodzi o Ampere A1, to ostatecznie odpuściłem instalację Debiana, którego Oracle nie dostarcza i użyłem gotowca w postaci Ubuntu. Przynajmniej na podstawce AKA hypervisorze, bo sam blog stoi już w kontenerze LXC z Debianem. Za wiele się tam nie dzieje, ale – po krótkim obcowaniu – maszynka wygląda na wydajną i generalnie śmiga.

Cloudflare

Przepięcie domeny na Cloudflare – szybkie, łatwe i przyjemne. Podpowiadają co mają podpowiadać, autouzupełnianie działa. Panel przejrzysty, ustawienia domyślne sensowne. Opcji w wersji darmowej niewiele, ale wystarczają.

Oczywiście jest tricky part związana z certyfikatami SSL czy ustawieniami DNS, jeśli chce się mieć coś dostępne bezpośrednio, ale da się. No i wypada zablokować ruch HTTP(S) do serwera spoza Cloudflare. Jest wiele sposobów, wybrałem prawdopodobnie najprostszy i najgorszy, czyli iptables z wyjątkami na klasy adresowe Cloudflare na maszynie. Może kiedyś zmienię.

WordPress

Stawianie WordPressa także okazało się pewnym wyzwaniem. Może nie tyle samo postawienie, co doprowadzenie do działania. W każdym jakby ktoś wybrał wariant z ruchem nieszyfrowanym między blogiem a Cloudflare, czyli teoretycznie najprostszą opcję, to może się naciąć. W praktyce chyba prościej uruchomić to jako szyfrowane, z certyfikatem self signed. Nie obyło się bez grzebania w wp-config.php. Poza tym, raczej było prosto. Najwięcej czasu zeszło na wybór grafiki i ręczną instalację i konfigurację wszystkich wtyczek do WordPressa, których używam.

ChatGPT

No i na koniec część związana z AI. Jak łatwo można się domyślić, bawiłem się chatGPT przy porannej kawie i wtedy powstał pomysł na bloga generowanego przy pomocy AI. No właśnie nie przez AI, a przy pomocy. Co to znaczy? Ano to, że może się zdarzyć, że ingeruję w odpowiedzi zwrócone przez chatGPT. Łączę je, przycinam, albo dodaję coś od siebie. Ale nie jest to regułą i zwykle po prostu przeklejam wprost. Bez korekty, sprawdzania faktów itd. Błędy się zdarzają, o czym można przeczytać choćby w komentarzach do tego wpisu. Poza tym, nie podaję prompta i sam, ręcznie wybieram tytuł. Ot, powiedzmy taki asystent leniwego copywrightera w postaci AI. Co do zasady muszę zmieścić się z utworzeniem wpisu od początku do końca przy paru łykach porannej kawy.

Projekt nie jest skończony. Marzy mi się dorzucanie powiązanych obrazków do każdego wpisu. Najchętniej automatyczne. Brakuje detali typu favicona czy optymalizacja szybkości. Choć ten w zasadzie goły WordPress za Cloudflare działa wg GTmetrix podobnie szybko, co ten blog. Nad wyświetlaniem reklam nadal pracuję – chwilę to trwa już po stronie Google No i oczywiście wpisów na razie jest mało, a chciałbym dodawać około dwóch tygodniowo, przynajmniej przez najbliższych parę miesięcy.

DeepL

UPDATE: Do gromady dołączył jeszcze DeepL, a dokładnie Write. Coraz częściej zdarza mi się dodać coś od siebie, poza tym ChatGPT pisze dość sucho i encyklopedycznie. Nie używam domyślnie, raczej sporadycznie póki co. I uwzględniam tylko niektóre sugestie, ale warto wspomnieć i o tym narzędziu.

Pomigracyjnie

W poprzednim wpisie pisałem o planowanej migracji na Oracle Cloud. Jak widać blog stoi już w nowej lokalizacji, więc operacja jest zakończona i mogę napisać kilka słów z perspektywy.

Migracja

Poszło niemal bezproblemowo. Backup w zasadzie zadziałał. Był problem z detalami typu lista zainstalowanych pakietów i crony. W sumie nieistotne i/lub poprawione. Xpil opisał swoją migrację VPSa i po tej lekturze miałem silne postanowienie zamknięcia wszystkiego w kontenerach LXC. To nieco wydłużyło proces migracji i dodało trochę zadań. Co prawda nadal nie jest to taka separacja jak w dockerach czyli per usługa, ale mariadb + nginx + całe WWW w osobnym VPSie też jest OK.

Konieczne było lekkie przemeblowanie. Musiałem rozdzielić skrypty cron do właściwych kontenerów. Okazało się też, że wynik działania jednego kontenera (Planeta Joggera) musi trafić nie do hypervisora, tylko do innego kontenera, a ten nie ma dostępu. Skrypt w cronie na hypervisorze załatwił sprawę.
Podobnie niezbyt elegancko rozwiązany jest backup bazy danych. Dump robię teraz w LXC, a następnie cały kontener jest backupowany. W ten sposób zawartość bazy jest zdublowana. Mam pomysł jak to rozwiązać, nie wiem, czy potrzebuję. Tyle o samej migracji, a efekty i hosting?

Efekty

Przede wszystkim jest szybciej, przynajmniej wg GTmetrix. Niestety nie zrobiłem testu tuż przed migracją i od razu po niej. Mam tylko ten link z twardymi danymi, ale w międzyczasie się poprawiło, więc polegam głównie na pamięci. Ale tak dobrze to nigdy nie było:

Blog GTmetrix w Oracle Cloud
GTmetrix w Oracle Cloud

Hosting

Pewnie w sporej części to kwestia przejścia z jednego VPSa na dwa, w dodatku z widocznymi dwoma rdzeniami w systemie. W Arubacloud było:

processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 79
model name      : Intel(R) Xeon(R) CPU E5-2650L v4 @ 1.70GHz
stepping        : 1
microcode       : 0xb000038
cpu MHz         : 1699.999
cache size      : 35840 KB
physical id     : 0
siblings        : 1
core id         : 0
cpu cores       : 1
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx hypervisor lahf_lm 3dnowprefetch pti arat
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit
bogomips        : 3399.99
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits virtual

Teraz jest (pojedynczy rdzeń):

processor       : 1
vendor_id       : AuthenticAMD
cpu family      : 23
model           : 1
model name      : AMD EPYC 7551 32-Core Processor
stepping        : 2
microcode       : 0x1000065
cpu MHz         : 1996.249
cache size      : 512 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 1
apicid          : 1
initial apicid  : 1
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 xsaves clzero xsaveerptr virt_ssbd arat npt nrip_save arch_capabilities
bugs            : sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass
bogomips        : 3992.49
TLB size        : 1024 4K pages
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits virtual

Blog zawsze dominował, jeśli chodzi o obciążenie, ale teraz ma całe zasoby dla siebie. Z drugiej strony bieżący VPS ma sporo wolniejszy dysk (3000 IOPS, 24 MB/s). Można tym jakoś sterować, ale zakładałem na domyślnych wartościach. No i nie widzę potrzeby zmiany.

Wady

Żeby nie było, że wszystko jest fajnie – port 25 TCP w Oracle Cloud jest zablokowany na twardo, w obie strony. Czyli ani maila nie przyjmę, ani nie wyślę. Znalazłem, że trzeba pisać do supportu o odblokowanie. Napisałem i zobaczymy. O ile do monitoringu poczta nie jest mi potrzebna, bo powiadomienia mogę wysyłać Telegramem, to przy blogu jest to jakby kluczowe. Potwierdzanie subskrybcji komentarzy itp. Z drugiej strony widzę, że nie było to jakoś mocno wykorzystywane… Zobaczę co odpowiedzą i wtedy pomyślę, co dalej.

Ogólnie sporo rzeczy w Oracle Cloud jest załatwianych przez support. Ustawienie PTR – support (działa!). Inny obraz dysku dla arm64 – support (tak powiedzieli na czacie, odpuściłem).

UPDATE: Port 25 nie został odblokowany, bo free tier. Nie jest to duży problem – wystarczy skonfigurować SMTP relay u któregoś z dostawców.