Keep-Alive, proxy üzerinden kalıcı bağlantılar bağlamında, tek bir TCP bağlantısının açık kalmasını ve bir istemci ile bir proxy arasında ve bir proxy ile bir kaynak sunucu arasında birden fazla HTTP isteği ve yanıtı için yeniden kullanılmasını sağlayan bir HTTP mekanizmasıdır; böylece her işlem için yeni bağlantı kurmanın getirdiği ek yük azalır.
Keep-Alive'ı anlamak
Kalıcı bağlantılar olarak da bilinen HTTP Keep-Alive, web performansı için temel bir optimizasyondur. Keep-Alive olmadan her HTTP isteği yeni bir TCP bağlantısı kurulmasını (TCP el sıkışması), ardından veri aktarımını ve sonra bağlantının sonlandırılmasını gerektirirdi. Bu süreç, özellikle ayrıca TLS el sıkışması gerektiren güvenli bağlantılarda, ciddi bir ek yük oluşturur.
Kalıcı bağlantıların faydaları
- Daha düşük gecikme: Aynı bağlantı üzerinden yapılan sonraki isteklerde TCP ve TLS el sıkışmasından kaynaklanan gecikmeyi ortadan kaldırır. Bu, gidiş-dönüş süresi (RTT) yüksek olan istemcilerde özellikle belirgindir.
- Daha az CPU ve bellek kullanımı: Bağlantıların daha seyrek kurulup sonlandırılması istemciler, proxy'ler ve kaynak sunucular üzerindeki hesaplama yükünü azaltır. Buna soket işlemleri için CPU döngüleri, bağlantı durumu için bellek ve dosya tanımlayıcı kullanımı dahildir.
- Daha az ağ tıkanıklığı: Daha az TCP bağlantısının açılıp kapanması, ağ üzerinde daha az sinyalleşme trafiği (SYN, SYN-ACK, FIN, FIN-ACK paketleri) anlamına gelir.
- Daha yüksek throughput: Bağlantılar zamanla daha yüksek aktarım hızlarına ulaşabildiği için TCP'nin tıkanıklık denetimi mekanizmalarının daha verimli kullanılmasını sağlar.
HTTP/1.x'te Keep-Alive
Keep-Alive'ın uygulanışı ve varsayılan davranışı HTTP/1.0 ile HTTP/1.1 arasında farklılık gösterir.
HTTP/1.0'da Keep-Alive
HTTP/1.0'da kalıcı bağlantılar varsayılan değildi. İstemcilerin isteklerine Connection: keep-alive başlığını ekleyerek Keep-Alive'ı açıkça talep etmesi gerekiyordu. Sunucular da kalıcı bağlantıları desteklediklerini belirtmek için aynı başlıkla yanıt veriyordu. Taraflardan biri bu başlığı eklemezse, bağlantı geçerli yanıttan sonra kapatılırdı.
HTTP/1.1'de Keep-Alive
HTTP/1.1, kalıcı bağlantıları varsayılan davranış haline getirdi. Aksi açıkça belirtilmedikçe istemciler ve sunucular, bir işlemden sonra bağlantının açık kalması gerektiğini varsayar. Bir bağlantıyı kapatmak için taraflardan birinin Connection: close başlığını göndermesi gerekir. Bu değişiklik, web performansını varsayılan olarak önemli ölçüde iyileştirdi.
Hop-by-hop başlık olarak Connection başlığı
Connection başlığı bir hop-by-hop başlıktır. Yani yalnızca iletişim kuran iki taraf arasındaki doğrudan bağlantı için tasarlanmıştır (örneğin istemciden proxy'ye ya da proxy'den kaynak sunucuya) ve proxy'ler veya ara sunucular tarafından yeniden iletilmemelidir. Proxy'ler, istekleri veya yanıtları iletmeden önce hop-by-hop başlıkları kaldırmalı ya da değiştirmelidir. Bunun yapılmaması protokol ihlallerine ve beklenmedik davranışlara yol açabilir; çünkü alt taraftaki sunucu veya istemci, bağlantı yönetimi talimatlarını yanlış yorumlayabilir.
Diğer yaygın hop-by-hop başlıklar arasında Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailers ve Upgrade bulunur.
Proxy üzerinden Keep-Alive
Proxy'ler kalıcı bağlantıların yönetiminde kritik bir rol oynar. Genellikle iki grup kalıcı bağlantı tutarlar:
- İstemci-proxy bağlantıları: Proxy, istemcileriyle kalıcı bağlantılar sürdürür.
- Proxy-kaynak bağlantıları: Proxy, istekleri ilettiği kaynak sunucularla kalıcı bağlantılar sürdürür.
Başlık yönetiminde proxy'nin rolü
Bir proxy, istemciden Connection: keep-alive başlığını aldığında, istemcinin proxy'ye olan bağlantısını açık tutmak istediğini anlar. Ancak proxy bu Connection başlığını kaynak sunucuya iletmemelidir. Bunun yerine proxy, kaynak sunucuyla kalıcı bir bağlantı kurup kurmayacağına kendi yapılandırmasına ve kaynak sunucunun yeteneklerine göre bağımsız olarak karar verir.
Özellikle HTTP/1.1 söz konusu olduğunda proxy'ler için yaygın bir yaklaşım, gelen istemci isteklerinden Connection başlığını kaldırmak ve kaynak sunucuya giden upstream bağlantıyı ayrı olarak yönetmektir. Proxy upstream tarafında HTTP/1.1 kalıcı bağlantılarını kullanmak istiyorsa, yalnızca Connection: close başlığını göndermez.
# Keep-Alive ile HTTP/1.1 proxy'lemek için örnek Nginx yapılandırması
location / {
proxy_pass http://backend_server;
proxy_http_version 1.1; # Nginx'e upstream için HTTP/1.1 kullanmasını söyler
proxy_set_header Connection ""; # Connection başlığını istemci isteklerinden kaldırır,
# böylece Nginx upstream Keep-Alive'ı bağımsız olarak yönetir.
# Hop-by-hop başlıkların doğru işlenmesi için bu kritiktir.
}
Bu Nginx örneğinde proxy_http_version 1.1;, Nginx'in backend_server sunucusuna bağlanırken HTTP/1.1 kullanmasını sağlar. Varsayılan olarak HTTP/1.1 bağlantıları kalıcıdır. proxy_set_header Connection ""; ise istemciden gelmiş olabilecek Connection başlığını açıkça kaldırır, bu başlığın kaynak sunucuya iletilmesini önler ve Nginx'in kendi upstream kalıcı bağlantılarını doğru şekilde yönetmesine izin verir.
Bağlantı havuzu (connection pooling)
Proxy'ler, kaynak sunuculara giden upstream bağlantıları için genellikle bağlantı havuzu uygular. Bu, çeşitli kaynak sunuculara açık ve boşta duran TCP bağlantılarından oluşan bir havuz tutmaları anlamına gelir. Belirli bir kaynak için yeni bir istek geldiğinde proxy önce havuzda o kaynağa ait boşta bir bağlantı olup olmadığını kontrol eder. Varsa o bağlantıyı yeniden kullanır. Yoksa yeni bir bağlantı kurulur. Bu, proxy'nin kurması gereken yeni bağlantı sayısını azaltarak verimliliği daha da artırır.
Keep-Alive zaman aşımları ve kaynak yönetimi
Faydalı olmakla birlikte kalıcı bağlantılar, proxy ve kaynak sunucularda kaynakların tükenmesini önlemek için dikkatli yönetim gerektirir.
Zaman aşımı mekanizmaları
Her taraf (istemci, proxy, kaynak sunucu) bir keep-alive zaman aşımı belirleyebilir. Bu zaman aşımı süresi içinde kalıcı bağlantı üzerinde veri alışverişi olmazsa bağlantı kapatılır.
- İstemci tarafı zaman aşımı: İstemci belirli bir süre içinde başka bir istek göndermezse proxy'ye olan bağlantısını kapatabilir.
- Proxy tarafı zaman aşımı: Proxy, hem istemciye hem de kaynağa bakan bağlantılar için kendi
keep-alivezaman aşımlarını yapılandırabilir. Boştaki bir istemci-proxy veya proxy-kaynak bağlantısı zaman aşımını aşarsa proxy bağlantıyı kapatır. - Kaynak sunucu zaman aşımı: Kaynak sunucu, bağlantı çok uzun süre boşta kalırsa proxy'ye olan bağlantısını kapatır.
Uyumsuz zaman aşımları sorunlara yol açabilir. Örneğin, bir kaynak sunucunun keep-alive zaman aşımı proxy'ninkinden kısaysa, kaynak sunucu proxy'nin hâlâ açık sandığı bir bağlantıyı kapatabilir. Proxy bu "bayat" bağlantıyı yeniden kullanmaya çalıştığında bir hatayla karşılaşır (örneğin connection reset) ve isteği yeni bir bağlantı üzerinden tekrarlamak zorunda kalır. Bu, gecikmeyi artırır ve hata oranlarını yükseltir. Bu nedenle proxy-kaynak keep-alive zaman aşımlarının kaynak sunucunun zaman aşımlarından biraz daha kısa veya bunlara eşit olacak şekilde yapılandırılması genellikle önerilir.
Maksimum bağlantı sayısı
Proxy'lerin ayrıca hem istemcilere hem de kaynak sunuculara karşı sürdürdükleri toplam kalıcı bağlantı sayısını sınırlaması gerekir. Açık her bağlantı sistem kaynaklarını (bellek, dosya tanımlayıcıları) tüketir. Sınırsız kalıcı bağlantılar şunlara yol açabilir:
- Dosya tanımlayıcılarının tükenmesi: Proxy'nin kullanılabilir dosya tanımlayıcısı kalmaz.
- Bellek tükenmesi: Çok sayıda açık bağlantı aşırı bellek tüketir.
- Artan CPU yükü: Çok sayıda boştaki bağlantıyı yönetmek yine de bir miktar ek yük getirir.
Proxy yapılandırmaları genellikle yöneticilerin keep-alive_timeout ve keep-alive_requests (tek bir kalıcı bağlantı üzerinden, bağlantı kapatılıp yeniden kurulmadan önce izin verilen maksimum istek sayısı) değerlerini ayarlamasına izin verir.
# Nginx örneği: istemciye bakan bağlantılar için Keep-Alive ayarları
http {
keepalive_timeout 60s; # İstemci-Nginx keep-alive zaman aşımı
keepalive_requests 1000; # İstemci-Nginx keep-alive bağlantısı başına maksimum istek
# ...
}
# Nginx örneği: proxy-kaynak bağlantıları için Keep-Alive ayarları
location / {
proxy_pass http://backend_server;
proxy_http_version 1.1;
proxy_set_header Connection "";
# İsteğe bağlı: gerekiyorsa upstream keep-alive ayarlarını özelleştirin
# Nginx'in varsayılan upstream keep-alive davranışı, bağlantılar upstream tarafından
# açıkça kapatılmadığı veya Nginx tarafından zaman aşımına uğratılmadığı sürece onları yeniden kullanmaktır.
# Upstream bağlantı havuzu üzerinde daha açık denetim için:
# proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
# proxy_connect_timeout 5s;
# proxy_read_timeout 10s;
# proxy_send_timeout 10s;
}
HTTP/2 ve sonrasında Keep-Alive
HTTP/2, çoklama (multiplexing) getirerek birden fazla HTTP isteği ve yanıtının tek bir TCP bağlantısı üzerinden eşzamanlı gönderilmesine olanak tanıdı. Bu, uygulama katmanında açık Connection: keep-alive başlıklarına gerek kalmadan Keep-Alive'ın faydalarını doğal olarak sağlar. Bir HTTP/2 bağlantısı, kurulduktan sonra açıkça kapatılana veya zaman aşımına uğrayana kadar açık kalacak ve istemci ile sunucu (ya da istemci ile proxy, proxy ile kaynak) arasındaki tüm trafiği taşıyacak şekilde tasarlanmıştır.
HTTP/2 açık Keep-Alive başlığını soyutlasa da, ek yükü azaltmak için kalıcı bir TCP bağlantısı sürdürme ilkesi hâlâ kritik önemdedir. HTTP/2'yi destekleyen proxy'ler istemciyle kalıcı bir HTTP/2 bağlantısı yönetir ve kaynağın yeteneklerine ile proxy yapılandırmasına bağlı olarak istekleri kaynak sunucuya HTTP/1.1 kalıcı bağlantılarına veya HTTP/2 bağlantılarına çevirebilir. Proxy'nin bu alttaki TCP bağlantılarını ve zaman aşımlarını yönetme rolü, performans ve kaynak yönetimi açısından hâlâ hayati önemdedir.
Keep-Alive davranışlarının özeti
| Özellik | HTTP/1.0 | HTTP/1.1 | HTTP/2 |
|---|---|---|---|
| Varsayılan kalıcılık | Hayır, bağlantılar her istekten sonra kapanır. | Evet, bağlantılar varsayılan olarak kalıcıdır. | Evet, birden çok stream için tek TCP bağlantısı. |
| Kalıcılık başlığı | Connection: keep-alive (açık) |
Sonlandırmak için Connection: close (açık) |
Yok (kalıcılığı çoklama sağlar) |
| İstek pipelining | Mümkün ama karmaşık (head-of-line blocking) | Mümkün ama karmaşık (head-of-line blocking) | Evet, tam çoklama |
| Proxy yönetimi | Proxy Connection başlığını yönetmeli ve upstream kalıcılığa karar vermelidir. |
Proxy Connection başlığını kaldırmalı ve upstream kalıcılığı yönetmelidir. |
Proxy, kalıcı TCP üzerinde HTTP/2 stream'lerini yönetir. |
| Ek yük azaltma | TCP el sıkışması ek yükünü azaltır. | TCP el sıkışması ek yükünü önemli ölçüde azaltır. | İstek başına TCP/TLS el sıkışması ek yükünü tamamen ortadan kaldırır. |
