Sunucu Mimarisi ve Performans
Reverse Proxy Performansı Nasıl Etkiler?
Reverse proxy ile performans arasındaki ilişki genellikle tek yönlü anlatılır: "Nginx ekle, her şey hızlanır." Gerçek tablo daha nüanslı. Doğru yapılandırılmış bir reverse proxy SSL yükünü origin'den alır, yanıtları sıkıştırır, statik dosyaları doğrudan sunar ve upstream bağlantılarını havuzda tutarak yeniden kullanır. Aynı proxy, yanlış yapılandırıldığında her isteğe ekstra gecikme katar, upstream zaman aşımlarını kötü yönetir ya da beklenmedik noktalarda veri akışını keser.
Sorun şu: proxy katmanı çoğu izleme aracının radarında pek görünmez. TTFB ölçümleri toplam gecikmeyi gösterir, ama proxy'nin bu toplamın içinde kaç milisaniye tuttuğunu ayırt etmez. Bu yüzden yavaşlamanın gerçekte nerede başladığını anlamadan yapılan optimizasyon girişimleri çoğunlukla yanlış katmanı hedef alır.
Proxy'nin performansa katkısını ve risklerini anlamak için önce proxy'nin gerçekte ne yaptığını netleştirmek gerekir. Ardından her işlevin nasıl ölçüldüğü ve nerede yanlış gidebileceği ele alınabilir.
Reverse proxy'nin gerçek rolü
Reverse proxy, istemci ile asıl uygulama sunucusu arasına giren bir ara katmandır. İstemci isteği doğrudan origin'e değil proxy'ye gider; proxy bu isteği kendi kurallarına göre işler ve uygun upstream'e yönlendirir. Bu mimaride proxy; SSL sonlandırma, sıkıştırma, yük dağıtımı, önbellekleme ve erişim kontrolü gibi görevleri üstlenebilir. Nginx, HAProxy, Caddy ve Varnish bu rolü üstlenen yaygın araçlardır. Her biri biraz farklı bir odak noktasına sahiptir: HAProxy genellikle yük dengeleme için tercih edilirken Varnish önbellekleme ağırlıklı çalışır.
Proxy'nin performansa katkısı tam bu sorumluluk dağılımından gelir. Origin sunucusu SSL el sıkışması yapmak zorunda kalmaz. Sıkıştırma işlemini uygulama kodu üstlenmez. Statik dosyalar için disk erişimi doğrudan proxy katmanından karşılanabilir. Ancak bu avantajlar yalnızca doğru yapılandırıldığında gerçekleşir; proxy'yi kurup varsayılan ayarlarla bırakmak çoğu kazanımı masada bırakır.
SSL sonlandırma ve origin'e kalan yük
HTTPS bağlantısının kurulması için TLS el sıkışması gerekir. Bu süreç asimetrik kriptografi kullandığından CPU ağırlıklıdır. Reverse proxy SSL'yi kendi üzerinde sonlandırırsa origin sunucuya yalnızca şifresiz HTTP trafiği gider; TLS işlemi proxy'de kalır. Böylece origin, her gelen bağlantı için ayrı TLS handshake maliyeti ödemez.
Pratik fark, yoğun trafikli sistemlerde belirginleşir. Saatte yüz binlerce istek alan bir yapıda origin'in her bağlantı için TLS işlemesi CPU basıncını artırır ve yanıt sürelerini uzatır. Proxy üzerinde SSL sonlandırma yapıldığında origin CPU kapasitesinin tamamı uygulama mantığı için kullanılabilir. TLS 1.3'ün yaygınlaşmasıyla handshake süresi kısaldı, ancak yüksek eşzamanlılıkta kriptografik işlem maliyeti hâlâ ölçülebilir düzeyde kalır.
Sıkıştırma: proxy seviyesinde mi, origin'de mi?
Gzip ya da Brotli sıkıştırma hem origin hem de proxy seviyesinde yapılandırılabilir. İkisi birden aktifse yanıt çift sıkıştırmaya maruz kalır; bu hem boyutu artırır hem de gereksiz CPU tüketir. Proxy katmanında merkezi sıkıştırma yapıldığında origin bu işten muaf tutulur, ancak proxy CPU'su bu kez sıkıştırma yükünü taşır.
Proxy üzerinde sıkıştırmanın avantajı, farklı origin'lerden gelen yanıtları tutarlı biçimde işleyebilmesidir. Bir origin sıkıştırmayı uygularken diğeri uygulamıyorsa proxy katmanında bu tutarsızlık giderilebilir. Gzip ve Brotli sıkıştırma rehberinde detaylı ele alındığı gibi, proxy seviyesindeki merkezi yapılandırma hem bakım hem tutarlılık açısından avantajlıdır. Burada dikkat edilmesi gereken tek nokta, proxy'nin upstream'den gelen zaten sıkıştırılmış yanıtı yeniden sıkıştırmaya kalkmamasıdır; gzip_proxied ve benzeri direktifler bu davranışı kontrol eder.
Upstream bağlantı havuzu yönetimi
Her yeni istek için sıfırdan TCP bağlantısı kurmak maliyetlidir. Proxy, upstream'e giden bağlantıları havuzda tutarak bu maliyeti ortadan kaldırır: bir istek tamamlandığında bağlantı kapatılmaz, bir sonraki istek için hazır bekler. Bu mekanizma, özellikle TLS bağlantı kurulum süresini tekrar tekrar ödemekten kaçınmak açısından değerlidir.
Nginx'te keepalive direktifi upstream bağlantıları için bu havuzu yönetir. Varsayılan değerler genellikle düşük tutulduğundan yüksek trafikli yapılar bu ayarı bilinçli olarak artırır. Havuz boyutu çok küçük ayarlandığında proxy yeni bağlantı açmaya devam eder; çok büyük tutulduğunda boşta bağlantılar origin üzerinde gereksiz kaynak tüketir. Doğru denge, gerçek trafik desenine bakılarak kurulur; teorik maksimumdan değil, çakışan eşzamanlı istek sayısından yola çıkmak gerekir.
Statik dosya sunumu ve origin bypass
Nginx gibi araçlar, statik dosyaları doğrudan dosya sisteminden sunmada son derece verimlidir. CSS, JavaScript, görsel ve font dosyaları proxy'nin kendi disk erişimiyle karşılanabilir; bu istekler hiç upstream'e ulaşmaz. Origin sunucu bu yükten tamamen muaf kalır.
Bu yaklaşımın asıl değeri, origin üzerindeki eşzamanlı bağlantı sayısını düşürmesidir. Bir sayfa yüklenmesi sırasında tarayıcı onlarca paralel istek açar. Bu isteklerin büyük bölümü statikse proxy hepsini kendi üzerinden karşılar; origin yalnızca HTML veya API yanıtı gibi dinamik içerikleri üretmekle sorumlu olur. Büyük görsellerin proxy üzerinden sunulduğu yapılarda origin CPU ve bant genişliği tüketimi ciddi biçimde düşer. Statik varlıklar için expires veya Cache-Control başlıklarının da proxy'de doğru ayarlanması, tekrarlayan isteklerin tarayıcı cache'inden karşılanmasını sağlar.
Load balancing ve yanıt süresi dağılımı
Birden fazla upstream sunucu varsa proxy hangi isteği nereye göndereceğine karar verir. Round-robin, least connections ve IP hash en yaygın stratejilerdir. Bu noktada önemli olan, proxy'nin yalnızca istekleri dağıtmadığıdır; yanıt süresi dağılımını da doğrudan etkiler.
Least connections stratejisi, o an en az aktif bağlantıya sahip upstream'i seçer. Yavaş bir upstream varsa istekler birikmeye başlar; proxy bu durumu fark ederek yüklü sunucuya daha az istek gönderir. Ancak proxy'nin sağlıklı ve sağlıksız upstream'i ayırt edebilmesi için health check yapılandırması doğru kurulmuş olmalıdır. Pasif health check başarısız yanıtları sayarak upstream'i geçici olarak devre dışı bırakır; aktif health check ise periyodik olarak belirli bir URL'yi test eder. İkisi birlikte kullanıldığında yavaş upstream'in yük dağılımını bozması daha hızlı tespit edilir.
Proxy katmanının TTFB'ye katkısı
Proxy'nin her isteğe kattığı süre genellikle birkaç milisaniye ile onlarca milisaniye arasındadır. Bu aralık yapılandırmaya ve sunucu donanımına göre değişir. İstek proxy'ye ulaştığında proxy onu işler, uygun upstream'e yönlendirir, yanıtı alır ve istemciye iletir. Her adımda küçük bir gecikme birikir.
Normal koşullarda bu gecikme ihmal edilebilir düzeyde kalır. Sorun, proxy'nin upstream'e bağlantı açarken geciktiği ya da upstream'den yanıt beklerken timeout yapılandırmasının gevşek tutulduğu durumlarda ortaya çıkar. Sunucu yanıt süresinin katmanları incelendiğinde proxy tipik olarak 5–15 ms arasında bir ek süre ekler; bu oran sorunsuz bir yapıda kabul edilebilirdir. Ancak aynı proxy birden fazla middleware, kimlik doğrulama kontrolü ya da ek log işlemi çalıştırıyorsa bu süre artabilir.
Buffer ve streaming: akışın kırıldığı yer
Proxy, upstream'den gelen yanıtı tamamen alıp sonra istemciye mi iletmeli, yoksa geldiği gibi mi akıtmalı? Bu seçim hem gecikmeyi hem de bellek tüketimini etkiler. Nginx varsayılan olarak yanıtı tamponlar: upstream'den gelen veri bir buffer'a yazılır, ardından istemciye gönderilir. Bu yaklaşım upstream bağlantısını hızla serbest bırakır ve yavaş istemcilerden kaynaklanan upstream bloklanmasını önler.
Ancak büyük yanıtlarda ya da yavaş istemcilerde buffer'lama sorun yaratabilir. Yavaş bir bağlantıdaki istemci buffer'ı tüketemeden proxy bellek basıncına girer. Server-Sent Events veya chunked transfer gibi streaming senaryolarında ise buffer'lama akışı geciktirir ya da tamamen bozar. proxy_buffering off direktifi bu durumlarda gerekli olabilir, ancak bu kez upstream bağlantıları daha uzun süre açık kalır ve bağlantı havuzunun boşalmasını yavaşlatır. Senaryo bazlı test yapmadan tek bir buffer stratejisi benimsemek, bazı istek tiplerine iyi gelirken diğerlerine zarar verir.
Keep-alive yapılandırması ve bağlantı maliyeti
İstemci ile proxy arasındaki bağlantı için de keep-alive kritiktir. HTTP/1.1'de tarayıcı bağlantıyı açık tutar ve aynı origin'e birden fazla istek gönderir. Proxy bu bağlantıları yönetirken keepalive_timeout değeri belirleyici rol oynar. Bu değer çok düşük ayarlandığında bağlantılar erken kapanır; tarayıcı her kaynak için yeni bağlantı açmak zorunda kalır ve her seferinde TCP handshake maliyeti ödenir.
HTTP/3 kullanıldığında istemci ile proxy arasında tek bağlantı üzerinden çoklu akış çalışır; bu, keep-alive sorununu büyük ölçüde ortadan kaldırır. Ancak proxy HTTP/2 ya da HTTP/3'ü istemci tarafında desteklerken upstream'e HTTP/1.1 ile bağlanıyorsa — ki bu yaygın bir senaryo — upstream bağlantı havuzu boyutu daha kritik hale gelir. Upstream HTTP/2'yi desteklese bile proxy'nin bu protokolü kullanabilmesi için genellikle ayrıca yapılandırılması gerekir.
Upstream timeout: çok kısa ve çok uzun arasındaki denge
Proxy, upstream'den belirli bir süre içinde yanıt alanamazsa bu isteği başarısız sayar. Bu süre çok kısa ayarlanırsa gecikmeli ama doğru yanıtlar kesilir; kullanıcı hata alır. Çok uzun ayarlanırsa yavaş upstream nedeniyle bağlantılar birikir, diğer istekler kuyruğa girer ve toplam gecikme kümülatif olarak artar.
Nginx'te proxy_connect_timeout, proxy_send_timeout ve proxy_read_timeout farklı aşamaları kontrol eder. Bağlantı timeout'u genellikle 5–10 saniye, okuma timeout'u ise uygulamanın maksimum olağan yanıt süresine göre ayarlanmalıdır. Yavaş veritabanı sorguları olan bir uygulamada okuma timeout'u çok düşük tutulursa proxy, uygulama hâlâ sorguyu işlerken bağlantıyı keser ve istemci 504 alır. Bu hata loglardan izlendiğinde upstream performans sorunlarının habercisi olduğu görülür.
Nginx, HAProxy, Varnish: proxy tipi fark yaratır mı?
Her reverse proxy'nin mimarisi biraz farklıdır ve bu fark belirli iş yüklerinde ölçülebilir sonuçlar doğurur. Nginx olay güdümlü, non-blocking bir mimari kullanır; çok sayıda eşzamanlı bağlantıyı düşük bellek tüketimiyle yönetir. HAProxy L4/L7 yük dengeleme konusunda son derece verimlidir ve health check mekanizmaları daha granülerdir. Varnish ise HTTP önbellekleme için optimize edilmiştir; VCL dili ile neredeyse her yanıt için özelleştirilmiş cache kuralı yazılabilir.
Seçim performans hedefine göre yapılmalıdır. Yalnızca statik site sunumu ve SSL sonlandırma gerekiyorsa Nginx yeterlidir. Çok sayıda backend sunucusu arasında yük dengeleme ve granüler health check gerekiyorsa HAProxy öne çıkar. Dinamik sayfaların önbelleğe alınması kritikse Varnish değerlendirilir. CDN ile yapılan önbellekleme ise Varnish'in coğrafi dağılım isteyen senaryolarda alternatifi olarak düşünülebilir; CDN kenarı benzer işlevi birden fazla PoP üzerinde sunar.
Proxy katmanını izole etmek için ölçüm yaklaşımı
Proxy'nin performansa katkısını doğru değerlendirmek için iki ölçüm noktası gerekir: istemciden proxy'ye TTFB ve proxy'den upstream'e TTFB. Fark, proxy'nin eklediği süredir. Nginx'te $upstream_response_time değişkeni, upstream'in yanıt vermesi için geçen süreyi log formatına eklenebilir. $request_time ise proxy'nin toplam işlem süresini verir. İki değer arasındaki fark proxy katkısını gösterir.
Bu loglar zaman içinde izlendiğinde pattern görünür hale gelir. Upstream response time sabitken request time artıyorsa gecikme proxy katmanındadır. Upstream response time değişkenlik gösteriyorsa sorun origin'dedir. Lighthouse skorları bu ayrımı yapamaz; log analizi veya APM araçları bu düzeyde görünürlük sağlar. Karmaşık proxy zincirlerinde sunucu taraflı tracing araçlarıyla her aşamanın süresi ayrı ayrı kayıt altına alınabilir.
Yanlış yapılandırmanın tipik görünümü
Pratikte en sık karşılaşılan sorunlar birkaç kategoride toplanır. Upstream keep-alive devre dışıysa her istek için yeni TCP bağlantısı açılır; yüksek trafikte bu port tükenmesine kadar gidebilir. Sıkıştırma hem origin hem proxy'de açıksa transfer boyutu küçülmek yerine artar. Buffer boyutları varsayılan bırakılmışsa büyük yanıtlar diske dökülerek disk I/O baskısı yaratır.
Timeout değerlerinin üretim ortamına göre ayarlanmamış olması da yaygın bir hata kaynağıdır. Geliştirme ortamından kopyalanan yapılandırmalar, production trafik desenini karşılamak için yetersiz kalır. Yük arttığında sorun kendini yavaş yanıt yerine 502 veya 504 hataları olarak gösterir. Cache-Control başlıklarının proxy düzeyinde yanlış yorumlanması da ayrı bir sorun kaynağı oluşturur; proxy'nin cache politikasıyla origin'in gönderdiği başlıklar çeliştiğinde kullanıcılar güncel olmayan içerik alabilir ya da önbelleklenmemesi gereken kişisel veriler paylaşılabilir.
Reverse proxy, doğru kurgulandığında birden fazla boyutta performans kazanımı sağlar. SSL yükünü origin'den alır, sıkıştırmayı merkezi olarak yönetir, bağlantı maliyetini havuzla eritir ve statik içerikleri origin'e uğramadan sunar. Ancak bu kazanımların hiçbiri otomatik değildir; her biri bilinçli yapılandırma kararlarına bağlıdır.
Proxy'nin gerçek etkisini görmek için upstream response time ile toplam request time'ı ayrı ayrı izlemek gerekir. Toplam TTFB'ye bakarak "proxy mu yavaşlatıyor, origin mi?" sorusunu yanıtlamak güçtür. Katman bazlı ölçüm bu soruyu yanıtlar. Yapılandırma değişiklikleri sonrasında log karşılaştırması, proxy'nin beklenen avantajı gerçekten sağladığını doğrular.
Karmaşık mimarilerde proxy katmanı genellikle görünmez kalır. Sorun yaşandığında ilk bakılan yer origin sunucu ya da uygulama kodudur. Proxy'nin zaman zaman bizzat darboğaz yaratabileceğini akılda tutmak ve bunu izolasyonlu biçimde ölçmek, tanı sürecini kısaltır ve gerçek optimizasyon fırsatlarını gün yüzüne çıkarır.