Oğuzhan KARAGÜZEL

OĞUZHAN KARAGÜZEL

Yazılım geliştirici

Web Sitesi Hızı ve Core Web Vitals: ASP.NET Optimizasyonu

Yazar: Oğuzhan KARAGÜZEL ·

SEO serisinin son bölümünde web sitesi hızını ele alıyoruz. Önceki bölümler: sayfa içi SEO, teknik SEO ve Open Graph, yapılandırılmış veri ve ARIA. Bu yazıdaki öneriler ASP.NET Core, HTML, CSS ve JavaScript ile çalışan geliştiriciler düşünülerek hazırlandı; kendi mimarinize ve kullandığınız framework'e göre uyarlamanız gerekebilir.

Neden Hız? Core Web Vitals

Web sitesi hızı; kullanıcı deneyimini, SEO'yu ve dönüşüm oranlarını doğrudan etkileyen kritik bir faktördür. Yavaş açılan bir site ziyaretçinin siteyi terk etmesine, dolayısıyla işletmenin potansiyel müşteri kaybetmesine yol açar.

Google, hızı ve kullanıcı deneyimini Core Web Vitals adı verilen üç ölçümle değerlendirir:

  • LCP (Largest Contentful Paint): En büyük içerik öğesinin (genellikle ana görsel ya da başlık) görünme süresi. İyi değer 2,5 saniye veya altıdır.
  • INP (Interaction to Next Paint): Sayfanın kullanıcı etkileşimlerine verdiği yanıt süresi (eski FID ölçümünün yerini aldı). İyi değer 200 ms veya altıdır.
  • CLS (Cumulative Layout Shift): Sayfa yüklenirken öğelerin yer değiştirmesi. İyi değer 0,1 veya altıdır.

Aşağıdaki başlıkların neredeyse tamamı bu üç ölçümden birini iyileştirmeye hizmet eder. Örneğin görsel optimizasyonu LCP'yi, script erteleme INP'yi, görsellere genişlik ve yükseklik vermek CLS'yi düzeltir.

Sunucu ve Altyapı Optimizasyonu

Sitenin hızı büyük ölçüde sunucunun hızına ve yapılandırmasına bağlıdır.

  • Yük dengeleme (load balancing): Yüksek trafikli sitelerde yükü birden fazla sunucuya dağıtın.
  • CDN: Statik içerikleri (CSS, JS, görseller) kullanıcıya yakın sunuculardan sunarak gecikmeyi azaltın.
  • HTTP/2 ve HTTP/3: Sunucunuzun bu protokolleri desteklediğinden emin olun ve kullanıma alın; tek bağlantı üzerinden çoklu istek ve daha verimli aktarım sağlarlar.
  • Sıkıştırma: Yanıtları Gzip ya da Brotli ile sıkıştırın.
  • Ortam yönetimi: ASP.NET'te Development ve Production ortamlarını doğru kullanın. launchSettings.json ile geliştirmeyi istediğiniz ortamda test edebilir, canlıya çıkarken yapılandırma karmaşasını ve beklenmedik ezilmeleri önleyebilirsiniz.

ASP.NET Core'da yanıt sıkıştırmayı açmak için:

C#
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

var app = builder.Build();

app.UseResponseCompression();

ASP.NET Core Performans İyileştirmeleri

  • Asenkron programlama: Veritabanı, dosya ve ağ işlemlerinde async/await kullanın; thread'ler beklemek yerine başka isteklere hizmet verir ve ölçeklenebilirlik artar.
  • EF Core'da gereksiz veri çekmeyin: N+1 sorgu sorununa karşı ilişkili veriyi Include ile (eager loading) tek sorguda alın ve her sayfa için yalnızca o sayfayı ilgilendiren alanları çekin.
  • Salt okunur sorgularda change tracker'ı kapatın: AsNoTracking() bellek kullanımını ve sorgu süresini azaltır.
  • Sayfa bazında soyutlama: CQRS benzeri bir yaklaşım, her sayfanın kendi sorgusunu ve modelini taşımasını sağlar. Daha fazla dosya ve sınıf anlamına gelir, ancak hata ayıklamayı ve optimizasyonu kolaylaştırır. Benim de sık kullandığım bir yaklaşım; ama her proje için zorunlu değildir.
C#
public async Task<List<ArticleListItemDto>> GetLatestArticlesAsync(CancellationToken ct)
{
    return await _db.Articles
        .AsNoTracking()                          // değişiklik takibi yok
        .Where(a => a.IsPublished)
        .OrderByDescending(a => a.PublishedAt)
        .Select(a => new ArticleListItemDto      // yalnızca gereken alanlar
        {
            Title = a.Title,
            Slug = a.Slug,
            AuthorName = a.Author.Name           // join tek sorguda
        })
        .Take(10)
        .ToListAsync(ct);
}

Veritabanı Optimizasyonu

Veritabanı sorguları uygulamanın performansını büyük ölçüde belirler.

  • Sorgu optimizasyonu: Gereksiz sorguları kaldırın, yalnızca ihtiyacınız olan kolonları çekin.
  • İndeksleme: Sık filtrelenen ve sıralanan kolonlara uygun indeksler ekleyin.
  • Önbellekleme: Sık okunan ve nadiren değişen verileri her istekte veritabanından çekmek yerine önbelleğe alın.
  • Doğru veritabanı seçimi: Seçimi hız değil, veri modeli ve kullanım belirler. Tek sunucuda çalışan küçük bir site için SQLite yeterli olabilir; eşzamanlı yazma ve kullanıcı sayısı arttıkça PostgreSQL ya da SQL Server gibi sunucu tabanlı veritabanları gerekir. MongoDB gibi belge tabanlı veritabanları ise verisi gerçekten belge yapısında olan uygulamalar için anlamlıdır; tek başına bir hız çözümü değildir.

İndekslerin nasıl çalıştığını SQL Server İndeksleri: Clustered, Non-Clustered ve B-Tree yazısında, EF Core sorgularını hafifletmenin yollarını da EF Core Sorgu Performansı yazısında ayrıntılı anlatıyorum.

HTML, CSS ve JavaScript Optimizasyonu

İyi yapılandırılmış ve küçültülmüş ön yüz kodu sayfa yükleme süresini belirgin biçimde azaltır.

  • Minify ve compress: HTML, CSS ve JS dosyalarını küçültün ve Gzip ya da Brotli ile sıkıştırın.
  • Birleştirme: Birden fazla CSS ve JS dosyasını birleştirmek istek sayısını azaltır. HTTP/2 ve HTTP/3 altında bu kazanç eskisi kadar büyük değildir, ancak makul sayıda dosya hâlâ iyi bir pratiktir.
  • Kritik CSS: İlk görünümü oluşturan CSS'i HTML içine gömün, kalan CSS'i ertelenmiş yükleyin.
  • Script'leri statik dosyada tutun: View içine yazılan stil ve script kodu her sayfa isteğinde yeniden gönderilir ve tarayıcı tarafından önbelleğe alınamaz. Bu kodu statik dosyalara taşıyıp script ve link etiketleriyle referans verdiğinizde tarayıcı dosyayı bir kez indirir ve sonraki sayfalarda önbellekten kullanır. Ortak kodu modüllere ayırıp export / import ile paylaşarak kod tekrarını da azaltırsınız.
  • Az ve temiz HTML: Gereksiz sarmalayıcı etiketlerden kaçının. SEO araçlarında sık görülen "metin/HTML oranı" Google'ın kullandığı bir ölçüt değildir; ama sade HTML hem sayfayı küçültür hem de tarayıcının işini hızlandırır.
  • Animasyonları CSS ile yapın, JS'i en aza indirin: CSS animasyonları ve geçişleri hem daha hafiftir hem de ana iş parçacığını daha az meşgul eder.
  • CSS değişkenleri kullanın: Renk, yazı boyutu gibi sabit değerleri bir kez tanımlayıp her yerde yeniden kullanarak kod tekrarından kaçının.
CSS
:root {
  --primary-color: #3498db;
  --secondary-color: #2ecc71;
  --font-size: 16px;
}

body {
  font-size: var(--font-size);
  color: var(--primary-color);
}

h1 {
  color: var(--secondary-color);
}

Not: Değişkenleri ayrı bir dosyada tutuyorsanız onu CSS içinde @import ile çağırmak yerine HTML'de ayrı bir <link> etiketiyle yükleyin ya da dosyaları derleme aşamasında birleştirin. @import tarayıcının dosyaları sırayla indirmesine yol açar ve yüklemeyi yavaşlatır.

Fontları, kapak görsellerini ve dış alan adlarına bağlantıyı öne almak için kullanılan preload, preconnect ve fetchpriority gibi ipuçlarını Kaynak İpuçları yazısında bulabilirsiniz.

Async ve Defer ile Script Yükleme

JavaScript dosyaları sayfanın işlenmesini engelleyebilir. İki seçenek vardır:

  • defer: Script arka planda indirilir ve HTML işlendikten sonra, sayfadaki sıraya uygun şekilde çalışır. Çoğu senaryoda en güvenli ve öngörülebilir seçenektir.
  • async: Script indirilir indirilmez, sıradan bağımsız olarak çalışır. Birbirine bağımlı olmayan bağımsız script'ler (örneğin analitik) için uygundur.
HTML
<head>
  <!-- Küçültülmüş CSS -->
  <link rel="stylesheet" href="/css/styles.min.css">

  <!-- Sıra önemliyse defer -->
  <script src="/js/script.js" defer></script>

  <!-- Bağımsız script için async -->
  <script src="/js/analytics.js" async></script>
</head>

Görsel Optimizasyonu

Görseller genellikle bir sayfanın en büyük ve en yavaş yüklenen parçalarıdır; LCP'yi en çok etkileyen öğe de çoğu zaman bir görseldir.

  • Sıkıştırma: Görselleri TinyPNG, JPEGoptim gibi araçlarla ya da derleme/yükleme aşamasında otomatik olarak sıkıştırın.
  • Modern formatlar: WebP ve AVIF, JPEG ve PNG'ye göre belirgin biçimde daha küçük dosyalar sunar.
  • Responsive görseller: Farklı ekran genişlikleri için farklı boyutlarda görsel sunun.
  • Lazy loading: Ekranın dışındaki görselleri yalnızca gerektiğinde yükleyin. Ancak sayfanın ilk görünümündeki ana görsele (LCP öğesi) lazy loading uygulamayın; ona öncelik verin.
  • Boyutlar: Görsellere width ve height verin; böylece yüklenirken sayfa kaymaz (CLS).
HTML
<!-- Responsive ve lazy loading (sayfa altındaki görsel) -->
<img src="image-800.jpg"
     srcset="image-400.jpg 400w, image-800.jpg 800w"
     sizes="(max-width: 600px) 400px, 800px"
     width="800" height="450"
     loading="lazy"
     alt="Responsive görsel örneği">

<!-- Sayfanın ana görseli: lazy değil, yüksek öncelik -->
<img src="hero.jpg" width="1200" height="630" fetchpriority="high" alt="Ana görsel">

Önbellekleme Stratejileri

Önbellekleme, sayfa yükleme süresini ve sunucu yükünü önemli ölçüde azaltır. İki düzeyde düşünülmelidir.

Tarayıcı Önbelleği

CSS, JS ve görseller gibi statik dosyalar için uzun süreli önbellek başlıkları ayarlanmalıdır. Bunu yaparken dosya adına sürüm bilgisi eklemek (cache busting) önemlidir; böylece dosya değiştiğinde kullanıcı yeni sürümü alır. ASP.NET Core'da statik dosyalar için:

C#
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        // 1 yıl; dosya adları sürümlüyse (ör. site.css?v=hash) güvenlidir
        ctx.Context.Response.Headers.CacheControl = "public,max-age=31536000,immutable";
    }
});

Razor görünümlerinde asp-append-version="true" özelliği, dosya içeriğine göre otomatik bir sürüm parametresi ekler. IIS üzerinde barındırılan bir projede aynı ayar web.config ile de yapılabilir:

XML
<configuration>
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
    </staticContent>
  </system.webServer>
</configuration>

Dikkat: httpProtocol/customHeaders ile tüm yanıtlara Cache-Control: public, max-age=31536000 eklemek, dinamik HTML sayfalarını da bir yıl önbelleğe aldırabilir. Bu başlığı yalnızca statik dosyalara uygulayın.

Sunucu Tarafı Önbellek

Değişmeyen ya da çok az değişen sayfalar için sunucu tarafında önbellek kullanın. Veri düzeyinde Redis gibi dağıtık bir önbellek, sayfa düzeyinde ise ASP.NET Core'un Output Caching özelliği tercih edilebilir:

C#
// Program.cs
builder.Services.AddOutputCache();
// ...
app.UseOutputCache();

// Controller
[OutputCache(Duration = 60)]
public IActionResult Index()
{
    return View();
}

Ölçüm ve Test Araçları

Ölçmediğiniz şeyi iyileştiremezsiniz. Sık kullanılan araçlar:

  • Google PageSpeed Insights: Sayfayı analiz eder, Core Web Vitals sonuçlarını ve iyileştirme önerilerini verir.
  • GTmetrix: Sayfa hızını ayrıntılı raporlarla analiz eder.
  • WebPageTest: Sayfayı farklı lokasyonlardan ve cihazlardan test eder.
  • Lighthouse ve Search Console: Lighthouse tarayıcıda yerel ölçüm yapar; Search Console'un Core Web Vitals raporu ise gerçek kullanıcı verisini gösterir.

Hız Kontrol Listesi

  1. Yanıt sıkıştırma (Brotli/Gzip) açık mı, HTTP/2 veya HTTP/3 kullanılıyor mu?
  2. Statik dosyalar CDN ve uzun süreli önbellek başlıklarıyla sunuluyor mu, dosya adları sürümlü mü?
  3. Veritabanı işlemleri asenkron mu, EF sorgularında gereksiz veri ve N+1 sorunu var mı?
  4. CSS ve JS küçültülmüş, script'ler defer ya da async ile yükleniyor mu?
  5. Görseller sıkıştırılmış, WebP/AVIF ve srcset ile sunuluyor, boyutları tanımlı mı?
  6. Ana görsel (LCP) lazy yüklenmiyor ve öncelikli mi?
  7. Sık okunan, az değişen veriler ve sayfalar önbellekte mi?
  8. PageSpeed Insights ve Search Console'da Core Web Vitals değerleri "iyi" aralığında mı?

Böylece dört bölümlük SEO serisini tamamlamış olduk. Seriye ilk bölümden yeniden göz atabilirsiniz.