WooCommerce sepet sayfası neden önbelleğe alınamaz ve her istek neden PHP'yi yeniden tetikler? Session yönetiminin TTFB üzerindeki etkisi ve fragment caching seçenekleri.
WooCommerce Sepet Sayfası Neden Her Zaman Yavaş Olur?
WooCommerce mağazanızı optimize ettiniz; görseller sıkıştırıldı, JavaScript dosyaları birleştirildi, statik sayfalar için bir önbellek eklentisi kuruldu. Ana sayfa milisaniyeler içinde yükleniyor, ürün sayfaları da kabul edilebilir sürelerde geliyor. Ama alışveriş sepeti sayfasına her gittiğinizde sunucu yanıtı uzuyor, TTFB kötüleşiyor ve kullanıcı bekliyor. Önbellek eklentisi kapatılmış gibi davranıyor.
Sorun önbellekte değil. Sepet sayfası, WooCommerce'in tasarımı gereği tam önbelleğe alınamaz; çünkü sayfa her ziyaretçi için, her oturum için farklı içerik üretmek zorundadır. Bu durum bir konfigürasyon hatası değil, platforma özgü bir mimari gerçektir. Anlaşılması gereken, bu gerçeğin neden böyle olduğu ve bu durumla nasıl başa çıkılabileceğidir.
Bir müşteri deneyimi üzerinden gidelim. Ziyaretçi ürün sayfasında "Sepete Ekle" düğmesine tıklıyor; bu noktadan itibaren WooCommerce o ziyaretçi için bir oturum başlatıyor ve sepet içeriğini bu oturuma bağlıyor. Sepet sayfasına gidildiğinde PHP, ziyaretçinin oturumunu okuyor, sepet içeriğini veritabanından çekiyor, fiyatları hesaplıyor, kupon durumunu kontrol ediyor ve kargo seçeneklerini belirliyor. Tüm bu işlemler her sayfa yüklenmesinde yeniden gerçekleşiyor.
Sepet sayfasının önbelleğe alınamamasının teknik nedeni
Bir önbellek sistemi çalışırken şu mantıkla işler: bir URL'ye ilk istek geldiğinde PHP çalıştırılır, sonuç HTML olarak diske yazılır; sonraki istekler için PHP çalıştırılmadan bu HTML doğrudan sunulur. Bu model, sayfanın tüm ziyaretçiler için aynı içeriği ürettiğinde mükemmel çalışır. Statik sayfalar, blog yazıları ve kategori listeleri bu kalıba uyar.
Sepet sayfası bu kalıba uymaz. Aynı URL (/sepet/) her kullanıcı için farklı içerik üretir; birinin sepetinde üç ürün varken diğerinin sepeti boştur, birinde kupon uygulanmışken diğerinde uygulanmamıştır, birinin kargo bölgesi farklıdır. Önbelleklenmiş bir HTML dosyasını bir sonraki kullanıcıya sunmak, o kullanıcıya başkasının sepet içeriğini göstermek anlamına gelir ve bu güvenlik açığından öte ciddi bir işlevsellik sorunudur.
Çoğu önbellek eklentisi bu durumun farkındadır. Sepet sayfasını, ödeme sayfasını ve hesabım sayfasını otomatik olarak önbellek dışında tutar. Bunu bir sorun değil, bir özellik olarak sunar. Ancak önbellek dışı kalan bu sayfalar, her istek için tam PHP yürütme döngüsünü tetiklemeye devam eder ve bu döngü ne kadar uzun sürerse TTFB o kadar yüksek kalır.
Yanlış bir beklenti sık karşılaşılan bir sorundur. Önbellek eklentisi kurulur, önbellek isabet oranı (cache hit rate) raporlarda yüksek görünür ve bu başarının sepet sayfasına da yansıyacağı varsayılır. Aslında iki ölçüm birbiriyle ilişkisizdir; önbellek, kapsayamadığı sayfaları iyileştiremez.
Her istek PHP'yi nasıl tetikler?
Statik sayfa önbelleği olmayan bir senaryoda normal bir WordPress sayfası için şu süreç işler: PHP başlar, WordPress yüklenir, veritabanına birkaç sorgu atılır, tema çalıştırılır ve HTML üretilir. WooCommerce kuruluyken bu süreç daha karmaşıktır; eklentiler, kancalar (hooks) ve filtreler sisteme eklenir ve her biri yürütme süresine katkıda bulunur.
Sepet sayfası için bu sürecin üzerine şunlar da eklenir: WC_Session başlatılır, oturum deposundan kullanıcının verisi okunur, WC_Cart nesnesi oluşturulur, ürün verileri çekilir, kupon doğrulaması yapılır, vergi hesaplamaları çalıştırılır ve kargo yöntemleri sorgulanır. Bu adımların her biri ek veritabanı sorgusu veya hesaplama gerektiren işlemlerdir.
Veritabanı sorgu sayısı fark yaratır. Basit bir WooCommerce sepet sayfası yüklemesinde çalışan sorgu sayısı, iyi optimize edilmiş bir ana sayfanın iki katını kolaylıkla geçebilir. Eklenti sayısı arttıkça bu rakam büyür; birçok eklenti sepet değişikliklerini dinlediği kancalara ek işlem yükler ve her istek bu yükü taşır.
PHP bellek tüketimi de bu tabloya eklenir. Sepet nesnesi ürün nesnelerini, değişken ürünlerin (variable products) varyantlarını ve ilgili meta verileri belleğe alır. Büyük kataloglu mağazalarda bu bellek baskısı, PHP'nin yanıt üretme süresini doğrudan etkiler. İstek başına bellek, sunucu kapasitesini eşzamanlı kullanıcılar açısından da sınırlar.
Session yönetimi TTFB'yi nasıl etkiler?
WooCommerce, PHP'nin yerleşik oturum (session) mekanizması yerine kendi oturum yöneticisini kullanır. Yerleşik PHP oturumları dosya sistemine yazar; WooCommerce ise oturum verilerini wp_woocommerce_sessions tablosuna kaydeder. Bu tablonun durumu, sepet sayfasının TTFB'sini doğrudan etkiler.
Varsayılan kurulumda her sayfa yüklemesinde şu adımlar yaşanır: PHP, isteğin çerezinden (cookie) oturum kimliğini okur; bu kimlikle veritabanından oturum satırını çeker; oturum verisini çözümler (unserialize); sayfa işlemi tamamlanır; güncellenmiş oturum verisi tekrar serileştirilip (serialize) veritabanına yazılır. Hem okuma hem yazma işlemi her istekte gerçekleşir.
Tablo şişer. wp_woocommerce_sessions tablosu büyük mağazalarda hızla büyüyebilir; sitelerinde arama yapan, sepete ürün ekleyip terk eden ya da birden fazla cihazdan giriş yapan her ziyaretçi bu tabloya satır bırakır. Oturum temizleme görevi (cron job) varsayılan aralıklarla çalışır; ancak tablo boyutu belirli bir eşiği geçince sorgu süreleri uzar ve bu gecikme TTFB'ye yansır.
Gecikmenin bir diğer kaynağı satır kilitleridir (row locks). Çok sayıda eş zamanlı kullanıcının bulunduğu mağazalarda, özellikle kampanya dönemlerinde, oturum tablosundaki satır kilitleri birbiriyle çakışabilir. Bu durum, yüksek trafik anlarında sepet sayfasının TTFB'sinde düzensiz artışlar olarak gözlemlenir ve sunucu kaynakları yeterli görünse bile performans dalgalanmaları yaşanır.
Fragment caching: kısmi önbelleğin mantığı ve sınırları
Fragment caching (parçalı önbellekleme) şu fikre dayanır: sayfanın tamamını önbelleğe almak mümkün değilse, değişmeyen bölümleri önbellekle, yalnızca kişiselleştirilmiş parçaları dinamik bırak. Ana gezinme menüsü, ürün önerileri bloğu, tanıtım bantları değişmez; sepet toplamı, kupon durumu ve kullanıcıya özel bildirimler değişir.
Uygulamada iki yol öne çıkar. Birincisi sunucu tarafı fragment caching: PHP, önbelleklenebilir bloğu bir anahtar-değer deposuna (Redis veya Memcached) yazar; sonraki istekte veritabanına gitmek yerine bu depodan okur ve yalnızca kişiselleştirilmiş bölümleri hesaplar. İkincisi istemci tarafı yaklaşım: sayfa bir iskelet HTML ile hızla sunulur, kişiselleştirilmiş içerik sonradan JavaScript ile AJAX aracılığıyla çekilir ve kullanıcı sayfayı dolu görmeden önce sayfanın çerçevesini görür.
WooCommerce'deki yaygın uygulama AJAX tabanlıdır. Sepet sayacı ve mini sepet, sayfa yüklendikten sonra ayrı bir uç noktaya (endpoint) yapılan AJAX çağrısıyla güncellenir. Bu yaklaşım TTFB ve FCP (First Contentful Paint) değerlerini iyileştirirken, LCP (Largest Contentful Paint) öğesinin bir sepet tablosuna bağlı olduğu durumlarda sınırlı kalır.
Fragment caching her zaman fayda sağlamaz. Sepet sayfasının zaten kısa olduğu, tek ürünlü veya basit mağazalarda AJAX çağrılarının ek karmaşıklığı performans kazancından büyük olabilir. Birden fazla eş zamanlı AJAX isteği, tek bir tam sayfa yüklemesinden daha fazla sunucu yükü yaratır; bu nedenle karar, mağazanın yapısına ve sepet sayfasının ne kadar karmaşık olduğuna bağlıdır.
PHP ve veritabanı yapılandırmasının payı
Sepet sayfası önbelleğe alınamıyorsa sunucunun her isteği kısa sürede işleyebilme kapasitesi belirleyici olur. PHP-FPM havuzu boyutu, OPcache yapılandırması ve PHP sürümü bu kapasiteyi doğrudan şekillendirir. Bu üç bileşen doğru yapılandırılmadığında sepet sayfasının TTFB'si, mağaza büyüdükçe görünmez biçimde artar.
PHP'nin OPcache'i yorumlama yükünü ortadan kaldıran ilk ve en temel optimizasyon katmanıdır. WooCommerce gibi büyük bir kod tabanında opcache.memory_consumption ve opcache.max_accelerated_files değerlerinin yetersiz kalması, kod tabanının bir bölümünün önbelleğe sığmaması anlamına gelir. Sığmayan parçalar her istekte yeniden yorumlanır.
Veritabanı yük yönetimi de aynı derecede önemlidir. MySQL yapılandırmasında innodb_buffer_pool_size değeri yeterince büyük olmadığında, wp_woocommerce_sessions tablosunun sık okunan satırları bellek yerine diskten çekilir. Disk erişimi bellek erişimine kıyasla büyüklük sırası fark içerir ve bu fark yüksek trafik dönemlerinde ölçülebilir hale gelir.
Redis ile nesne önbellekleme (object caching) sepet sayfasına doğrudan yardımcı olmaz; çünkü her kullanıcının oturum verisi benzersizdir. Ancak ürün meta verileri, vergi kurları ve kargo bölgeleri gibi yüzlerce kullanıcı için değişmeyen verilerin veritabanı yerine Redis'ten gelmesi, genel sorgu yükünü azaltır; sepet sayfası bu dolaylı rahatlamadan payını alır.
Sunucu yazılımı ve reverse proxy'nin rolü
Bazı sunucu yazılımları bu soruna özgü çözümler sunar. LiteSpeed'in önbellek sistemi, çerez bazlı kurala göre sepet sayfasını önbellekten hariç tutarken değişmeyen bölümler için ESI (Edge Side Includes) tekniğini kullanabilir. Bu yaklaşım sunucu yazılımı ile önbellek eklentisinin koordineli çalışmasını gerektirir; yanlış yapılandırıldığında bir kullanıcının sepet içeriği başka bir kullanıcıya gösterilebilir.
Bir reverse proxy katmanı, önbelleklenemeyen sepet sayfası için doğrudan fayda sunmaz; arka uçtaki PHP yükü aynen kalır. Ancak SSL sonlandırma ve keep-alive bağlantı yönetimi gibi görevleri üstlenerek sunucu kaynaklarını serbest bırakır. Yüksek trafik dönemlerinde bu dolaylı katkı ölçülebilir fark yaratabilir; özellikle eş zamanlı bağlantı sayısının artık sunucuyu zorladığı durumlarda görünür hale gelir.
PHP sürümünün güncel olması tartışmasız fayda sağlar. PHP 8.x, önceki sürümlere kıyasla WooCommerce gibi nesne yoğun uygulamalarda belirgin hız artışı sunar. Bu değişiklik altyapı düzeyinde yapılır ve sepet sayfası dahil tüm dinamik sayfaları etkiler; ayrıca eklenti uyumluluğu test edildiğinde genellikle güvenle uygulanabilir bir adımdır.
Sepet sayfasının TTFB'sini düşürmek için pratik adımlar
İlk adım ölçmektir. Sepet sayfasının TTFB'si ile diğer dinamik sayfaların TTFB'si karşılaştırılmalıdır. Sorunun kaynağını bulmadan önce yavaşlığın sunucu kapasitesinden mi, oturum tablosundan mı, yoksa eklenti yükünden mi kaynaklandığını anlamak gerekir. Her birinin çözümü farklıdır ve yanlış teşhis gereksiz çabaya yol açar.
wp_woocommerce_sessions tablosu temizliği hızlı ve güvenli bir başlangıç noktasıdır. Uzun süredir aktif mağazalarda bu tablonun boyutunun kontrol edilmesi ve süresi dolmuş oturumların temizlenmesi tek başına ciddi fark yaratabilir. WooCommerce'in yerleşik cron görevi bu temizliği yapar; ancak görevin düzenli çalışıp çalışmadığı, tablo boyutunun kabul edilebilir sınırlarda olup olmadığı kontrol edilmelidir.
Eklenti yükünü izole etmek ikinci adımdır. Sepet sayfasına özgü kancaları gereksiz yere dolduran eklentiler TTFB'yi sistematik biçimde artırır. Hangi eklentinin hangi kancaya ne kadar işlem eklediğini anlamak, e-ticaret performans optimizasyonunun temel adımlarından biridir; bu analiz yapılmadan hangi eklentinin kaldırılabileceğini ya da değiştirilebileceğini söylemek güçtür.
AJAX tabanlı mini sepet ve sepet güncellemeleri kullanıcı deneyimini algısal olarak iyileştirmenin en hızlı yoludur. Sayfa tam yüklenmeden önce kullanıcının içeriği görmesi, ölçülen TTFB değişmese bile algılanan hızı artırır. TTFB ile FCP arasındaki ilişkiyi anlamak bu yaklaşımın neden işe yaradığını açıklar; sunucu yanıtı yavaş olsa da tarayıcının ekranda bir şey göstermesi kullanıcının bekleme algısını kırar.
Sepet sayfası yavaşlığı, WooCommerce'in mimarisinden kaynaklanan ve tamamen ortadan kaldırılamayan bir kısıttır. Yapılabilecek, bu kısıtı kabul edip o sınırlar içinde mümkün olan en iyi performansı elde etmektir. Oturum tablosu bakımı, PHP yapılandırması, gereksiz eklenti yükünün azaltılması ve nesne önbelleğiyle dolaylı optimizasyon bu kapsamın içindedir.
Bir mağazanın sepet sayfası için gerçekçi beklenti şudur: statik sayfa hızına asla ulaşamaz. Kullanıcının fark edeceği kadar yavaş olması ise şart değildir. İki ile üç saniyelik bir TTFB ile 400 milisaniyelik bir TTFB arasındaki fark hem ölçülebilir hem de kullanıcı davranışlarını etkiler; bu fark çoğunlukla altyapı ve yapılandırma tercihlerinden doğar.
Düzenli hız takibi yaparken sepet sayfasını ayrı bir URL olarak izlemek, diğer sayfaların iyileşmesinin sepeti de otomatik iyileştirdiği yanılgısını önler. Sepet sayfası kendi başına bir ölçüm kalemi olarak takip edildiğinde, yapılan her müdahalenin gerçek etkisi net biçimde görülür ve gelecekteki sorunlar erken fark edilir.