HTTP/2 ve HTTP/3'ün Görsel Yükleme Stratejisini Nasıl Değiştirdiği
HTTP/1.1, on yılı aşkın süre boyunca webin tek taşıma protokolü olarak kaldı. Bu sürede geliştiriciler, protokolün kısıtlamalarını aşmak için bir dizi pratik ama garip çözüm ürettiler: CSS sprite'lar, domain sharding, inline base64 görseller. Yıllarca en iyi uygulama kabul edilen bu yöntemler, HTTP/2 ve ardından HTTP/3'ün yaygınlaşmasıyla birlikte işe yaramaz değil, aktif olarak zararlı hale geldi.
Değişim yalnızca protokol sürüm numarasından ibaret değil. Taşıma katmanı köklü biçimde yeniden yazıldı. Yeni protokollerin görsel yüklemeyle ilgisi tam da bu noktada başlar: protokol, her görsel isteğini artık farklı bir maliyet yapısıyla değerlendiriyor ve HTTP/1.1 döneminde yapılan optimizasyonların büyük kısmı bu yeni yapıda tersine çalışıyor.
Hangi optimizasyonların geçerliliğini koruduğunu anlamak için önce HTTP/1.1'in ne tür kısıtlamalar yarattığını, ardından multiplexing'in bu kısıtlamayı nasıl tarihe gömdüğünü görmek gerekiyor.
HTTP/1.1 döneminde neden bu kadar çok geçici çözüme başvuruluyordu
HTTP/1.1, bir TCP bağlantısı üzerinden tek seferde yalnızca bir istek işleyebildi. Tarayıcılar bu sorunu aynı anda birden fazla bağlantı açarak çözdü; ancak belirli bir alan adına yönelik eş zamanlı bağlantı sayısı çoğu tarayıcıda 6 ile sınırlıydı.
Bir sayfa 30 görsel yüklüyorsa ve tarayıcı aynı anda yalnızca 6 bağlantı kullanabiliyorsa, görseller sıraya girmek zorundaydı. Sıraya giren her görsel, önceki isteğin tamamlanmasını bekledi. Her bağlantı kendi TCP el sıkışmasını, varsa TLS müzakeresini ve istek başlıklarını taşıdı; toplam gecikme görsel sayısıyla doğrusal biçimde büyüdü.
Geliştiricilerin bulduğu çözümler bu kısıtlamayı doğrudan hedef aldı. CSS sprite, onlarca küçük görsel isteğini tek bir büyük dosyaya indirdi. Domain sharding, cdn1.example.com ve cdn2.example.com gibi farklı alt alanlar açarak tarayıcının eş zamanlı bağlantı limitini iki katına çıkardı. Inline base64, görsel isteğini tamamen ortadan kaldırdı; görsel HTML veya CSS içine gömüldü. Her üç çözüm de HTTP/1.1'in bağlantı başına bir istek kısıtlamasına verilen yanıttı; protokol değişince bu yanıtların mantığı da çöktü.
Multiplexing nedir ve bağlantı maliyetini nasıl ortadan kaldırır
HTTP/2'nin getirdiği en önemli değişiklik multiplexing'dir. Tek bir TCP bağlantısı üzerinden onlarca istek eş zamanlı olarak gidip gelebilir. Her istek bir "akış" (stream) kimliğiyle etiketlenir, yanıtlar paralel ilerler ve sıralama zorunluluğu ortadan kalkar.
Pratik sonuç basittir: 30 görsel isteği artık sıra beklemez.
HTTP/2 aynı zamanda başlık sıkıştırması (HPACK) getirir. HTTP/1.1'de her istek kendi başlık setini düz metin olarak taşıdı; aynı User-Agent, Accept ve Cookie başlıkları her görsel isteğinde tekrar gönderildi. HPACK, tekrar eden başlıkları hafızaya alır ve yalnızca değişen kısımları iletir; çok sayıda görsel içeren sayfada bu sıkıştırma, HTTP başlık yükünü belirgin biçimde azaltır.
HTTP/3 bir adım daha atar ve TCP yerine QUIC protokolünü kullanır. QUIC, UDP üzerine inşa edilmiş, kendi güvenilirlik katmanını içeren bir protokoldür. HTTP/2'de multiplexing uygulama katmanında vardı ama TCP'nin doğası gereği tek bir paket kaybı tüm akışları durdurabiliyordu; bu soruna "head-of-line blocking" (satır başı engelleme) denir. QUIC, her akışı bağımsız biçimde ele alır: bir akıştaki kayıp paket yalnızca o akışı etkiler, diğerleri akmaya devam eder.
Sprite ve domain sharding: eski çözümlerin yeni ortamda yaptığı zarar
HTTP/2 ortamında CSS sprite ve domain sharding yalnızca gereksiz değil, performansı bozar.
CSS sprite bir sayfadaki 40 küçük ikonu tek bir büyük PNG içinde taşır. HTTP/1.1'de bu mantıklıydı; 40 ayrı istek yerine 1 istek yeterliydi. HTTP/2'de bu hesap tersine döner: multiplexing'le birlikte 40 küçük istek tek bağlantı üzerinden eş zamanlı çalışır, sprite için gereksiz veri yüklenmez, tarayıcı önbelleği bireysel görsellere ayrı çalışır ve bir ikonu değiştirmek için tüm sprite'ı geçersiz kılmak zorunda kalınmaz. Sprite mantığını sürdürmek ise her yeni ikon için editöre gitmeyi, koordinatları güncellemeyi ve CSS'i düzenlemeyi gerektirdiğinden geliştirme yükünü de artırır.
Domain sharding daha doğrudan zarar verir. Her alt alan adı ayrı bir DNS sorgusu, ayrı bir TCP bağlantısı ve ayrı bir TLS el sıkışması gerektirir. HTTP/2'de tüm bu yük gereksizdir, çünkü tek bağlantı her şeyi taşır. İki farklı alt alan kullanıldığında tarayıcı ayrı HTTP/2 bağlantıları kurmak zorunda kalır; bu durum multiplexing'in faydalarını azaltır. Aynı kaynak (origin) üzerindeki istekler tek bir bağlantıda toplanabildiğinde, alt alanlar bu birleşmeyi önler.
Inline base64 da benzer bir hesapla çalışır. HTTP/1.1'de bir isteği ortadan kaldırmak kazanımdı; HTTP/2'de isteğin maliyeti düştüğünden base64'ün ek boyutu (yaklaşık yüzde 33 şişkinlik) ve önbellek dışı kalma sorunu öne çıkar. Base64 ile kodlanmış bir görsel, görseli içeren HTML veya CSS dosyasının önbelleğine bağlıdır; görsel değişmese bile CSS değişince yeniden indirilir.
HTTP/2 ile görsel yükleme önceliklendirilmesi
HTTP/2 her akışa bir öncelik ağırlığı atanmasına izin verir. Sayfa üzerindeki ilk katlamadaki görseller yüksek öncelikle işaretlenebilir, görünür alanın dışındaki görseller düşük öncelikle ertelenebilir. Tarayıcılar bu önceliklendirmeyi kendi iç mantıklarına göre otomatik yapar; fetchpriority HTML özelliği ise geliştiricinin bu kararı açıkça bildirmesine olanak tanır.
Yükleme sırası HTTP/1.1'e kıyasla daha esnek hale gelir; ama esneklik, kendi sorunlarını da getirir. Çok sayıda görsel aynı anda yüksek öncelikli olarak işaretlendiğinde önceliklendirme anlamsızlaşır ve sıra bekleme fiilen geri döner. Önceliklendirmeyi anlamlı kılan şey, gerçekten kritik olan görselleri geri kalanlardan ayırt etmektir.
LCP (Largest Contentful Paint) görseli için fetchpriority="high" ve loading="eager" kombinasyonu, hero görselini hızlı yüklemek için tutarlı bir yöntemdir. Diğer görseller loading="lazy" ile erteleyin. HTTP/2, bu iki uç arasındaki farkı HTTP/1.1'den daha net çizer; sıra beklemesi olmadığı için kaynaklar gerçekten paralel iner ve lazy ile eager arasındaki ayrım daha belirleyici olur.
HTTP/3 ve QUIC: kayıp paket sorununu kökten çözmek
HTTP/2, TCP üzerinde çalıştığı için head-of-line blocking sorununu tam çözemedi. Multiplexing uygulama katmanında vardı, ama paket kaybı TCP katmanında tüm akışları etkiledi. Mobil ağlarda veya zayıf bağlantılarda bu sorun, görsel yoğun sayfaların takılmasına neden olabilir.
QUIC her akışı bağımsız olarak izler. Bir görsel isteğindeki paket kaybı diğer akışları bekletmez. Bağlantı kurma süresi de kısalır: QUIC'in 0-RTT (sıfır gidiş-dönüş) yeniden bağlantı desteği, önceki bağlantıdan kriptografik bağlamı hatırlayarak TLS el sıkışmasını atlar ve özellikle tekrar ziyaret eden kullanıcılarda ilk bayt süresi (TTFB) düşer.
Kötü ağ koşullarında HTTP/3'ün farkı en belirgin hale gelir. Stabil bir bağlantıda HTTP/2 ile HTTP/3 arasındaki fark küçük kalabilir; ama yüksek paket kaybı olan ortamlarda QUIC'in akış bağımsızlığı görsellerin çok daha dengeli yüklenmesini sağlar. Büyük CDN sağlayıcılarının çoğunda HTTP/3 desteği artık varsayılan ya da tek satır yapılandırmayla açılabilen bir seçenek konumundadır; tarayıcı desteği de ana akım hale gelmiştir.
Sunucu push'un vaadi ve yerini alan mekanizma
HTTP/2'nin tanıtımında sunucu push (server push) büyük ilgi gördü. Tarayıcı henüz HTML'i ayrıştırmadan önce sunucu, görselleri ve diğer kaynakları push'layabilecekti; böylece her kaynak için istek-yanıt döngüsünü beklemek gerekmeyecekti.
Pratikte push, görsel yükleme için beklenen faydayı sağlamadı.
Sorun birkaç yerden geldi: tarayıcılar push'lanan kaynakları zaten önbellekte tutup tutmadıklarını sunucuya bildirmiyordu, sunucu gerekmediği halde dosyaları tekrar gönderdi, push'lanan kaynaklar bazen tarayıcının önceliklendirme kararlarını bozdu. Chrome 2022'de HTTP/2 sunucu push desteğini devre dışı bıraktı; HTTP/3 üzerinden push ise zaten sınırlı kullanımdaydı.
Günümüzde push'un pratik alternatifi 103 Early Hints yanıt kodudur. Sunucu, 200 yanıtından önce hangi kaynakların yükleneceğini bildirir; tarayıcı bu ipucuyla önceden bağlantı kurabilir ya da kaynakları erken isteyebilir. Hero görseli veya kritik CSS için rel="preload" bağlantısını 103 yanıtında bildirmek, push'ın karmaşıklığı olmadan erken yükleme avantajı sağlar.
Yeni protokollerle örtüşen görsel yükleme yaklaşımı
HTTP/2 ve HTTP/3'ün gerçekten kullanıldığı bir ortamda görsel stratejisi şu ilkeler üzerine oturur:
- Sprite birleştirme yerine bireysel görsel dosyaları kullanın. Eğer ikon birleştirmesi gerekiyorsa SVG sprite tercih edin; SVG sprite CSS koordinat bağımlılığı taşımaz, tarayıcı önbelleğiyle daha temiz çalışır ve HTTP/2 ortamında ayrı dosya maliyeti neredeyse yoktur.
- Domain sharding'i kaldırın. Tüm görselleri mümkünse aynı kaynak veya tek bir CDN alan adı üzerinden sunun; birden fazla alt alan yalnızca HTTP/1.1 bağlantı limitini aşmaya yarardı, HTTP/2'de tam tersine multiplexing verimliliğini bozar.
- LCP görseli için
fetchpriority="high"verel="preload"kullanın. Bu iki özellik tarayıcının kritik görseli erken keşfetmesini sağlar ve HTTP/2'nin paralel akış kapasitesinden doğru kaynaklar yararlanır. - Ekran dışı görselleri
loading="lazy"ile erteleyin. HTTP/2 ortamında kapasite yeterli olsa da bant genişliği sınırlıdır; erteleme, bant genişliğini öncelikli kaynaklara yönlendirmeye devam eder. - Base64 inline görselleri yalnızca çok küçük ikonlar için değerlendirin ve genel kural olarak bundan da kaçının. HTTP/2'de istek maliyeti düşük, önbellek dışı kalma maliyeti yüksektir.
Görsel boyutu, format seçimi (WebP, AVIF) ve sıkıştırma kalitesi protokolden bağımsız geçerliliğini korur. HTTP/2'nin getirdiği bağlantı verimliliği, 500 KB'lık bir görseli küçültmez; küçük ve doğru formatta görsel sunmak, iyi protokol yapılandırmasıyla çalışan ayrı bir optimizasyon katmanıdır.
Bir siteyi HTTP/2 veya HTTP/3'e taşırken önce sunucu yapılandırmasını, ardından CDN ayarlarını doğrulayın. Protokol aktif olduğunda sprite ve sharding alışkanlıklarından vazgeçmek hem kod tabanını sadeleştirir hem de yükleme süresini iyileştirir. HTTP/1.1 döneminin karmaşık geçici çözümleri temizlendiğinde yeni protokollerin sağladığı paralel yükleme kapasitesi tam anlamıyla devreye girer.