Ötüken
Moderatör Penguen
- Katılım
- 18 Temmuz 2026
- Mesajlar
- 12
- Konum
- Tekirdağ
Ağ hatalarına tolerans konusu, özellikle microservis mimarileriyle uğraşanların kafasını kurcalayan klasik bir konudur. İki uygulama arasındaki fark genelde kod kalitesinden ziyade, mimari ve kullanılan protokolün doğasından kaynaklanır.
Olayın özü şu: Stateful (durum bilgisi tutan) vs Stateless (durum bilgisi tutmayan) bağlantı yönetimi.
Klasik bir web tarayıcısını düşünün. Sayfayı yüklerken internetiniz gitti, modemin ışığı söndü. Tarayıcı hemen çökmez, bir süre dönen tekerleği gösterir. İnternet geri gelince sayfayı komple refresh etmek zorunda kalmaz, genelde kaldığı yerden yüklemeye çalışır. Peki buna karşılık bir SSH bağlantısı neden anında patlar? Çünkü SSH, TCP üzerinde sürekli açık kalan ve her iki tarafın da birbirinin durumunu (sequence numbers, window size) takip ettiği bir stateful tüneldir. Aradaki fiziksel bağ kopunca, TCP keep-alive mekanizması devreye girer. Eğer paket kaybı çok yüksekse veya timeout süresi aşılırsa, işletim sistemi “broken pipe” hatasını fırlatır ve uygulama çöker.
Uygulamanın crash olmasına neden olan temel faktörler:
Peki tolere edenler ne yapıyor?
Genelde Circuit Breaker Pattern ve Idempotency (Tekrarlanabilirlik) kullanılıyor. Örneğin bir ödeme servisine istek attınız, cevap gelmedi. Çöken uygulama “Acaba para çekildi mi çekilmedi mi?” diye sorgulamaz. Ama dayanıklı bir uygulama, işleme unique bir
Basit bir kod mantığıyla anlatmak gerekirse, çöken uygulama şöyle bir şey yapar:
Tolere eden uygulama ise şöyle yaklaşır:
Bir diğer kritik konu da Graceful Degradation. Yani uygulamanın tüm özellikleri çalışmasa bile, temel işlevini kaybetmemesi. Spotify'ı düşünün. İnternet gidince uygulama çökmez. Çevrimdışı moda geçer, cache'lenmiş şarkıları çalar. Arayüzde bir banner çıkar “Çevrimdışısınız” der. Bu, uygulamanın network layer'ının soyutlanmış olması sayesinde olur. Repository pattern ile veri katmanı izole edilir, ağ yoksa otomatik olarak local veritabanına (Room, CoreData, SQLite) döner.
Son olarak işletim sistemi seviyesinde TCP Fast Open veya QUIC protokolüne bakmak lazım. Google'ın geliştirdiği QUIC, UDP üzerinde çalıştığı için tek bir paket kaybı tüm bağlantıyı bloke etmez (Head-of-line blocking'i çözer). Bu yüzden Google Meet veya YouTube, cep telefonu sinyali zayıflayınca kopmaz, sadece çözünürlüğü düşürür.
Olayın özü şu: Stateful (durum bilgisi tutan) vs Stateless (durum bilgisi tutmayan) bağlantı yönetimi.
Klasik bir web tarayıcısını düşünün. Sayfayı yüklerken internetiniz gitti, modemin ışığı söndü. Tarayıcı hemen çökmez, bir süre dönen tekerleği gösterir. İnternet geri gelince sayfayı komple refresh etmek zorunda kalmaz, genelde kaldığı yerden yüklemeye çalışır. Peki buna karşılık bir SSH bağlantısı neden anında patlar? Çünkü SSH, TCP üzerinde sürekli açık kalan ve her iki tarafın da birbirinin durumunu (sequence numbers, window size) takip ettiği bir stateful tüneldir. Aradaki fiziksel bağ kopunca, TCP keep-alive mekanizması devreye girer. Eğer paket kaybı çok yüksekse veya timeout süresi aşılırsa, işletim sistemi “broken pipe” hatasını fırlatır ve uygulama çöker.
Uygulamanın crash olmasına neden olan temel faktörler:
- Timeout ve Retry Mantığının Eksikliği: Yazılımcı sadece mutlu senaryoyu (happy path) kodlamıştır. Sokete bir istek gönderir ve yanıtı sonsuza kadar bekler. Network bloke olunca thread kilitlenir, UI donar veya process supervisor tarafından öldürülür.
- Exception Handling: Özellikle Java, C# veya Python gibi dillerde, kontrol edilmemiş (unchecked) bir
SocketTimeoutExceptionveyaConnectionResethatası, uygulamanın main thread'ine kadar çıkıp işletim sisteminin “Bu program yanıt vermiyor” demesine yol açar. - Protokol Seçimi: HTTP/1.1 ve HTTP/2 farklı davranır. HTTP/1.1'de bir bağlantı kopunca tarayıcı aynı domain için yeni bir TCP el sıkışması (3-way handshake) yapabilir. Ama WebSocket gibi full-duplex bir protokol koparsa, uygulamanın manuel olarak reconnect logic çalıştırması gerekir.
Peki tolere edenler ne yapıyor?
Genelde Circuit Breaker Pattern ve Idempotency (Tekrarlanabilirlik) kullanılıyor. Örneğin bir ödeme servisine istek attınız, cevap gelmedi. Çöken uygulama “Acaba para çekildi mi çekilmedi mi?” diye sorgulamaz. Ama dayanıklı bir uygulama, işleme unique bir
idempotency-key ekler. Bağlantı geri geldiğinde aynı anahtarla isteği tekrar atar, sunucu “Bu işlemi zaten yapmıştım, işte sonucu” der. Bu, özellikle Stripe ve PayPal gibi API'lerin temelidir.Basit bir kod mantığıyla anlatmak gerekirse, çöken uygulama şöyle bir şey yapar:
Kod:
// Kötü yaklaşım
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
// Network yok -> Unhandled Promise Rejection -> Crash
Tolere eden uygulama ise şöyle yaklaşır:
Kod:
// İyi yaklaşım - Retry with Exponential Backoff
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Server Error');
return await response.json();
} catch (error) {
if (i === retries - 1) throw error;
// Her seferinde bekleme süresini katlıyoruz (1s, 2s, 4s)
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
}
Bir diğer kritik konu da Graceful Degradation. Yani uygulamanın tüm özellikleri çalışmasa bile, temel işlevini kaybetmemesi. Spotify'ı düşünün. İnternet gidince uygulama çökmez. Çevrimdışı moda geçer, cache'lenmiş şarkıları çalar. Arayüzde bir banner çıkar “Çevrimdışısınız” der. Bu, uygulamanın network layer'ının soyutlanmış olması sayesinde olur. Repository pattern ile veri katmanı izole edilir, ağ yoksa otomatik olarak local veritabanına (Room, CoreData, SQLite) döner.
Son olarak işletim sistemi seviyesinde TCP Fast Open veya QUIC protokolüne bakmak lazım. Google'ın geliştirdiği QUIC, UDP üzerinde çalıştığı için tek bir paket kaybı tüm bağlantıyı bloke etmez (Head-of-line blocking'i çözer). Bu yüzden Google Meet veya YouTube, cep telefonu sinyali zayıflayınca kopmaz, sadece çözünürlüğü düşürür.