Networking & Web — Kapsamlı Rehber
HTTP/1.1, HTTP/2, HTTP/3, TCP/IP, TLS, DNS, WebSocket, gRPC, REST, Reverse Proxy, Load Balancer ve Connection Pooling konularını derinlemesine ve pratik biçimde ele alan bir referans rehber.
İçindekiler
- TCP/IP
- DNS
- TLS
- HTTP/1.1
- HTTP/2
- HTTP/3
- REST
- WebSocket
- gRPC
- Reverse Proxy
- Load Balancer
- Connection Pooling
- Genel Geçer Best Practice’ler
1. TCP/IP
1.1 Genel Bakış
TCP/IP, internetin temel protokol paketidir ve OSI’nin 7 katmanına karşılık dört kavramsal katmanda organize edilir:
| Katman | Örnekler | Sorumluluk |
|---|---|---|
| Uygulama (Application) | HTTP, DNS, gRPC | Uygulama düzeyinde veri alışverişi |
| Taşıma (Transport) | TCP, UDP | Uçtan uca teslimat, portlar |
| İnternet | IP, ICMP | Yönlendirme (routing), adresleme |
| Bağlantı (Link) | Ethernet, Wi-Fi | Fiziksel/çerçeve (frame) teslimatı |
1.2 TCP Üçlü El Sıkışma (Three-Way Handshake)
İstemci Sunucu
| ---- SYN (seq=x) ----> |
| <-- SYN-ACK (seq=y, |
| ack=x+1) --------- |
| ---- ACK (ack=y+1) --> |
| bağlantı açık |
- SYN: istemci başlangıç sıra numarasını (sequence number) önerir.
- SYN-ACK: sunucu onaylar ve kendi sıra numarasını önerir.
- ACK: istemci onaylar; bağlantı artık
ESTABLISHEDdurumundadır. - Bağlantı kapatma (teardown) işlemi 4 yönlü FIN/ACK alışverişiyle yapılır (ani kapanış için RST kullanılır).
1.3 Temel TCP Mekanizmaları
- Güvenilirlik: sıra numaraları + onaylar (acknowledgment) + yeniden gönderim zamanlayıcıları (RTO).
- Akış kontrolü (flow control): alıcı penceresi (
rwnd) alıcının aşırı yüklenmesini engeller. - Tıkanıklık kontrolü (congestion control):
cwnd, slow start → congestion avoidance aşamalarıyla büyür; algoritmalar arasında Reno, CUBIC (Linux varsayılanı) ve BBR (Google tarafından kullanılan, giderek yaygınlaşan) sayılabilir. - Nagle algoritması: küçük yazmaları (write) birleştirerek çok küçük paketleri engeller; gecikmeye duyarlı gerçek zamanlı uygulamalarda
TCP_NODELAYile devre dışı bırakılmalıdır. - Delayed ACK: alıcı, ACK göndermeden önce kısa bir süre bekler; Nagle ile birleştiğinde ~40ms’lik gecikmelere (klasik bir gecikme hatası) yol açabilir.
1.4 TCP vs UDP
| TCP | UDP | |
|---|---|---|
| Bağlantı | Bağlantı odaklı | Bağlantısız |
| Güvenilirlik | Garantili, sıralı | En iyi çaba (best-effort) |
| Ek yük (overhead) | Yüksek (başlıklar, el sıkışma) | Minimal |
| Kullanım alanları | HTTP, gRPC, veritabanları | DNS sorguları, video akışı, QUIC/HTTP3, oyun |
1.5 Best Practice’ler
- Yüksek gecikme/yüksek bant genişliğine sahip bağlantılarda (video, CDN)
net.ipv4.tcp_congestion_controldeğerinibbrolarak ayarlayın. - Yüksek eşzamanlılık gerektiren sunucularda
somaxconnve backlog değerlerini artırın. - Birden fazla process/thread’in aynı port üzerinde accept yapabilmesi için
SO_REUSEPORTkullanın (accept döngüsünü çekirdekler arasında ölçeklendirir). - Çok sayıda kısa ömürlü outbound bağlantı açan sunucularda TIME_WAIT tükenmesine dikkat edin; her istek için yeniden bağlanmak yerine connection pooling kullanın (bkz. §12).
- Ölü peer’ları tespit etmek için uzun süre boşta kalan bağlantılarda TCP keepalive etkinleştirin (NAT zaman aşımları, çökmüş host’lar).
1.6 Sık Yapılan Hatalar
- MTU/MSS uyumsuzluklarının fragmentasyona veya paketlerin kaybolmasına (blackhole) yol açtığını göz ardı etmek (Path MTU Discovery sorunları).
- Yarı açık bağlantıları (peer FIN göndermeden çökmüş) ele almamak — keepalive + uygulama düzeyinde heartbeat ile azaltılabilir.
- TCP
send()çağrısının veri teslim edildiği anlamına geldiğini varsaymak — bu sadece verinin yerel olarak buffer’landığı anlamına gelir.
2. DNS
2.1 Genel Bakış
DNS (Domain Name System), insan tarafından okunabilir alan adlarını IP adreslerine (ve diğer kayıtlara) çeviren hiyerarşik, dağıtık bir isimlendirme sistemidir.
2.2 Çözümleme Akışı
İstemci → Recursive Resolver (ISS/8.8.8.8)
→ Root Sunucu (.)
→ TLD Sunucu (.com)
→ Yetkili (Authoritative) Sunucu (example.com)
→ Yanıt önbelleğe alınır ve döndürülür
2.3 Kayıt Türleri
| Kayıt | Amaç |
|---|---|
| A | Hostname → IPv4 |
| AAAA | Hostname → IPv6 |
| CNAME | Başka bir hostname’e takma ad (alias) |
| MX | Mail sunucuları |
| TXT | Serbest metin (SPF, DKIM, doğrulama) |
| NS | Yetkili isim sunucuları |
| SOA | Zone yetki bilgisi |
| SRV | Servis konumu (host+port), gRPC/Kubernetes tarafından kullanılır |
| PTR | Ters arama (IP → hostname) |
2.4 Önbellekleme ve TTL
- Her kaydın, resolver’ların ne kadar süre önbellekte tutacağını belirleyen bir TTL (saniye) değeri vardır.
- Düşük TTL (örn. 60sn) → daha hızlı failover, daha fazla DNS yükü. Yüksek TTL (örn. 24 saat) → daha az yük, daha yavaş yayılma (propagation).
- Negatif önbellekleme: NXDOMAIN yanıtları da önbelleğe alınır (SOA minimum TTL’e göre).
2.5 Modern Pattern’ler
- DNS tabanlı load balancing: birden fazla A kaydı, round-robin veya coğrafi/gecikme tabanlı (GeoDNS).
- Anycast DNS: aynı IP, BGP üzerinden birden fazla lokasyondan duyurulur; router’lar isteği topolojik olarak en yakın instance’a yönlendirir — root sunucular ve CDN’ler tarafından kullanılır.
- DNSSEC: sahtecilik/önbellek zehirlenmesini önlemek için kayıtları kriptografik olarak imzalar.
- DoH / DoT (DNS over HTTPS/TLS): gizlilik için DNS sorgularını şifreler, düz metin UDP:53 dinlemesini bypass eder.
- Split-horizon DNS: iç ve dış istemciler için farklı yanıtlar (kurumsal/VPC yapılarında yaygın).
2.6 Best Practice’ler
- Planlanan altyapı geçişlerinden önce TTL değerlerini düşük tutun, sonrasında yükseltin.
- Felaket kurtarma için sağlık kontrollü (health-checked) DNS failover kullanın, ancak istemci tarafı önbellekleme nedeniyle failover’ın anında gerçekleşmediğini unutmayın.
- Derin CNAME zincirlerinden kaçının (ek round trip’ler, bazı resolver’lar zincir derinliğini sınırlar).
- DNS’in tek hata noktası (single point of failure) olmasına dikkat edin — uptime kritikse birden fazla yetkili sağlayıcı kullanın.
2.7 Sık Yapılan Hatalar
- Tüm istemcilerin TTL’e uymadığını unutmak (bazı OS/tarayıcılar daha agresif önbellekler, “sticky DNS”).
- Zone apex’te (
example.com) CNAME kullanımı spesifikasyona göre yasaktır — bunun yerine ALIAS/ANAME veya A kayıtları kullanın. - DNS amplification istismarı: açık recursive resolver’lar DDoS saldırılarında silah olarak kullanılabilir — recursion’ı güvenilir istemcilerle sınırlayın.
3. TLS
3.1 Genel Bakış
TLS (Transport Layer Security), TCP (veya DTLS/QUIC aracılığıyla UDP) üzerinde gizlilik, bütünlük ve kimlik doğrulama sağlar. Güncel standart: TLS 1.3 (RFC 8446); TLS 1.0/1.1 kullanımdan kaldırılmıştır, TLS 1.2 hâlâ yaygın olarak desteklenmektedir.
3.2 El Sıkışma (TLS 1.3 — kısaltılmış, 1-RTT)
İstemci Sunucu
---- ClientHello (key_share) ------->
<-- ServerHello (key_share)
+ EncryptedExtensions
+ Certificate
+ CertificateVerify
+ Finished
---- Finished ---------------------->
==== Uygulama Verisi (şifreli) ====
- TLS 1.3, el sıkışmayı (TLS 1.2’deki 2 round trip’e karşılık) 1 round trip’e indirir ve tekrar bağlanan istemciler için 0-RTT devam ettirmeyi destekler (replay saldırısı riskiyle birlikte).
- Zayıf şifreleri (RC4, CBC modu sorunları), statik RSA anahtar değişimini (forward secrecy sağlamaz) kaldırır — yalnızca forward-secret (EC)DHE anahtar değişimleri kalır.
3.3 Temel Kavramlar
- Sertifika zinciri: leaf sertifika → ara CA’lar (intermediate) → root CA (işletim sistemi/tarayıcı güven deposunda güvenilir).
- SNI (Server Name Indication): istemci, el sıkışma sırasında hedef hostname’i açık metin olarak gönderir, bu da tek bir IP üzerinde birden fazla TLS sertifikasına olanak tanır (virtual hosting). (ECH — Encrypted Client Hello — bunu da şifreler, gelişmekte olan bir standart.)
- Forward secrecy: oturum anahtarları bağlantı başına türetilir (ephemeral Diffie-Hellman), böylece uzun ömürlü bir anahtarın ele geçirilmesi geçmiş trafiği ifşa etmez.
- Mutual TLS (mTLS): hem istemci hem sunucu sertifika sunar — servisler arası (zero-trust) mimarilerde ve gRPC’de yaygındır.
- ALPN (Application-Layer Protocol Negotiation): TLS el sıkışması sırasında HTTP/1.1, HTTP/2 veya HTTP/3’ten hangisinin kullanılacağını müzakere eder.
3.4 Best Practice’ler
- Uçtan uca şifreleme gerekmedikçe TLS’i edge’de (load balancer/reverse proxy) sonlandırın (gerekiyorsa iç ağda yeniden şifreleyin veya mTLS mesh kullanın).
- Mümkün olduğunda TLS 1.3 kullanın; TLS 1.0/1.1’i tamamen devre dışı bırakın.
- Sertifika verme/yenileme işlemlerini otomatikleştirin (Let’s Encrypt + ACME, Kubernetes’te cert-manager).
- İstemci tarafı iptal (revocation) kontrolü gecikmesini önlemek için OCSP stapling etkinleştirin.
- Yalnızca güçlü şifre paketleri (cipher suite) kullanın (AEAD şifreler:
TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256). - Sonraki ziyaretlerde HTTPS’i zorunlu kılmak ve downgrade saldırılarını önlemek için
HSTSbaşlıklarını ayarlayın.
3.5 Sık Yapılan Hatalar
- Düzgün ara sertifika bundle’ı olmadan uzun sertifika zincirleri → “tarayıcıda çalışıyor, curl/mobil uygulamada çalışmıyor.”
- Sunucularda saat kayması (clock skew) sertifika geçerlilik kontrollerini bozar.
- TLS sonlandırma noktalarını tutarsız biçimde karıştırmak, iç trafiğin şifresiz sızmasına yol açar (“TLS termination sprawl”).
- Mutasyonlu (non-idempotent) isteklerde oturum devam ettirme/0-RTT replay riski — mutasyon yapan endpoint’lerde 0-RTT’yi devre dışı bırakın.
4. HTTP/1.1
4.1 Genel Bakış
HTTP/1.1 (RFC 7230–7235, 1997), TCP üzerinde metin tabanlı bir istek-yanıt protokolüdür. HTTP/2 ve HTTP/3’ün anlamsal olarak üzerine inşa edildiği temel protokoldür.
4.2 Temel Özellikler
- Kalıcı bağlantılar (persistent connections) (
Connection: keep-alive) — 1.1’de varsayılan, her istek için yeni bir TCP el sıkışmasını önler. - Pipelining: yanıtları beklemeden birden fazla istek gönderme — teorik olarak izin verilse de head-of-line (HOL) blocking (yanıtların sırayla dönmesi gerekir) nedeniyle neredeyse evrensel olarak devre dışıdır.
- Chunked transfer encoding:
Content-Length‘i önceden bilmeden yanıt gövdesini akış (stream) hâlinde gönderme. - Önbellekleme başlıkları:
Cache-Control,ETag,Last-Modified,If-None-Match. - İçerik müzakeresi (content negotiation):
Accept,Accept-Encoding,Accept-Language.
4.3 İstek/Yanıt Yapısı
GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128
Cache-Control: max-age=60
{"id":42,"name":"Ada"}
4.4 Best Practice’ler
- Bağlantı yeniden kullanımını (connection reuse) agresif biçimde uygulayın — her istek için TCP+TLS kurulum maliyetinden kaçının.
- Domain sharding‘i dikkatli kullanın (tarayıcının host başına 6 bağlantı sınırına karşı bir çözümdü) — HTTP/2 multiplexing ile büyük ölçüde gereksiz hâle geldi.
Content-Encodingaracılığıyla yanıtları sıkıştırın (gzip,br).- Bant genişliğini azaltmak için koşullu istekler (
If-Modified-Since/ETag) kullanın. - Açık zaman aşımları (client & server) belirleyin — HTTP/1.1 bağlantıları bunlar olmadan süresiz olarak asılı kalabilir.
4.5 Sık Yapılan Hatalar
- Head-of-line blocking: pipelining kullanılıyorsa, yavaş bir istek tüm bağlantı kuyruğunu bloke eder — bu yüzden çoğu istemci tek bağlantı yerine paralel bağlantılar açar (tarayıcılar: host başına ~6).
- Her istekte tekrar eden, ayrıntılı başlıklar (çerezler, user-agent) — HTTP/2’nin HPACK’inin aksine başlık sıkıştırması yoktur.
- Load balancer’ın idle timeout’uyla uyuşmayan varsayılan keep-alive zaman aşımlarına güvenmek, aralıklı
502/bağlantı sıfırlama hatalarına yol açar.
5. HTTP/2
5.1 Genel Bakış
HTTP/2 (RFC 7540, 2015, Google’ın SPDY’sine dayanır), HTTP/1.1 anlamlarını (metotlar, durum kodları, başlıklar) korur ancak tel formatını tek bir TCP bağlantısı üzerinden binary, multiplexed bir protokole dönüştürür.
5.2 Temel Özellikler
- Multiplexing: tek bir TCP bağlantısı üzerinden birçok eşzamanlı istek/yanıt stream‘i — artık istek başına bağlantı yükü veya tarayıcının 6 bağlantı sınırı yok.
- Stream önceliklendirme (prioritization): istemciler stream’lerin göreli önemini belirtebilir (karmaşıklığı nedeniyle pratikte kısmen kullanımdan kalktı — HTTP/3 bunu yeniden ele alıyor).
- HPACK başlık sıkıştırması: paylaşımlı, indekslenmiş bir tablo aracılığıyla gereksiz başlık iletimini ortadan kaldırır.
- Server Push (
PUSH_PROMISE): sunucu, istemcinin ihtiyaç duyacağını öngördüğü kaynakları proaktif olarak gönderir — zayıf önbellek uyumu ve karmaşıklığı nedeniyle büyük ölçüde kullanımdan kaldırıldı (2022’de Chrome’dan kaldırıldı); bunun yerineLink: rel=preloadveya 103 Early Hints tercih edin. - Akış kontrolü: stream başına ve bağlantı başına pencereler.
5.3 Binary Framing
Tüm iletişim, bir stream ID ile etiketlenmiş ve tek bir bağlantı üzerinde multiplekslenmiş frame’lere (HEADERS, DATA, SETTINGS, WINDOW_UPDATE, RST_STREAM, PING, GOAWAY) bölünür.
Bağlantı
├─ Stream 1: HEADERS → DATA → DATA (yanıt gövdesi)
├─ Stream 3: HEADERS → DATA
└─ Stream 5: HEADERS (istek işlemde)
5.4 Best Practice’ler
- HTTP/1.1 dönemi optimizasyonlarından vazgeçin: domain sharding, sprite’lama, birleştirme (concatenation) — bunlar HTTP/2’ye aktif olarak zarar verir (çok sayıda küçük bağlantı yerine daha az, daha büyük bağlantılar tercih edilir).
- Origin başına tek bağlantı kullanın; paralel bağlantılar yerine multiplexing’e güvenin.
- Kritik varlıkları önceden yüklemek için kullanımdan kaldırılan Server Push yerine
103 Early Hintstercih edin. - Stream-flood eden istemcilerden kaynaklanan kaynak tükenmesini önlemek için sunucu tarafında
SETTINGS_MAX_CONCURRENT_STREAMSdeğerini ayarlayın.
5.5 Sık Yapılan Hatalar
- TCP düzeyinde head-of-line blocking: HTTP/2, uygulama düzeyindeki HOL blocking’i çözer, ancak kaybedilen tek bir TCP paketi hâlâ multiplekslenmiş tüm stream’leri durdurur (bu, HTTP/3’ün temel motivasyonudur).
- Pratikte TLS gerektirir (tüm büyük tarayıcılar HTTP/2’yi yalnızca TLS üzerinden destekler,
h2ALPN token’ı) — spesifikasyon düz metni (h2c) izin verse bile. - HTTP/2 framing’ini anlamayan yanlış yapılandırılmış ara katmanlar (eski proxy’ler/WAF’lar) bağlantıları sessizce bozabilir — HTTP/2 downgrade fallback’i önemlidir.
6. HTTP/3
6.1 Genel Bakış
HTTP/3 (RFC 9114, 2022), TCP’nin yerine Google tarafından geliştirilen ve IETF’de standartlaştırılan UDP tabanlı bir taşıma protokolü olan QUIC‘i (RFC 9000) kullanır. Amaç: HTTP/2’nin TCP düzeyindeki HOL blocking sorununu çözmek ve bağlantı kurulum gecikmesini azaltmak.
6.2 QUIC Temelleri
- UDP üzerinde çalışır, kendi güvenilirlik, tıkanıklık kontrolü ve multiplexing mekanizmasını kullanıcı alanında (user space) uygular (kernel düzeyindeki TCP değişikliklerinden daha hızlı iterasyon).
- Stream’ler taşıma katmanında bağımsızdır: kaybedilen bir paket yalnızca ait olduğu stream’i durdurur, tüm bağlantıyı değil — HTTP/2’nin TCP HOL blocking sorununu çözer.
- Entegre TLS 1.3: el sıkışma aynı zamanda TLS el sıkışmasıdır — bağlantı kurulumu ve kripto müzakeresi 1-RTT‘de (devam ettirilen bağlantılarda 0-RTT‘de) birlikte gerçekleşir.
- Bağlantı taşınması (connection migration): bağlantılar IP:port dörtlüsü yerine bir Connection ID ile tanımlanır — Wi-Fi’dan mobil veriye geçen bir istemci bağlantısını canlı tutabilir (mobil için büyük avantaj).
6.3 Karşılaştırma
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| Taşıma | TCP | TCP | QUIC (UDP) |
| Multiplexing | Hayır (pipelining kullanılmıyor) | Evet, tek TCP bağlantısı | Evet, bağımsız stream’ler |
| HOL blocking | Var (bağlantı düzeyinde) | Kısmi (yalnızca TCP düzeyinde) | Çözüldü (stream başına) |
| El sıkışma | TCP + TLS (2–3 RTT) | TCP + TLS (2–3 RTT) | 1-RTT (0-RTT devam ettirme) |
| Başlık sıkıştırma | Yok | HPACK | QPACK (HOL-blocking’e karşı güvenli) |
| Bağlantı taşınması | Hayır | Hayır | Evet |
6.4 Best Practice’ler
- İstemcilerin HTTP/2’den fırsatçı bir şekilde yükseltme yapabilmesi için
Alt-Svcbaşlığıyla HTTP/3’ü duyurun. - Firewall’larda/load balancer’larda UDP/443’ün açık olduğundan emin olun — birçok kurumsal ağ varsayılan olarak UDP’yi engeller, bu yüzden her zaman bir HTTP/2 fallback’i bulundurun.
- QUIC sonlandırmasını kendiniz uygulamak yerine olgun QUIC uygulamalarına sahip CDN/edge sağlayıcıları kullanın (çoğu büyük CDN artık destekliyor).
- QUIC endpoint’lerini kendiniz barındırırken UDP tabanlı amplification/DoS vektörlerine karşı izleme yapın.
6.5 Sık Yapılan Hatalar
- Bazı middlebox’lar/NAT’lar UDP’yi kötü ele alır (TCP’den daha kısa idle timeout’lar) — NAT bağlantılarını canlı tutmak için PING frame’leri gerekir.
- Hata ayıklama daha zordur — QUIC, TLS-over-TCP’ye kıyasla el sıkışmanın daha fazlasını şifreler, bu yüzden geleneksel paket yakalama tabanlı hata ayıklama QUIC’e duyarlı araçlar gerektirir (
qlog, Wireshark QUIC dissector). - CPU maliyeti: QUIC’in kullanıcı alanındaki kripto/tıkanıklık kontrolü işi, byte başına kernel-optimize TCP’den daha CPU yoğun — çok yüksek throughput’ta önem kazanır.
7. REST
7.1 Genel Bakış
REST (Representational State Transfer), Roy Fielding’in 2000 tarihli tezinde tanımlanan, ağ üzerindeki API’leri tasarlamak için bir mimari stildir — bir protokol değildir — ve genellikle HTTP üzerinde uygulanır.
7.2 Kısıtlamalar (REST’in gerçek tanımı)
- Client-server ayrımı
- Durumsuzluk (statelessness) — her istek gerekli tüm bağlamı içerir; sunucu tarafında oturum durumu yoktur
- Önbelleklenebilirlik (cacheability) — yanıtlar açıkça önbelleklenebilir/önbelleklenemez olarak işaretlenir
- Tekdüze arayüz (uniform interface) — kaynaklar URI’lerle tanımlanır, temsiller (representation) aracılığıyla değiştirilir, kendini açıklayan mesajlar, HATEOAS
- Katmanlı sistem — istemci, doğrudan sunucuya mı yoksa bir ara katmana (proxy, gateway) mı bağlı olduğunu anlayamaz
- İsteğe bağlı kod (code on demand) (opsiyonel) — sunucu istemci işlevselliğini genişletebilir (örn. JS)
7.3 Kaynak ve Metot Tasarımı
| Metot | Anlam | İdempotent | Güvenli (Safe) |
|---|---|---|---|
| GET | Kaynağı oku | Evet | Evet |
| POST | Oluştur / idempotent olmayan işlem | Hayır | Hayır |
| PUT | Kaynağı tamamen değiştir | Evet | Hayır |
| PATCH | Kısmi güncelleme | Hayır* | Hayır |
| DELETE | Kaynağı sil | Evet | Hayır |
GET /orders → siparişleri listele
POST /orders → sipariş oluştur
GET /orders/123 → 123 numaralı siparişi getir
PUT /orders/123 → 123 numaralı siparişi tamamen değiştir
PATCH /orders/123 → 123 numaralı siparişi kısmen güncelle
DELETE /orders/123 → 123 numaralı siparişi sil
7.4 Önemli Durum Kodları
200 OK,201 Created(+Locationbaşlığı),202 Accepted(asenkron işleme),204 No Content400 Bad Request,401 Unauthorized,403 Forbidden,404 Not Found,409 Conflict,422 Unprocessable Entity,429 Too Many Requests500 Internal Server Error,502 Bad Gateway,503 Service Unavailable,504 Gateway Timeout
7.5 Best Practice’ler
- URI’lerde isim kullanın, fiil değil (
/orders/123/cancel, temiz bir kaynak eşlemesi olmayan işlemler için pragmatik bir istisnadır). - API’leri bilinçli olarak versiyonlayın: URI (
/v1/orders), başlık (Accept: application/vnd.api+json;version=1) veya içerik müzakeresi — birini seçin ve tutarlı olun. - Sayfalama (pagination) destekleyin (
?cursor=veya?page=&limit=) — büyük/değişen veri kümelerinde offset tabanlıdan çok cursor tabanlı sayfalamayı tercih edin. - İyimser eşzamanlılık kontrolü (optimistic concurrency control) için ETag + koşullu istekler kullanın (PUT/PATCH’te
If-Match). - Makine tarafından okunabilir hata kodlarıyla tutarlı hata gövdeleri döndürün (örn.
application/problem+json, RFC 9457). - Ödeme/kritik işlemlerde yeniden denemeleri (retry) güvenle ele almak için POST’ta idempotency key tasarımı yapın.
- OpenAPI/Swagger ile dokümante edin; istek/yanıtları CI’da şemaya karşı doğrulayın.
7.6 Sık Yapılan Hatalar
- REST kılığına girmiş “RPC-over-HTTP” (URI’lerde fiiller, durum kodlarının göz ardı edilmesi, her şey POST) — bir stil tercihi olarak sorun değil, ama buna REST demeyin.
- İstemci tarafında N+1 istek pattern’ine yol açan “gevezelik eden” (chatty) API’ler — batching, GraphQL veya BFF (Backend-for-Frontend) pattern’lerini düşünün.
- İç DB şemasını doğrudan API şekli olarak sızdırmak — istemcileri iç uygulama detaylarına bağımlı kılar.
- HATEOAS’ı tamamen göz ardı etmek pratikte yaygın ve çoğunlukla sorun değildir — ancak Fielding’in tam modelini değil, REST’in pragmatik bir alt kümesini kullandığınızın farkında olun.
8. WebSocket
8.1 Genel Bakış
WebSocket (RFC 6455), bir HTTP Upgrade el sıkışmasıyla başlatılan, tek bir TCP bağlantısı üzerinden tam çift yönlü (full-duplex), kalıcı bir iletişim kanalı sağlar.
8.2 El Sıkışma
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
101 yanıtından sonra TCP bağlantısı, WebSocket framing protokolü için yeniden amaçlandırılır — artık HTTP istek/yanıt anlamı yoktur.
8.3 Temel Özellikler
- Tam çift yönlü: her iki taraf da istediği zaman frame gönderebilir.
- Hafif framing (frame başına tam HTTP başlıklarına kıyasla 2–14 byte ek yük).
- Metin ve binary frame’leri destekler; keepalive/liveness için ping/pong frame’leri.
- Tek bir bağlantının ömrü ötesinde yeniden bağlanma, backoff veya mesaj sıralaması garantisi yerleşik değildir — bunları uygulama katmanı sağlamalıdır.
8.4 Best Practice’ler
- Boşta kalan TCP’yi sessizce düşüren proxy’ler/NAT’lar üzerinden ölü bağlantıları tespit etmek için uygulama katmanında heartbeat (ping/pong) uygulayın.
- Üstel geri çekilme (exponential backoff) + jitter ile istemci tarafı yeniden bağlanma uygulayın.
- İleriye dönük uyumluluk için mesajları bir tür/versiyon zarfı (envelope) ile tasarlayın (
{"type": "chat.message", "v": 1, "payload": {...}}). - Yatay olarak ölçeklenmiş instance’lar arasında mesajları dağıtmak için WebSocket sunucularının arkasında bir mesaj broker’ı (Redis Pub/Sub, Kafka, NATS) kullanın — tek bir WS sunucusu başka instance’lara bağlı istemcilere yayın yapamaz.
- Tarayıcı WebSocket API’lerinde özel başlıklar kullanılamadığından, el sıkışma sırasında kimlik doğrulaması yapın (query param’da token veya
Sec-WebSocket-Protocol/cookie). - Kaynak tükenmesini önlemek için makul idle timeout’lar ayarlayın ve mesaj boyutu sınırları uygulayın.
8.5 Sık Yapılan Hatalar
- WebSocket bağlantılarının load balancer yeniden başlatmalarında/deploy’larında hayatta kalacağını varsaymak — istemci tarafında zarif yeniden bağlanmayı planlayın.
- Sticky-session gereksinimleri: sunucu bağlantı başına bellek içi durum tutuyorsa, LB yeniden bağlanmaları tutarlı biçimde yönlendirmelidir (veya durumu Redis vb. bir yere taşıyın).
- Backpressure’ı ele almamak — yavaş bir tüketici sınırsız sunucu tarafı buffer’lamaya yol açabilir; sınırlı kuyruklar kullanın ve taşmada bağlantıyı düşürün/kapatın.
- Server-Sent Events (SSE)’nin yeterli olacağı yerde WebSocket kullanmak (daha basit, HTTP-native, otomatik yeniden bağlanma, tek yönlü sunucu→istemci) — tek yönlü akış için varsayılan olarak WebSocket’e yönelmeyin.
9. gRPC
9.1 Genel Bakış
gRPC, Google tarafından geliştirilen, HTTP/2 ve Protocol Buffers (protobuf) üzerine inşa edilmiş, servisler arası verimli iletişim için tasarlanmış yüksek performanslı bir RPC framework’üdür.
9.2 Temel Özellikler
.protodosyaları aracılığıyla güçlü tipli sözleşmeler (contracts), birçok dilde kod üretilmiş istemci/sunucular.- Binary serileştirme (protobuf) — JSON’dan daha küçük, daha hızlı.
- Dört çağrı türü:
- Unary (istek → yanıt, normal REST gibi)
- Server streaming (bir istek → yanıt akışı)
- Client streaming (istek akışı → bir yanıt)
- Bidirectional streaming (her iki taraf da bağımsız olarak akış yapar)
- HTTP/2 multiplexing üzerine inşa edilmiştir — tek bir bağlantı üzerinden birçok eşzamanlı RPC.
- Deadline/timeout ve iptal (cancellation), servis çağrı zincirleri boyunca otomatik olarak yayılır.
- Kimlik doğrulama, loglama, retry, tracing için interceptor’lar (middleware).
9.3 Örnek .proto
syntax = "proto3";
service OrderService {
rpc GetOrder (OrderRequest) returns (Order);
rpc StreamOrderUpdates (OrderRequest) returns (stream Order);
}
message OrderRequest { string order_id = 1; }
message Order {
string id = 1;
string status = 2;
double total = 3;
}
9.4 Best Practice’ler
- gRPC’yi iç servisler arası iletişim için kullanın; tarayıcı/genel istemciler için edge’de REST/GraphQL sunun (tarayıcılar, gRPC-Web + proxy çeviri katmanı olmadan gRPC’nin HTTP/2 trailer tabanlı framing’ini doğal olarak konuşamaz).
- Her çağrıda deadline belirleyin — bunlar olmadan istekler süresiz asılı kalabilir ve hatalar yukarı doğru zincirlenebilir (cascading).
- Mesh/zero-trust ortamında servis kimlik doğrulaması için mTLS kullanın.
.protomesajlarını dikkatli versiyonlayın: yalnızca opsiyonel alanlar ekleyin, alan numaralarını asla yeniden numaralandırmayın/yeniden kullanmayın, kaldırılan alanlar için reserved anahtar kelimesini kullanın.- Backoff’lu yeniden denemeleri yalnızca idempotent metotlarda kullanın; metotları açıkça işaretleyin.
- Uzun ömürlü HTTP/2 bağlantıları basit L4 LB’ler üzerinden iyi yeniden dengelenmediğinden istemci tarafında load balancing (servis keşfi ile) kullanın.
9.5 Sık Yapılan Hatalar
- L4 (TCP düzeyi) load balancer’lar gRPC çağrılarını iyi dağıtmaz çünkü tek bir HTTP/2 bağlantısı birçok RPC taşır — L7-farkında LB’ler (Envoy, Linkerd) veya istemci tarafı load balancing gerekir.
- Akış kontrolü ayarlanmadan streaming RPC’ler üzerinden büyük mesajlar bellek baskısına yol açabilir.
- Protobuf alan numaralarının, bir kez yayınlandıktan sonra esasen kalıcı API sözleşmeleri olduğunu unutmak.
- Tarayıcı istemcileri gRPC-Web + Envoy/proxy çeviri katmanı gerektirir — düz gRPC tarayıcı JS’inden doğrudan çalışmaz.
10. Reverse Proxy
10.1 Genel Bakış
Bir reverse proxy, bir veya daha fazla backend sunucusunun önünde durur, istemci isteklerini onlara iletir ve yanıtları döndürür — istemci yalnızca proxy ile konuşur, backend topolojisinden habersizdir.
İstemci → Reverse Proxy → [Backend A, Backend B, Backend C]
10.2 Yaygın Kullanımlar
- TLS sonlandırma: HTTPS’i edge’de şifresini çöz, düz metni (veya yeniden şifrelenmiş mTLS’i) iç ağa ilet.
- Load balancing: istekleri backend instance’lar arasında dağıt (bkz. §11).
- Önbellekleme: statik/yarı statik yanıtları istemciye yakın önbelleğe al.
- Sıkıştırma: servis başına değil, merkezi olarak gzip/brotli yanıtları sıkıştır.
- İstek yönlendirme: path tabanlı (
/api/*→ servis A,/static/*→ CDN), host tabanlı (virtual hosting). - Güvenlik: WAF kuralları, rate limiting, IP izin/red listeleri, iç topolojiyi gizleme.
- Protokol çevirisi: HTTP/1.1 istemci ↔ HTTP/2 veya gRPC backend.
10.3 Popüler Uygulamalar
| Araç | Notlar |
|---|---|
| Nginx | Kanıtlanmış, config dosyası tabanlı, geniş ekosistem |
| Envoy | L7-farkında, xDS API ile dinamik config, gRPC-native, service mesh data plane |
| HAProxy | Son derece yüksek performanslı L4/L7 LB/proxy |
| Traefik | Otomatik keşif (Docker/Kubernetes etiketleri), dinamik config |
| Caddy | Let’s Encrypt ile otomatik HTTPS, basit config |
10.4 Örnek (Nginx)
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/api.crt;
ssl_certificate_key /etc/ssl/private/api.key;
location /v1/ {
proxy_pass http://backend_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 30s;
}
}
10.5 Best Practice’ler
- Backend’lerin orijinal istemci bağlamını bilmesi için her zaman
X-Forwarded-For,X-Forwarded-Proto,X-Real-IPbaşlıklarını iletin. - Her hop’ta (connect, read, write) açık zaman aşımları belirleyin — proxy ve backend arasında uyumsuz zaman aşımları kafa karıştırıcı
502/504hatalarına yol açar. - TLS’i proxy’de sonlandırın ama zero-trust ortamlarda iç ağda yeniden şifrelemeyi (mTLS) düşünün — iç ağların güvenli olduğunu varsaymayın.
- Kolay yatay ölçeklenme için proxy katmanını mümkün olduğunda stateless tutun.
- Sağlıksız backend’leri rotasyondan otomatik olarak çıkarmak için health check’ler kullanın.
10.6 Sık Yapılan Hatalar
- Proxy yaparken hop-by-hop başlıkları (
Connection,Keep-Alive) çıkarmayı unutmak. - Büyük istek/yanıt gövdelerini proxy’de bellekte buffer’lamak — yük altında OOM’a yol açar; bunun yerine akış (stream) yapın.
- Reverse proxy vs forward proxy karışıklığı: forward proxy istemciyi temsil eder (örn. kurumsal çıkış proxy’si); reverse proxy sunucuyu temsil eder.
11. Load Balancer
11.1 Genel Bakış
Bir load balancer, kullanılabilirliği, ölçeklenebilirliği ve hata toleransını artırmak için gelen trafiği birden fazla backend instance arasında dağıtır.
11.2 Katmanlar
- L4 (Taşıma katmanı): IP/port’a göre yönlendirir, HTTP içeriğine görünürlüğü yoktur — çok hızlı, protokolden bağımsız (genel olarak TCP/UDP için çalışır). Örnekler: AWS NLB, IPVS, TCP modunda HAProxy.
- L7 (Uygulama katmanı): HTTP/gRPC’yi anlar — path, başlık, cookie’ye göre yönlendirebilir; TLS sonlandırma, retry, circuit breaking destekler. Örnekler: AWS ALB, Envoy, Nginx.
11.3 Algoritmalar
| Algoritma | Açıklama | Uygun olduğu durum |
|---|---|---|
| Round robin | Backend’ler arasında sırayla döner | Homojen backend kapasitesi |
| Weighted round robin | Kapasite ağırlıklarıyla round robin | Heterojen backend boyutları |
| Least connections | En az aktif bağlantıya sahip backend’e yönlendirir | Değişken istek süresi |
| Least response time | Bağlantı sayısı + gecikmeyi birleştirir | Gecikmeye duyarlı servisler |
| IP hash / consistent hashing | Aynı istemci (veya key) → aynı backend | Oturum yakınlığı (session affinity), önbellek lokalitesi |
| Random (2 seçimli) | 2 rastgele backend seç, daha az yüklü olanı tercih et | Least-connections’tan basit, iyi ölçeklenir |
11.4 Yüksek Kullanılabilirlik Pattern’leri
- Active-passive: bekleyen (standby) LB, birincil (primary) hata durumunda VRRP/keepalived ile devralır.
- Active-active: DNS round-robin veya Anycast arkasında birden fazla LB, tümü aynı anda trafik sunar.
- Health check’ler: aktif (LB
/healthz‘ı poll eder) vs pasif (LB gerçek trafik hatalarını gözlemler, hata oranı eşiğinde çıkarır — “outlier detection”).
11.5 Best Practice’ler
- Düzensiz istek sürelerinde naif round robin yerine least connections veya power-of-two-choices‘ı tercih edin.
- Circuit breaking uygulayın: tekrarlanan hatalardan sonra bir backend’e trafik göndermeyi durdurun, kademeli olarak yeniden deneyin (half-open durumu).
- Deploy sırasında connection draining (zarif kaldırma) kullanın — bir instance’a yeni istek göndermeyi durdurup devam eden isteklerin tamamlanmasına izin verin.
- Ham throughput için L4 + gerektiğinde akıllı yönlendirme için edge’de L7’yi birleştirin — gerekmiyorsa her zaman tam L7’ye varsayılan olarak yönelmeyin (ekstra gecikme/CPU maliyeti).
- Mümkün olduğunda oturum yakınlığı/sticky session’lardan kaçının — herhangi bir backend herhangi bir isteği sunabilsin diye oturum durumunu dışsallaştırın (Redis); kaçınılmazsa (örn. WebSocket), consistent hashing kullanın.
11.6 Sık Yapılan Hatalar
- Backend yeniden başlatmasında thundering herd: LB, yeni başlayan bir instance ısınmadan hemen tam trafiği göndermeye başlar — slow-start ramping kullanın.
- Health check endpoint’inin çok yüzeysel olması (
200 OKher zaman) — gerçek backend sağlığını yansıtmaz (DB bağlantısı, bağımlılık durumu). - gRPC/HTTP2 önünde L4 LB dengesizliğe yol açar (bkz. §9.5) — uzun ömürlü multiplekslenmiş bağlantılar tek bir backend’e yapışır.
12. Connection Pooling
12.1 Genel Bakış
Connection pooling, her işlem için bir bağlantı oluşturup kapatmak yerine önceden kurulmuş bir bağlantı setini (TCP, TLS, DB) yeniden kullanır — bağlantı kurulumu (TCP el sıkışma + TLS el sıkışma + kimlik doğrulama) gerçek işe kıyasla pahalı olduğu için kritiktir.
12.2 Neden Önemli
Pooling olmadan: [bağlan][TLS][auth][sorgu][kapat] ← her istekte tekrarlanır
Pooling ile: [pool'dan al][sorgu][pool'a geri ver]
- Tekrarlanan 3 yönlü TCP el sıkışma + TLS el sıkışma gecikmesini önler (istek başına 2-3 RTT tasarrufu sağlayabilir).
- Sunucu tarafı kaynak tüketimini (file descriptor, geçici (ephemeral) portlar, TIME_WAIT birikimi) azaltır.
- Veritabanları, çok sayıda outbound çağrı yapan HTTP istemcileri, gRPC channel’ları için gereklidir.
12.3 Temel Parametreler
| Parametre | Amaç |
|---|---|
| Min pool size | Boşta olsa bile sıcak tutulan bağlantılar |
| Max pool size | Backend’i aşırı yüklenmeden korumak için üst sınır |
| Idle timeout | N saniyeden fazla kullanılmayan bağlantıları kapat |
| Max lifetime | Bağlantıları periyodik olarak zorla yenile (bayat/sızdırılmış durumu önle, rolling backend restart’a olanak tanı) |
| Acquisition timeout | Çağıranın boş bir bağlantı için hata almadan önce ne kadar bekleyeceği |
| Doğrulama/health check | Vermeden önce bağlantının canlı olduğunu test et (örn. SELECT 1) |
12.4 Best Practice’ler
- Pool’ları tahmine değil, gerçek eşzamanlılık ihtiyaçlarına göre boyutlandırın —
max_pool_size ≈ (ortalama eşzamanlı istek) × (ortalama bağlantı tutma süresi); aşırı büyük pool’lar backend’i (örn. DB bağlantı limitleri) aşırı yükleyebilir, yetersiz büyük pool’lar kuyruklamaya yol açar. - İstek başına veya thread başına değil, process başına paylaşımlı bir pool kullanın — tüm uygulama genelinde yeniden kullanımı sağlar.
- Güvenli DNS/backend rotasyonuna izin vermek için pool’lanan bağlantılarda max lifetime ayarlayın (round-robin DNS arkasında “ölü bir backend’e sabitlenme” sorununu önler).
- Pool metriklerini izleyin: aktif/boşta sayısı, bekleme süresi, timeout oranı — pool tükenmesi, kademeli gecikme sıçramalarının başlıca nedenidir.
- HTTP istemcileri için keep-alive’ın etkin olduğundan ve bağlantı yeniden kullanımının çalıştığından emin olun (birçok HTTP istemci kütüphanesi, açıkça paylaşımlı bir client/transport instance’ı ile yapılandırılmadıkça varsayılan olarak bağlantıları yeniden kullanmaz).
- Veritabanları için, uygulamanın kendisi pool’ları tek başına iyi tutamayan çok sayıda kısa ömürlü process açtığında (serverless/lambda) harici pooler’ları (Postgres için PgBouncer) tercih edin.
12.5 Sık Yapılan Hatalar
- Her istek için yeni bir HTTP client (dolayısıyla yeni bir connection pool) oluşturmak — istek handler’ı içinde app başlangıcında değil
http.Client()/axios.create()örneklendiren kodda son derece yaygın bir hata. - Yük altında pool tükenmesi thundering herd of timeouts‘a yol açar, bu da istemci yeniden denemelerini tetikler, bu da yükü daha da artırır — klasik bir retry storm.
- Pool boyutunu backend’in kendi bağlantı limitleriyle eşleştirmemek (örn. 50 uygulama instance’ı × 20 bağlantılık pool’lar = maksimum 200 için yapılandırılmış bir DB’ye çarpan 1000 bağlantı).
- Bağlantıları sızdırmak (hata yollarında pool’a geri döndürmemek) — her zaman
try/finallyveya RAII tarzı kaynak yönetimi kullanın. - Backend yeniden başlatma/failover sonrası pool’da bayat bağlantılar — max lifetime + liveness check’lerle azaltın.
13. Genel Geçer Best Practice’ler
- Her yerde, her hop’ta zaman aşımları: istemci → proxy → LB → backend → veritabanı. Eksik tek bir zaman aşımı süresiz asılı kalmaya ve kaynak tükenmesine yol açabilir.
- Yeniden denenebilecek her şey için idempotency‘yi birinci sınıf bir tasarım kaygısı olarak ele alın (ağ güvenilmezdir — her zaman yeniden denemelerin gerçekleştiğini varsayın).
- Gözlemlenebilirlik (observability): yapılandırılmış loglar, proxy → LB → servis → gRPC çağrıları → DB arasında bir isteği ilişkilendiren dağıtık tracing (OpenTelemetry) ve metrikler (RED: Rate, Errors, Duration).
- Zarif bozulma (graceful degradation): circuit breaker’lar, bulkhead’ler, fallback yanıtları — bir bağımlılığın başarısız olmasının tam bir kesintiye dönüşmesine izin vermeyin.
- Derinlemesine savunma (defense in depth): her yerde TLS (zero-trust modellerinde iç trafik dahil), birden fazla katmanda rate limiting, her sınırda input doğrulaması.
- Protokol müzakeresi: eski istemcileri bozmadan istemcilerin fırsatçı bir şekilde yükseltme yapmasına izin vermek için ALPN/
Alt-Svckullanın (HTTP/1.1 → HTTP/2 → HTTP/3). - Kapasite planlaması: connection pooling, load balancer algoritması ve backend eşzamanlılık limitlerinin gerçek trafik pattern’leri altında nasıl etkileşime girdiğini anlayın — sadece ham istek oranıyla değil, gerçekçi bağlantı yeniden kullanım davranışıyla yük testi yapın.
Rehberin sonu. İngilizce versiyon için networking-web-guide-en.md dosyasına bakın.