Bölüm 58:Kapsülleme Çözme
Ağlar'a “Sen”i Katmak yazısının parçası: adres çubuğuna yazdığın tek bir isteğin peşinden bakırla fiberin fiziğine kadar inen uzun bir teknik yolculuk.
Tüm bölümler
- Giriş
- Adres Çubuğundan İsteğe
- Paket Anahtarlamalı Yol
- İsimden Adrese
- Önbellek, Tazelik ve Güven
- Port Numarası ve Soket
- Bağlantısız Taşıma: UDP
- Üç Adımlı El Sıkışma
- Simetrik Şifreleme
- Açık Anahtarlı Kriptografi
- TLS El Sıkışması
- Sertifika Zinciri
- HTTP Mesajının Anatomisi
- Durum, Çerez ve Oturum
- HTTP/2'den HTTP/3'e
- İçerik Dağıtım Ağları
- Diğer Uygulama Protokolleri
- Katmanlı Mimari
- Kapsülleme ve Başlıklar
- Paket Yakalama ve Çözümleme
- Ağ Arayüz Kartı
- Fiziksel Adresleme
- Hata Sezme ve CRC
- Adres Çözümleme: ARP
- Anahtarlama ve Ortam Erişimi
- Ağ Topolojileri
- Sanal Yerel Ağlar
- Kablosuz Erişim: 802.11
- Radyo Kanalı ve Kapasite
- Kablosuz Ağ Güvenliği
- Hücresel Ağlar
- Spektrum ve Kuşaklar
- Hareketlilik ve Aktarma
- Adres Kiralama: DHCP
- Adresin Anatomisi
- Adres Tükenmesi ve IPv6
- Yönlendirici Mimarisi
- Kuyruk Yönetimi
- Cihaz Yapılandırma
- Yönlendirme Protokolleri
- Kontrol Düzlemi ve SDN
- Ağ İzleme ve Yönetimi
- Alanlar Arası Yönlendirme
- Adres Çevirisi
- Ara Kutular
- Tünelleme ve IPsec
- Güvenlik Duvarları
- Operatör ve Metro Ağları
- Bitten Sinyale
- Çoklama Teknikleri
- İletim Ortamları
- Kablo Sonlandırma
- Fiber Optik İletim
- Bakır Erişim Ağı: DSL
- Pasif Optik Ağlar
- Kablo Erişim Ağları
- Denizaltı Kabloları
- Veri Merkezi Ağları
- Kapsülleme Çözme
- Güvenilir Aktarım
- Tıkanıklık Denetimi
- Trafik Çözümleme
- Gecikme Bütçesi
- Son Söz
Paket rafın tepesindeki anahtardan geçip içerideki sunucunun kartına düştü. Makine onu henüz okumadı; okumak için önce soyması gerekiyor.
Gidişte takılan her zarf, gelişte ters sırayla açılıyor. Kartın elinde şimdilik bir bit dizisi var. Senin yazdığın satır oradan nasıl çıkacak?
Kart çerçeveyi neye bakarak kabul ediyor?
Kablodan gelen bitler karta sırayla düşüyor. Çerçeveyi baştan okumaya kalksan ilk göreceğin şey veri olmaz: önde 7 baytlık bir önsöz ve 1 baytlık SFD duruyor. Bu 8 bayt çerçeve uzunluğu hesabına girmiyor; işleri tek, alıcının saatini gelen bitlerin ritmine oturtmak.
Kart kablodaki her çerçeveyi en azından hedef adres alanına kadar okuyor, adres kendisine ait değilse gerisini okumadan bırakıyordu.
Çerçevenin sonunda ise 4 baytlık bir FCS alanı buluyorsun; gönderen onu yola çıkmadan önce yazmış oluyor. Döngüsel artıklık denetimi sezme ile düzeltme arasına bir sınır çekiyordu; alıcı burada aynı hesabı tekrarlayıp sonucu alandaki değerle karşılaştırıyor.
Sıraya dikkat et, çünkü bağlayıcı. Çerçeve alındığında önce FCS sınanıyor; sonuç tutmuyorsa hedef MAC adresine hiç bakılmadan çerçeve atılıyor. Adres elemesini bitler akarken yapılan bir hızlandırma olarak düşün; kabul kararını asıl veren şey sağlama.
Gönderene haber vermenin de bir yolu yok, ve sebebi düşündüğünden basit: hasar görmüş olabilecek alanlardan biri Kaynak Adres alanının kendisi. Haberin gideceği adres de şüphelilerin arasında. Çerçeve bu yüzden sessizce düşüyor.
İki sınamadan da geçen çerçeve karta ait tampona yazılıyor; ancak ondan sonra üst katmanların gündemine girebiliyor. Ağ kartı kablonun ucunda duran ayrı bir işlemciydi; halka tampona düşenler işte bunlar. Elenen çerçeve ise hiçbir yere yazılmıyor; makinenin geri kalanı onun geldiğini bile duymuyor. Sayaç tutmasan varlığından haberin olmaz. Bu kabul kararı, ters kapsülleme zincirinin ilk halkası.
Her zarf açılırken aynı soruyu cevaplıyor
Kart zarfı atmadan önce bir alanı daha okuyor. Ethernet adreslerinin hemen ardından gelen 16 bitlik tür alanına bakıyor ve içeride hangi üst katman protokolünün durduğunu oradan öğreniyor. Alıcı paketi hangi yığına vereceğini buradan öğreniyor.
Port numarasıyla tanıdığın çoklama çözmenin burada her katmanda bir kez tekrarlandığını göreceksin. Sorulan şey her seferinde aynı kalıyor: içindeki nedir? Zarfların bu sırayla açılmasına ters kapsülleme deniyor.
Kargo benzetmesinde her görevli yalnızca kendi etiketine bakıyordu; soyulmada da her katman kendi etiketini okuyup içindekini bir üstüne uzatıyor. Benzetme yine aynı yerde bitiyor: kimse üsttekinin etiketini yorumlamıyor.
Kapsülleme merdivenini inerken saydığın 18 baytlık sabit zarf burada ters yönde açılıyor; kartın kabul aralığı da o tablodan çıkıyor, 64 ile 1.518 bayt. Soyma bittiğinde kenara atılan başlık toplamı 58 bayt eder: 18 baytlık çerçeve zarfı ve 20’şer baytlık IP ile TCP başlıkları. Tam boy bir çerçevenin %3,8’i. En küçük çerçevede aynı hesap acımasız çalışıyor: 46 baytlık veri alanının 40 baytını iki başlık yiyor, uygulamaya 6 bayt kalıyor. Küçük paket göndermenin neden pahalı olduğunu bir kez bu sayının üstünde gör; bir daha unutmazsın.
IP başlığında aynı soruyu 8 bitlik Protokol alanı cevaplıyor. Süzme kuralları yazarken kullandığın numaralar — TCP 6, UDP 17 — burada ikinci zarfı kimin açacağını söylüyor. Alan bir sayı taşıyor, protokolün adını değil.
Aynı soruyu üçüncü kez taşıma başlığında soruyorsun ve cevabı hedef port veriyor. Bu üçüncü cevap artık bir protokolü değil, o makinede çalışan tek bir uygulamayı gösteriyor.
Hedef uç sistem de tıpkı bir yönlendirici gibi datagramı ağ sargısından çıkarıyor. Fark tek bir adımda: yönlendirici onu yeniden sarıyor, hedef makine sarmıyor.
IPv4 başlığının kendi sağlaması 16 bit ve yalnızca başlığa uygulanıyor; veri alanı bu hesaba hiç girmiyor. TTL ile parçalanma alanları yolda değiştiği için sağlamayı her yönlendirici yeniden doğrulayıp yeniden hesaplıyor. Yani hedefe varan sağlama değerini gönderen yazmamış oluyor; onu yolun son yönlendiricisi yazıyor.
Şimdi iki sağlamayı yan yana koyalım, çünkü güçleri hiç aynı değil. FCS 32 bitlik olduğu için 4.294.967.296 farklı sonuç üretiyor; bozulmuş bir çerçevenin doğru değeri rastgele tutturma olasılığı kabaca %0,000000023 kalıyor. Başlıktaki 16 bitlik alanda aynı olasılık %0,0015’e çıkıyor. Ucuz olan alan, kabloyu değil yolda değişen başlığı korumak için seçilmiş.
Datagram parçalanmışsa birleştirmeyi yalnızca burada göreceksin; ara yönlendiriciler parçaları taşıyor ama toplamıyor. Aynı kimlik değerini taşıyan parçalar geldikçe veri alanları tampondaki doğru konuma yerleşiyor. Birleşme, ofset sıfırdan başlayan kesintisiz bir dizi oluştuğunda ve More bayrağı sıfır olan parça geldiğinde tamamlanıyor. Bir parça hiç gelmezse zamanlayıcı doluyor ve eldeki bütün parçalar atılıyor; sekiz parçadan yedisi elinde olsa bile hiçbir işine yaramıyor.
Bir datagramı yolun sonuna getirmeyen üç sebep var ve üçü de bu bölümde geçti: ömrünün dolması, tıkanıklık, ve sağlamanın tutmaması.
Segment doğru sürece nasıl teslim ediliyor?
Taşıma katmanı makineleri değil süreçleri birbirine bağlıyor. Süreç, bir makinede çalışmakta olan bir program örneği; şu anda kendi makinende yüzlercesi birden koşuyor.
Yığındaki her katmanın kendi kimlik kavramı var ve üçünü de tanıyorsun: kart MAC adresiyle, düğüm IP adresiyle, uygulama da port numarasıyla anılıyor. Katmanlı mimarinin arayüz sözleşmesi gereği her kimlik kendi katmanının başlığında taşınıyor.
Soket bu kimliklerin üçünü tek adda topluyor: taşıma katmanı protokolü, IP adresi ve port numarası. MAC adresini o üçlünün içinde arama; çerçeve çoktan soyuldu.
Konuşmayı tanıyan four-tuple burada bir değer daha kazanıyor. Taşıma protokolü de kimliğin parçası; TCP’nin protokol numarası 6 ve four-tuple’ı five-tuple’a (beşli) çıkaran değer o. Somut vakada sunucu 203.0.113.10 üzerinde 443 numaralı portu dinliyor, istemci ise 198.51.100.7 üzerinden 51844 numaralı portla bağlanıyor.
UDP tarafında alıcının üç işi var: IP’den segmenti almak, sağlama alanını denetlemek ve mesajı soket üzerinden uygulamaya çıkarmak. Sağlamanın kapsamı taşıma başlığıyla sınırlı kalmıyor; UDP başlık alanlarının yanında IP adreslerini de içine katıyor.
Teslim noktasında bir tampon buluyorsun. TCP alıcı tamponunun boyutunu soket seçenekleriyle ayarlayabiliyorsun; tipik varsayılanı 4.096 bayt. Bunun ne kadar dar olduğunu görmek için böl: 1.460 baytlık tam boy bir segmentten oraya yalnızca 2,8 tanesi sığıyor. Birçok işletim sistemi bu değeri kendiliğinden büyütüyor.
Tamponu iki uç birden işletiyor: ağ katmanı içine yazıyor, uygulama da okuyarak boşaltıyor. Uygulaman yavaş okursa boş yer eriyor ve alıcı kalanı TCP başlığındaki rwnd alanıyla karşıya bildiriyor.
Erimeyi çıplak gözle de görebilirsin. netstat -tan çıktısındaki Recv-Q sütunu, uygulamanın henüz almadığı veriyi bayt olarak gösteriyor:
$ netstat -tan
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 32120 0 203.0.113.10:443 198.51.100.7:51844 ESTABLISHEDSunucu yavaşladıkça o sütun büyüyor. Senin isteğin de bu satırın kuyruğunda bekliyor ve sunucu süreci onu oradan okuyor.
Aynı anda yüz bin kişi varsa?
Buraya kadar tek bir bağlantıyı izledik. Gerçek bir sunucuda o satırın yanında on binlerce satır daha var ve bu, kitabın şimdiye kadar sormadığı bir soruyu doğuruyor: tek bir makine bu kadar soketi nasıl taşıyor?
Kapıda iki kuyruk var, ikisi de çekirdekte. Gelen SYN paketleri yarı açık kuyruğa düşüyor; bu kuyruğun taşırılması bir saldırı yöntemiydi. El sıkışma tamamlanınca bağlantı ikinci kuyruğa, kabul kuyruğuna geçiyor ve orada uygulamanın onu almasını bekliyor. Bu kuyruğun derinliğini uygulama kendisi bildiriyor. Uygulama almakta geri kalırsa kuyruk dolar ve yeni bağlantılar sessizce düşer — istemci tarafında bu, “sunucu var ama cevap vermiyor” diye görünür.
Asıl soru kabul edildikten sonra başlıyor. En sade tasarım her bağlantıya bir iş parçacığı vermek: kod okunaklı olur, çünkü her parçacık kendi bağlantısını baştan sona takip eder. On bin bağlantıda çöküyor. Her parçacığın kendi yığını var, ve çekirdeğin on bin parçacık arasında sıra dağıtması işin kendisinden pahalıya geliyor. Bu duvarın literatürdeki adı C10K problemi.
Çıkış yolu tasarımı tersine çevirmekten geçti: her bağlantıya bir parçacık verme, tek bir parçacığa bütün bağlantıları sor. Uygulama çekirdeğe “şu soketlerden hangisinde okunacak veri var?” diye soruyor ve yalnızca hazır olanlarla ilgileniyor. Buna olay döngüsü deniyor.
Sorunun nasıl sorulduğu ise otuz yıllık bir iyileştirme hikâyesi ve tek bir kusurun etrafında dönüyor.
İlk yöntemler her turda bütün listeyi çekirdeğe veriyor ve çekirdek onu baştan sona tarıyordu. Yüz bin soketin durumunu sormak, yüz bin soketi tek tek yoklamak demekti — oysa o an belki üçünde veri vardı. Maliyet soket sayısıyla büyüyordu.
Bugünkü yöntem listeyi bir kez kaydediyor ve her turda yalnızca hazır olanları döndürüyor. İş artık soket sayısıyla değil olay sayısıyla orantılı: doksan dokuz bin dokuz yüz doksan yedi sessiz soket hiçbir maliyet üretmiyor. Bugün bildiğin her yüksek başarımlı sunucu bu kapıdan geçiyor.
Tek bir olay döngüsü de tek bir işlemci çekirdeğini doldurabiliyor. İkinci hamle aynı kapıya birden çok bekleyen koymak: çekirdek gelen bağlantıları bunlar arasında kendisi dağıtıyor ve her işlemci çekirdeğine ayrı bir kabul kuyruğu düşüyor.
Kalan darboğaz veriyi kopyalamakta. Bir dosyayı ağa göndermek klasik yolla dört kopya istiyor: diskten çekirdeğe, çekirdekten uygulamaya, uygulamadan çekirdeğe, çekirdekten karta. Ortadaki iki kopya tamamen gereksiz — uygulama veriye bakmıyor bile. Modern işletim sistemleri onları atlayıp veriyi çekirdeğin içinden doğrudan karta geçirebiliyor; yöntemin adı sıfır kopya. Statik dosya sunucularının bu kadar az işlemci harcamasının sebebi bu.
Son darboğaz ağ kartının kendisinde. Kart bütün gelen trafiği tek bir kesme hattından bildirirse, o kesmeyi işleyen tek bir çekirdek dolar ve makinenin geri kalanı boş kalır. Modern kartlar bu yüzden çok kuyruklu: gelen her paketin soket four-tuple’ından bir özet çıkarıp paketi o özete karşılık gelen kuyruğa koyuyorlar ve her kuyruk ayrı bir çekirdeğe bağlanıyor. Yöntemin adı alış tarafı ölçekleme. Aynı akışın bütün paketleri hep aynı çekirdeğe düşüyor, böylece hem önbellek ısınıyor hem de sıra bozulmuyor.
Dördü birlikte okunduğunda ortaya tek bir cümle çıkıyor: ölçek, işi hızlandırarak değil gereksiz işi kaldırarak geliyor. Taranmayan liste, kopyalanmayan bayt, beklemeyen parçacık.
Özet
Peki, ne öğrendik?
- Adres elemesi. Elemeden geçen çerçeve karta ait tampona yazılıyor, elenen çerçeve ise hiçbir yere yazılmıyor.
- Sağlama önceliği. FCS tutmayan çerçeve hedef MAC adresine hiç bakılmadan atılıyor; kabul kararının sahibi adres değil, sağlama.
- Sessiz düşüş. Bozuk çerçeve için gönderene haber gitmiyor, çünkü hasarlı olabilecek alanlardan biri Kaynak Adres alanının kendisi.
- Çoklama çözme. Tür alanı, Protokol alanı ve hedef portu aynı soruyu üç kez cevaplıyor: bu zarfın içindekini kim alacak?
- Teslim kimliği. Segmenti doğru sürece ulaştıran şey adreslerle portların birleşimi, ve protokolle birlikte bu kimlik beş değere çıkıyor.
- Ölçek gereksiz işi kaldırmaktan geliyor. Bağlantı başına bir iş parçacığı on binde çöküyor; olay bildirimi soket sayısı yerine olay sayısıyla çalışıyor, sıfır kopya ara kopyaları atlıyor, çok kuyruklu kart kesmeyi çekirdeklere dağıtıyor.
Sunucu süreci ilk satırı okudu ve yanıtı hazırladı. Bu sefer geri dönecek olan küçük bir istek değil, iki yüz parçaya bölünecek koca bir dosya. Parçalardan biri yolda kaybolursa gönderen bunu kimden öğrenecek?
59. bölüme devam et: Güvenilir Aktarım