Yüksek Bağlantı Sayısı Sorunları: netstat ve ss ile Soket Durumu Analizi
Sunucunda bir şeyler ters gittiğini hissediyorsun: uygulama yavaşlamış, bağlantılar zaman aşımına uğruyor, ya da tamamen hizmet veremiyor. İlk refleks olarak CPU ve RAM’e bakıyorsun, her şey normal görünüyor. Ama sorun ağ katmanında gizleniyor olabilir. Yüksek bağlantı sayısı, soket tükenmesi ya da yarı açık bağlantıların birikmesi, production ortamlarında en sık karşılaşılan ve en çok zaman harcatan sorunların başında geliyor. Bu noktada netstat ve ss araçları sysadmin’in en iyi dostları haline geliyor.
netstat mi, ss mi? Hangisini Kullanmalıyız?
Önce şunu netleştirelim: netstat eski, ss yeni nesil. netstat, net-tools paketinin bir parçası ve birçok modern Linux dağıtımında artık varsayılan olarak kurulu gelmiyor. ss ise iproute2 paketinin içinde geliyor ve doğrudan kernel’ın netlink arayüzünü kullandığı için hem çok daha hızlı hem de çok daha fazla bilgi sunuyor. Yüz binlerce soket açık olduğunda netstat dakikalarca çalışırken ss saniyeler içinde sonuç veriyor.
Ama şunu da söyleyeyim: production ortamlarında hâlâ netstat kurulu olan sistemler var, eski alışkanlıklar kolay gitmiyor. Bu yüzden her iki aracın da nasıl kullanıldığını bilmek gerekiyor. Ben her ikisini de anlatacağım.
Temel Durum Tespiti: İlk Bakış
Bir sunucuya bağlandığında ve “bağlantı sorunu var” dendiğinde ilk yapman gereken şey mevcut soket durumunu genel olarak görmek. Aşağıdaki komut sana toplam bağlantı sayısını duruma göre özetleyerek verir:
ss -s
Bu komutun çıktısı şuna benzer bir şey gösterir:
Total: 1842
TCP: 1756 (estab 1203, closed 412, orphaned 45, timewait 398)
Transport Total IP IPv6
RAW 0 0 0
UDP 12 8 4
TCP 1344 1102 242
INET 1356 1110 246
FRAG 0 0 0
Bu çıktıdan birkaç şeyi hemen okuyabilirsin. estab değeri aktif kurulu bağlantı sayısını gösteriyor. timewait değeri yüksekse bu bir sorunun habercisi olabilir. orphaned değeri yüksekse uygulama tarafında soket kapatma problemleri var demektir.
netstat ile benzer özet bilgiye şöyle ulaşırsın:
netstat -s | grep -E "connections|failed|reset|retransmit"
Bağlantı Durumlarını Anlamak
Sorun giderirken bağlantı durumlarını doğru okuyabilmek kritik. Aşağıdaki durumları bilmeden analiz yapamazsın:
- ESTABLISHED: Aktif, karşılıklı veri alışverişi olan bağlantı
- TIME_WAIT: Bağlantı kapatıldı, kernel hâlâ bekliyor. Varsayılan olarak 60-120 saniye sürer
- CLOSE_WAIT: Karşı taraf bağlantıyı kapattı, ama uygulama henüz soketini kapatmadı. Bu genellikle uygulama bug’ı işaretidir
- SYN_SENT: Bağlantı isteği gönderildi, henüz cevap yok
- SYN_RECV: SYN paketi alındı, SYN-ACK gönderildi, ACK bekleniyor. Yüksekse SYN flood saldırısı olabilir
- FIN_WAIT1 / FIN_WAIT2: Bağlantı kapatma sürecinin aşamaları
- LAST_ACK: Son ACK bekleniyor
- LISTEN: Servis bağlantı bekliyor
Duruma göre filtrelenmiş çıktı almak için:
ss -tan state time-wait | wc -l
ss -tan state close-wait | wc -l
ss -tan state established | wc -l
Gerçek Dünya Senaryosu 1: TIME_WAIT Patlaması
Bir web sunucusu düşünelim. Nginx arkasında bir uygulama servisi var, her dakika binlerce istek geliyor. Sabah saatlerinde yeni bağlantılar kurulmuyor, 502 Bad Gateway hataları almaya başlıyorsunuz. CPU normal, RAM normal, disk I/O normal. Ne bakacaksın?
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
Bu komut tüm TCP bağlantılarını durumlarına göre sayar ve sıralı şekilde gösterir. Eğer TIME_WAIT satırında 30.000 üzeri bir sayı görüyorsan, sorun açık.
Daha detaylı bakalım, hangi portlar arasında TIME_WAIT bağlantıları birikiyor:
ss -tan state time-wait | awk '{print $4}' | cut -d: -f2 | sort | uniq -c | sort -rn | head -20
Eğer uygulama sunucunun portu (mesela 8080) bu listede üst sıralarda görünüyorsa, Nginx ile uygulama arasındaki bağlantılar düzgün kapatılmıyor ya da yeterince hızlı geri dönüştürülemiyor demektir.
Çözüm için sysctl parametrelerine bakman gerekir:
sysctl net.ipv4.tcp_tw_reuse
sysctl net.ipv4.tcp_fin_timeout
sysctl net.ipv4.ip_local_port_range
tcp_tw_reuse parametresini 1 yaparak TIME_WAIT soketlerinin yeni bağlantılar için yeniden kullanılmasını sağlayabilirsin. tcp_fin_timeout değerini 60’tan 30’a indirerek TIME_WAIT süresini kısaltabilirsin. Bu değişiklikleri yaparken dikkatli ol, yük dengeleyicisi arkasında NAT kullanan ortamlarda tcp_tw_reuse bazen sorun çıkarabilir.
Gerçek Dünya Senaryosu 2: CLOSE_WAIT Kabusu
Bu durum TIME_WAIT’ten daha sinsi. TIME_WAIT zamanla kendiliğinden kapanır. CLOSE_WAIT ise uygulama soketini kapatana kadar bekler. Yani uygulama bug’ı olmadan bu bağlantılar kapanmaz ve zamanla dosya tanımlayıcısı (file descriptor) tükenmesine yol açar.
ss -tnp state close-wait
Bu komuttaki -p parametresi hangi process’in bu soketleri tuttuğunu da gösterir. Çıktıda şuna benzer bir şey göreceksin:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
CLOSE_WAIT 1 0 192.168.1.10:8080 10.0.0.5:54321 users:(("java",pid=12345,fd=47))
PID’i öğrendikten sonra o process’in kaç tane açık dosya tanımlayıcısı olduğunu görmek için:
ls -l /proc/12345/fd | wc -l
cat /proc/12345/limits | grep "open files"
Eğer açık fd sayısı limite yaklaşıyorsa, uygulama kısa süre içinde yeni bağlantı kabul edemez hale gelecektir. Bu noktada uygulamayı yeniden başlatmak anlık çözüm olabilir, ama asıl sorun koddaki soket kapatma eksikliğidir.
ss Komutunun İleri Seviye Kullanımı
ss aracı çok güçlü filtreleme seçenekleri sunuyor. Günlük işlerde sık kullandığım kombinasyonları paylaşayım.
Belirli bir porta bağlı tüm bağlantıları göster, process bilgisiyle birlikte:
ss -tnp sport = :443
Belirli bir uzak IP adresinden gelen tüm bağlantıları filtrele:
ss -tn dst 10.0.0.0/24
Recv-Q değeri yüksek olan, yani uygulama tarafından okunmayı bekleyen veri birikmiş soketleri bul:
ss -tn | awk '$2 > 0 {print}' | head -20
Recv-Q değeri yüksek olan soketler, uygulamanın gelen veriyi işleyemediğini gösterir. Bu CPU darboğazı, kilit (lock) sorunu ya da thread havuzunun dolmuş olmasından kaynaklanabilir.
Send-Q değeri yüksek olan soketler ise karşı tarafın veriyi okuyamadığını, yani ağ yavaşlığı ya da karşı uygulama sorunu olduğunu gösterir:
ss -tn | awk '$3 > 0 {print}' | head -20
netstat ile Klasik Analiz
netstat hâlâ pek çok ortamda kullanılıyor. Temel parametrelerini hatırlayalım:
- -t: Sadece TCP bağlantıları
- -u: Sadece UDP bağlantıları
- -n: İsimleri çözümleme, sayısal göster (훨씬 hızlı)
- -p: Process bilgisini göster (root yetkisi gerekir)
- -a: Tüm bağlantıları göster, LISTEN dahil
- -l: Sadece LISTEN durumundaki soketleri göster
Hangi process hangi portu dinliyor, sık sorulan bir soru:
netstat -tlnp
Bir porta özel bakış:
netstat -tnp | grep :3306
Bağlantı durumlarını say ve sırala, klasik netstat yöntemiyle:
netstat -tan | awk '{print $6}' | sort | uniq -c | sort -rn
SYN Kuyruğu ve Backlog Sorunu
Yüksek trafikli sistemlerde sık karşılaşılan ama fark edilmesi zor bir sorun: SYN kuyruğunun dolması. Kernel, gelen SYN paketleri için bir kuyruk tutar. Bu kuyruk dolduğunda yeni bağlantılar reddedilir ya da sessizce düşürülür.
ss -lnt
Bu komutun çıktısında Recv-Q sütunu, LISTEN durumundaki soketlerde o anki SYN kuyruğu uzunluğunu gösterir. Send-Q ise maksimum backlog değerini. Eğer Recv-Q, Send-Q’ya yaklaşıyorsa sorun var demektir.
watch -n 1 'ss -lnt | grep :80'
Bu komutu çalıştırarak Recv-Q değerini gerçek zamanlı izleyebilirsin. Değer sürekli Send-Q’nun %70-80’ine yakınsa backlog değerini artırman gerekiyor. Nginx için listen direktifindeki backlog parametresini, sistem genelinde ise net.core.somaxconn sysctl değerini artırabilirsin.
Otomatik İzleme Script’i
Manuel komutlarla tek seferlik analiz yapabilirsin, ama production’da sürekli izleme için bir script işine yarar. İşte basit ama etkili bir izleme script’i:
#!/bin/bash
LOG_FILE="/var/log/socket_monitor.log"
THRESHOLD_TIMEWAIT=20000
THRESHOLD_CLOSEWAIT=500
THRESHOLD_ESTABLISHED=10000
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
tw_count=$(ss -tan state time-wait | wc -l)
cw_count=$(ss -tan state close-wait | wc -l)
est_count=$(ss -tan state established | wc -l)
syn_recv=$(ss -tan state syn-recv | wc -l)
echo "[$timestamp] TW:$tw_count CW:$cw_count EST:$est_count SYN_RECV:$syn_recv" >> $LOG_FILE
if [ "$tw_count" -gt "$THRESHOLD_TIMEWAIT" ]; then
echo "[$timestamp] UYARI: TIME_WAIT sayisi yuksek: $tw_count" >> $LOG_FILE
ss -tan state time-wait | awk '{print $4}' | cut -d: -f2 |
sort | uniq -c | sort -rn | head -5 >> $LOG_FILE
fi
if [ "$cw_count" -gt "$THRESHOLD_CLOSEWAIT" ]; then
echo "[$timestamp] KRITIK: CLOSE_WAIT sayisi yuksek: $cw_count" >> $LOG_FILE
ss -tnp state close-wait | awk '{print $6}' | sort | uniq -c | sort -rn | head -5 >> $LOG_FILE
fi
if [ "$syn_recv" -gt 1000 ]; then
echo "[$timestamp] KRITIK: SYN_RECV yuksek, SYN flood olmali: $syn_recv" >> $LOG_FILE
fi
Bu script’i crontab’a ekleyerek her dakika çalıştırabilirsin:
* * * * * /usr/local/bin/socket_monitor.sh
Bağlantı Yoğunluğunu IP Bazında Analiz Etme
Bir sunucuya çok sayıda bağlantı açan istemcileri bulmak istiyorsun, belki bir DDoS durumu söz konusu ya da runaway bir uygulama sürekli bağlantı açıyor:
ss -tn state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
Bu komut hangi uzak IP adresinin kaç tane bağlantısı olduğunu gösterir. Eğer tek bir IP’den 500-1000 bağlantı geliyorsa bu olağandışıdır.
Benzer şeyi netstat ile yapmak istersen:
netstat -tn | awk '/ESTABLISHED/ {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
Şüpheli bir IP bulduğunda anlık olarak ss ile tüm bağlantı detaylarını inceleyebilirsin:
ss -tnp dst 192.168.1.100
UDP Soketleri ve Recv-Q Dolması
TCP kadar dramatik değil ama UDP soketlerinde de sorun yaşanabilir. UDP Recv-Q dolduğunda paketler sessizce düşer, uygulama fark bile etmez. DNS sunucuları, log toplama sistemleri ve monitoring agent’ları bu durumdan sık etkilenir.
ss -unp
Recv-Q değeri sürekli yüksekse, ya uygulama pakatleri yeteri kadar hızlı işleyemiyor ya da SO_RCVBUF değeri çok küçük. İkinci durumda:
sysctl net.core.rmem_max
sysctl net.core.rmem_default
Bu değerleri artırarak UDP alım tampon boyutunu büyütebilirsin. Ama bu semptom giderme, uygulama neden pakatleri işleyemiyor sorusunu da araştırman gerekiyor.
Kernel İstatistikleriyle Derinlemesine Analiz
ss -s çıktısının ötesine geçmek istiyorsan, kernel’ın TCP istatistik sayaçlarına doğrudan bakabilirsin:
cat /proc/net/sockstat
Bu dosyanın çıktısı şuna benzer:
sockets: used 2145
TCP: inuse 1203 orphan 45 tw 398 alloc 1344 mem 892
UDP: inuse 8 mem 4
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
orphan değeri burada önemli. Orphan soketler, bir process’e bağlı olmayan ama kernel tarafından hâlâ tutulan TCP soketleridir. Yüksek orphan sayısı genellikle hızlı bağlantı kapama gerektiren yük altında, kernel’ın soketleri temizleyemediği durumlarda oluşur. net.ipv4.tcp_max_orphans sysctl değeri bu sayıyı sınırlar, aşıldığında kernel soketleri zorla kapatır ve log’a “too many orphaned sockets” yazar.
Daha detaylı TCP istatistikleri için:
ss -ti state established | head -30
Bu komut her bağlantı için RTT, yeniden gönderme sayısı, pencere boyutu gibi TCP seviyesi istatistikleri gösterir. Yüksek retransmit değerleri ağ kalitesi sorununa işaret eder.
Sorun Giderme Akışı
Yüksek bağlantı sayısı sorunuyla karşılaştığında izlemen gereken genel akış şu şekilde:
- Önce
ss -sile genel duruma bak, hangi durum öne çıkıyor? - TIME_WAIT yüksekse: kaynak port tükenmesi mi, yoksa yavaş kapanma mı?
ip_local_port_rangevetcp_fin_timeoutdeğerlerini kontrol et - CLOSE_WAIT yüksekse:
ss -tnp state close-waitile hangi uygulama tuttuğunu bul, o uygulamanın kod gözden geçirilmesi şart - ESTABLISHED yüksekse: meşru trafik mi yoksa bağlantı sızıntısı mı? IP bazlı analiz yap
- SYN_RECV yüksekse: SYN flood ihtimalini değerlendir,
syncookies‘i kontrol et (sysctl net.ipv4.tcp_syncookies) - Recv-Q doluysa: uygulama performans sorunu, thread havuzu ya da işlem gecikmesi araştır
- Orphan soket yüksekse: sistem geneli yük ve
tcp_max_orphansdeğerini değerlendir
Sonuç
Ağ bağlantı sorunları, sistem yöneticilerinin en çok zaman harcadığı konulardan biri. Bunun temel nedeni, sorunun birçok farklı katmanda gizlenebilmesi. Uygulama seviyesi, kernel parametreleri, ağ altyapısı ya da karşı taraf sistemler: hepsi birbiriyle bağlantılı.
ss ve netstat, bu labirentin içinde sana net bir harita sunuyor. Bağlantı durumlarını doğru okumayı öğrendiğinde, TIME_WAIT ve CLOSE_WAIT arasındaki farkı kavradığında ve Recv-Q/Send-Q değerlerinin ne anlattığını anladığında, sorun giderme süresi dramatik şekilde kısalıyor.
Asıl önemli olan şu: bu araçları sadece sorun çıktığında değil, periyodik olarak kullan. Sisteminizin normal durumunda bu sayaçların ne gösterdiğini biliyor olmak, anormal durumu çok daha hızlı fark etmeni sağlar. Monitoring stack’ine soket durum istatistiklerini ekle, baseline oluştur ve sapmalar olduğunda haberdar ol. Yangın çıktıktan sonra koşmak yerine dumanı önceden görmek her zaman daha iyidir.
