Ana içeriğe geç

Bölüm 59:Güvenilir Aktarım

10 dakikalık okumaGüncelleme:

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
  1. Giriş
  2. Adres Çubuğundan İsteğe
  3. Paket Anahtarlamalı Yol
  4. İsimden Adrese
  5. Önbellek, Tazelik ve Güven
  6. Port Numarası ve Soket
  7. Bağlantısız Taşıma: UDP
  8. Üç Adımlı El Sıkışma
  9. Simetrik Şifreleme
  10. Açık Anahtarlı Kriptografi
  11. TLS El Sıkışması
  12. Sertifika Zinciri
  13. HTTP Mesajının Anatomisi
  14. Durum, Çerez ve Oturum
  15. HTTP/2'den HTTP/3'e
  16. İçerik Dağıtım Ağları
  17. Diğer Uygulama Protokolleri
  18. Katmanlı Mimari
  19. Kapsülleme ve Başlıklar
  20. Paket Yakalama ve Çözümleme
  21. Ağ Arayüz Kartı
  22. Fiziksel Adresleme
  23. Hata Sezme ve CRC
  24. Adres Çözümleme: ARP
  25. Anahtarlama ve Ortam Erişimi
  26. Ağ Topolojileri
  27. Sanal Yerel Ağlar
  28. Kablosuz Erişim: 802.11
  29. Radyo Kanalı ve Kapasite
  30. Kablosuz Ağ Güvenliği
  31. Hücresel Ağlar
  32. Spektrum ve Kuşaklar
  33. Hareketlilik ve Aktarma
  34. Adres Kiralama: DHCP
  35. Adresin Anatomisi
  36. Adres Tükenmesi ve IPv6
  37. Yönlendirici Mimarisi
  38. Kuyruk Yönetimi
  39. Cihaz Yapılandırma
  40. Yönlendirme Protokolleri
  41. Kontrol Düzlemi ve SDN
  42. Ağ İzleme ve Yönetimi
  43. Alanlar Arası Yönlendirme
  44. Adres Çevirisi
  45. Ara Kutular
  46. Tünelleme ve IPsec
  47. Güvenlik Duvarları
  48. Operatör ve Metro Ağları
  49. Bitten Sinyale
  50. Çoklama Teknikleri
  51. İletim Ortamları
  52. Kablo Sonlandırma
  53. Fiber Optik İletim
  54. Bakır Erişim Ağı: DSL
  55. Pasif Optik Ağlar
  56. Kablo Erişim Ağları
  57. Denizaltı Kabloları
  58. Veri Merkezi Ağları
  59. Kapsülleme Çözme
  60. Güvenilir Aktarım
  61. Tıkanıklık Denetimi
  62. Trafik Çözümleme
  63. Gecikme Bütçesi
  64. Son Söz

Sunucu yanıtı hazırladı ve geri gelen şey artık küçük bir istek değil. Karşıya geçecek gövde 292.000 bayt, yani 1.460 baytlık iki yüz parça. Değişen tek şey boyut gibi duruyor.

Değişen şey boyutun getirdiği sorun. Parçalardan biri yolda kayboluyor. Gönderen bunu kimden öğrenecek?

Her oktetin bir numarası var

TCP’nin verdiği söz üç parçalı: güvenilir, sırası bozulmamış ve mesaj sınırı olmayan bir bayt akışı. Bu sözün altındaki mekanizma tek bir fikirden çıkıyor. Bağlantı üzerinden giden her oktetin bir sıra numarası var. Standardın en temel tasarım kararı bu, ve bölümün geri kalanındaki her mekanizma ondan türüyor.

Numara segmentleri saymıyor, baytları sayıyor. Başlıktaki alan, o segmentin ilk baytının akış içindeki numarasını taşır. Yanıtın ilk segmenti 7.000 ile çıkıyorsa ikincisi 8.460, üçüncüsü 9.920, dördüncüsü 11.380 olur. Aradaki fark hep 1.460.

O 1.460 sayısı da havadan gelmiyor. MTU’dan iki başlığı düşünce kalan tam boy segment bu; kapsülleme merdiveninin taşımaya bıraktığı yer.

Onay numarasını okurken sık yapılan bir hata var: onu alınan son bayt sanmak. Gösterdiği şey bir sonraki beklenen bayt. Üstelik birikimli çalışıyor; 9.920 onayı, 9.920 hariç ondan öncekilerin tamamının alındığını söylüyor. Bu kural kopya saptamayı bedavaya getirir, çünkü yeniden gönderim varken aynı baytı ikinci kez alan taraf onu numarasından tanır.

Telefonda birine uzun bir adres yazdırdığını düşün. Karşı taraf her satırın sonunda “kapı numarasına kadar aldım, devamı?” der. Söylediği şey aldığının sonu değil, beklediğinin başıdır. Haritalama şurada: o cümle onay numarasıdır, “devamı” dediği yer beklenen bayttır, aynı cümleyi ikinci kez duyman aradan bir şey düştüğünün işaretidir. Benzetme şurada biter: karşındaki insan söylediğini anlar, TCP yalnızca sayar.

Sıra uzayı 0 ile 2^32 - 1 arasındadır ve bütün aritmetik 2^32 modunda yürür. Havuzda 4.294.967.296 numara var. Sonuncudan sonra sayaç başa döner. Başlıktaki alan genişlikleri de bu muhasebeyi doğruluyor:

sıra numarası    32 bit  (4 bayt)   segmentin ilk baytının numarası
onay numarası    32 bit  (4 bayt)   beklenen bir sonraki bayt
pencere          16 bit  (2 bayt)   alıcının o an kabul edebileceği bayt

Havuzun sonlu olması gerçek bir sınır koyar. Sayaç başa dönmeden önce eski bir kopyanın ağda ölmüş olması gerekir. Hızı bilince süre çıkar. 1 Gbit/s’lik bir akışta saniyede 125 MB gider; havuz 34,4 saniyede başa döner. Numaranın bir sonraki tura kalan ömrü, segmentin ağda yaşayabileceği en uzun süreden kısa olamaz.

Başlangıç sıra numarası her bağlantıda yeniden üretiliyordu; o numaranın neyi saydığı burada çalışıyor.

Dur ve bekle hattı boş bırakıyor

Güvenilirlik tek başına hattı verimli kullanmaya yetmiyor. Dur ve bekle protokolü doğru çalışır: gönderen bir segment yollar, onayı bekler, sonra bir tane daha yollar. Boruda aynı anda tek segment olur.

Bedeli hesaplanabilir. 1.460 baytlık bir segment 100 Mbit/s’lik bir hatta 116,8 µs’de çıkar. Gidiş-dönüş 30 ms ise gönderen her segment için o kadar bekler. Hat zamanının yalnızca %0,39’unda çalışır.

Çözüm boru hattıdır: gönderen onay beklemeden birden çok segmenti havada tutar. Üç paketlik bir boru hat kullanımını üç katına çıkarır. Bedeli de var. Sıra numarası aralığı genişlemek ve iki uçta da tampon açılmak zorundadır.

Havada tutulabilen o aralığın adı kayan penceredir. Gönderenin sıra uzayı dört bölgeye ayrılır: onaylanmış baytlar, gönderilmiş ama onaylanmamış baytlar, pencerede olup henüz gönderilmemiş baytlar ve pencere dışı. Sol kenarı tutan değişkenin adı SND.UNA’dır; alıcı tarafta alma penceresinin sol kenarı RCV.NXT’tir.

Gönderen uçuştaki segmentlerin kopyalarını bir yeniden gönderim kuyruğunda saklar. Onay geldiği anda kopya atılır ve sol kenar sağa kayar. Pencereyi kaydıran şey onaydır. Atma kuralı da kesindir: bir segmentin sıra numarası ile uzunluğunun toplamı gelen onayı geçmiyorsa o segment kuyruktan düşer.

Sunucu 203.0.113.10, istemci 198.51.100.20 olsun. SND.UNA 7.000’de duruyor ve alıcı 11.680 baytlık pencere ilan etti. Gönderen 18.680’e kadar yeni bayt yollayabilir, yani sekiz tam boy segment. 8.460 onayı gelince sol kenar oraya kayar. Sağ uç 20.140’a çıkar; ilan değişmese bile pencere sağa yürüdü.

Pencerenin iki kenarının onay geldikçe nasıl yürüdüğünü izleyelim:

Gönderenin sıra uzayı ve pencerenin kayması
sıra uzayısegment 1segment 2segment 3segment 4segment 5segment 67.0008.4609.92011.380pencereonaylanmışgönderildi, onaylanmadıgönderilebilirpencere dışıyeni sol kenar: onay 9.920pencere bir segment sağa kaydı
Akış baytlara numaralanıyor. Yanıt gövdesi 1.460 baytlık segmentlere bölünüyor ve her segmentin ilk baytı bir sıra numarası taşıyor. Numara segmenti değil, baytı sayıyor; aradaki fark her seferinde segmentin yükü kadar.
  1. Akış baytlara numaralanıyor. Yanıt gövdesi 1.460 baytlık segmentlere bölünüyor ve her segmentin ilk baytı bir sıra numarası taşıyor. Numara segmenti değil, baytı sayıyor; aradaki fark her seferinde segmentin yükü kadar.
  2. Pencere üç segmenti kapsıyor. Gönderen akışın tamamını bir anda yollayamıyor. Alıcının ilan ettiği pencere, o an gönderilmesine izin verilen aralığı işaretliyor; buradaki örnekte üç segment genişliğinde.
  3. Uzay dört bölgeye ayrılıyor. Solda onayı gelmiş baytlar duruyor. Pencerenin içinde gönderilmiş ama onaylanmamış segmentlerle henüz gönderilmemiş bir segment var; sağda ise izin sınırının ötesi kalıyor.
  4. Onay sol kenarı ileri itiyor. 9.920 onayı geliyor ve ondan önceki bütün baytları tek seferde kapatıyor. Uçuştaki ilk segment onaylanmış bölgeye düşüyor, sol kenar da onun bittiği yere taşınıyor.
  5. Pencere sağa kayıyor. Sol kenar ilerleyince sağ kenar da aynı miktarda ilerliyor ve daha önce sınırın dışında kalan segment gönderilebilir hâle geliyor. Pencereyi kaydıran şey onayın kendisi.

Gelen çerçevenin sağlamasına bakılıyor ve veri soket kuyruğuna bırakılıyordu; buradaki eksik bayt o denetimin yakaladığı bir bozulma değildir.

Sayaç ne kadar bekleyecek?

Kaybı saptamanın ilk yolu gönderendeki bir sayaçtır; süresinin adı yeniden gönderim zaman aşımıdır. Süre gidiş-dönüşten uzun olmalı. Ama gidiş-dönüş sabit değildir. Kısa seçersen ortada kayıp yokken gereksiz kopyalar üretirsin; uzun seçersen gerçek kayba geç tepki verirsin.

Ölçümün kendisi basit. Örnek gidiş-dönüş süresi, bir segmentin gönderilmesiyle onayının gelmesi arasında geçen süredir. Kestirim tek ölçümden çıkmaz. Üstel ağırlıklı hareketli ortalama kullanılır ve eski örneklerin etkisi hızla söner. Ağırlıklar sabittir: kestirim için 1/8, sapma için 1/4.

Üstüne bir güvenlik payı biner. RFC 6298 payı sapmanın dört katı olarak tanımlar. İlk ölçümün kendine ait bir kuralı var. Kestirim doğrudan ölçümün kendisi olur, sapma da onun yarısı. Hiç ölçüm yokken gönderen 1 saniyelik başlangıç değeriyle çalışır.

İlk ölçümün 32 ms geldiğini varsay: kestirim 32 ms, sapma 16 ms, pay da 64 ms olur. Ham zaman aşımı 96 ms çıkar. Ama taban 1 saniyedir ve her hesaba uygulanır: değer onun altına düşerse yukarı yuvarlanır. İkinci ölçüm 30 ms gelsin. Kestirim 31,75 ms’ye, sapma 12,5 ms’ye iner, ham değer 81,75 ms olur ve taban onu yine 1 saniyeye çeker. Zaman aşımına üst sınır konabilir, ama o sınır 60 saniyenin altına inemez.

Bir tuzak var. Karn kuralı yeniden gönderilmiş bir segmentten örnek almayı yasaklar; gelen onayın hangi kopyaya ait olduğu belirsizdir. Üstel geri çekilme de buradan gelir: sayaç her dolduğunda değer ikiye katlanır ve ardışık denemeler 1, 2, 4, 8, 16, 32 saniye olur.

Gönderen her segmente ayrı sayaç kurmaz. Tek sayaç en eski onaylanmamış segment için işler ve dolunca yalnızca o segment yeniden gider. Bekleyen bütün veri onaylandığında zamanlayıcı kapanır, yeni veri çıkınca yeniden kurulur.

Kuyruk gecikmesi trafikle birlikte oynuyordu; zaman aşımının sabit bir sayı olamamasının sebebi tam olarak o oynama.

Onay yinelenince beklemenin anlamı kalmıyor

Sayaç, kaybı yakalamanın tek yolu olarak kalmıyor. İkinci yol alıcının kendi davranışından çıkar.

Sırayla gelen ilk segment hemen onaylanmaz. Alıcı bir sonrakini bekler ve ikisini tek onayla kapatmayı dener; bu beklemenin adı gecikmeli onaydır. Sırada bir boşluk açılınca o bekleme hemen düşer.

alıcıya gelenalıcının yaptığı
sırayla gelen ilk segmentonayı en fazla 500 ms geciktirir
sırayla gelen ikinci segmentikisini tek onayla kapatır
sırası atlanmış segmentbeklediği baytın onayını hemen yineler
boşluğu dolduran segmentboşluğun ötesini de kapatan onayı yollar

Boşluk kapanana kadar alıcı hep aynı onayı yollar; gönderen o numarayı üst üste görür. Üç yinelenen onay geldiğinde sayacı beklemez. Hızlı yeniden gönderim en küçük sıra numaralı onaylanmamış segmenti hemen yola çıkarır. Eşiğin üç seçilmesinin sebebi ağın segmentleri yeniden sıralamasıdır; yinelenen onay her zaman kayıp anlamına gelmez ve daha düşük bir eşik yöntemi boşuna tetiklerdi.

Kazanç ölçülebilir. 30 ms’lik bir yolda 1 saniyelik zaman aşımını beklemek yerine yaklaşık 33 kat erken tepki verirsin. Ayrı bir olumsuz onay mesajına da gerek kalmaz; yinelenen onay gönderende aynı işi görür.

Her eksik onay yeniden gönderim doğurmaz. 8.460 onayının kaybolduğunu düşün. 9.920 onayı sayaç dolmadan gelirse boşluk kapanır ve hiçbir segment tekrar gitmez.

Onay, karşıya akan bir veri segmentinin başlığına da binebilir; bu birleştirmenin adı piggybacking. Kopya bir segment vardığında alıcı onu sessizce atmaz. Kendi onayının kaybolduğunu varsayıp kopyayı da onaylar.

Gecikmeli onayın bedeli de var. Her segmenti anında onaylamak ağa veri taşımayan segmentler ekler. Beklemek o yükü kısar ama gönderenin kestirimini bozar; ölçülen süreye alıcının bekleyişi de karışır.

Derinleşmeİki iyi niyetli optimizasyon çarpışırsa ne olur?

Alıcı tarafındaki gecikmeli onayın gönderen tarafında bir kardeşi var: Nagle algoritması. İkisi de aynı derdi çözüyor — küçük segmentlerin ağa gereksiz yük bindirmesi. Hesapladığımız uç vakayı hatırla: tek bir baytlık veri telde 84 bayt yer kaplıyor, yani zarfın payı %98,8.

Nagle’ın kuralı tek cümle: onaylanmamış veri varken küçük bir segment gönderme, biriktir. Elde bir tam segment birikirse ya da bekleyen bütün onaylar gelirse gönder. Uzak bir makinede metin düzenlerken her tuş vuruşunun ayrı bir pakete binmesini böyle engelliyor.

Şimdi ikisini yan yana koy. Gönderen küçük bir parça yolladı ve Nagle yüzünden ikinciyi göndermek için onay bekliyor. Alıcı ise gecikmeli onay yüzünden, ikinci segmenti bekleyerek onayı geciktiriyor. İki taraf birbirini bekliyor.

Kilidi kıran şey alıcının zamanlayıcısı: gecikmeli onay en fazla beklediği kadar bekleyip onayı yolluyor. Linux’ta bu genellikle 40 ms. Yani hiçbir kayıp, hiçbir tıkanıklık olmadan, tamamen boş bir hatta, iki iyi niyetli optimizasyon yüzünden 40 milisaniyelik bir duraklama doğuyor. Küçük istek-cevap çiftleriyle çalışan bir uygulamada bu, saniyede 25 işlem demek.

Çare uygulamanın elinde: tek bir soket ayarıyla Nagle kapatılabiliyor ve gecikmeye duyarlı hemen her kütüphane bunu varsayılan olarak yapıyor. Doğru hamle de bu, çünkü bugün küçük segment yükü 1980’lerdeki kadar önemli değil; gecikme ise daha önemli.

Birikimli onay bir şeyi söyleyemiyor

Yeniden gönderimin kapsamı ayrı bir karardır ve iki uçtaki klasik yaklaşımın adları var. N geri git’te bir zaman aşımı penceredeki bütün üst numaralı segmentleri de geri yollar; alıcı sırası bozuk geleni hiç tamponlamaz, bu yüzden alıcı basit ama hat israf edilir. Seçici tekrarda yalnızca eksik olan gider ve alıcı sırasızları tamponunda tutar; hat verimli ama alıcı karmaşıklaşır.

TCP ikisinin arasında bir yerde duruyor ve sıkıntısı birikimli onaydan geliyor. Onay numarası yalnızca “şu bayta kadar geldi” diyebiliyor; ötesinde neyin geldiğini söyleyemiyor. Somut bir örnek: gönderen 1.000, 2.000, 3.000, 4.000 ve 5.000 numaralı beş segment yolladı ve yalnızca 2.000 kayboldu. Alıcı elinde dördü var ama söyleyebildiği tek şey “2.000 bekliyorum”. Gönderen dört sağlam segmenti de yeniden yollamak ile yalnızca birini yollayıp riske girmek arasında kalıyor.

Çözüm bir seçenek. Seçici onay (SACK), onay numarasının yanına “şu aralıklar da elimde” listesini ekliyor. El sıkışmadaki SACK izinli seçeneği tanıdık; bu, o iznin karşılığı.

onay = 2.000        SACK: 3.000-6.460

İki satır birlikte okununca resim tamamlanıyor: 2.000 eksik, ondan sonrası tamam. Gönderen tek bir segment yolluyor ve boşluk kapanıyor. Seçenek alanı 40 baytla sınırlı olduğu için tek seferde en fazla dört blok bildirilebiliyor — zaman damgası seçeneği de açıksa üçe iniyor.

Kazanç, kayıpların tek tek değil kümeler hâlinde olduğu durumlarda büyüyor. Bir tıkanıklık anında bir pencerede birkaç segment birden düşer; SACK olmadan gönderen bunları ancak arka arkaya zaman aşımlarıyla, tur tur keşfeder. SACK ile hepsini tek turda görür.

Direksiyon alıcıda

Kayıp toparlandı. Geriye tek bir soru kalıyor: alıcı yetişemezse ne olacak?

Flow control bu soruyu alıcının eline veriyor. Gönderen uçuştaki veri miktarını alıcının ilan ettiği pencereyle sınırlar. İlan edilen sayı alma penceresidir: alıcının tamponunda o an kalan boş yer.

Tamponun dolma sebebi ağ kartı değil. IP kodu gelen yükü soket tamponuna bırakır, uygulama da oradan okur. Uygulama okumakta geri kalırsa boş yer erir ve ilan edilen sayı küçülür. Pencereyi olduğundan büyük göstermek işi düzeltmez. Kabul edilemeyen veri atılır ve gereksiz yeniden gönderim doğar.

Onay ile izin de ayrı şeylerdir. Alıcı bir baytı onaylayıp yeni gönderime izin vermeyebilir. TCP ikisini tek başlıkta taşır; onay numarası ile pencere yan yana durur.

Pencere alanı 16 bit olduğu için ölçeklemesiz en büyük ilan 65.535 bayttır. 100 ms gidiş-dönüşte bu, yaklaşık 5,24 Mbit/s’lik bir tavan demektir. Pencere ölçekleme uzantısı alandaki değeri kaydırarak o tavanı kaldırır. Tavanın ne kadar alçakta kaldığını bir hesap gösterir: 10 Gbit/s’i 100 ms gidiş-dönüşte tutturmak için 1.500 baytlık 83.333 paketin, yani yaklaşık 125 MB verinin aynı anda havada olması gerekir.

Pencere sıfırlandığında gönderen büsbütün durmak zorunda kalır. Pencereyi yeniden açan segment kaybolursa iki taraf birbirini bekler. Kilidi ısrar zamanlayıcısı kırar: dolduğunda gönderen, öncekinin kopyası olsa bile en az bir oktetlik bir yoklama yollar. Ardışık yoklamalar arasındaki süre üstel olarak açılır.

Flow control’ün koruduğu şey yalnızca alıcının kapasitesi. Ağın ortasındaki kuyrukları koruyan mekanizmayı bir sonraki durakta açacağım; pencere boyunu ikisi birlikte belirler.

Bunları kendi makinende görebilirsin. Linux’ta ss -ti çıktısı açık bir bağlantı için rtt ve rto alanlarını basar; rtt değerinin yanındaki ikinci sayı sapmadır. netstat -s ise TCP sayaçlarını döker; yeniden gönderilen segment sayısı orada durur.

Omurga sorusu: Kaybolabilen bir yolun üstünde kaybolmayan bir aktarım nasıl kuruluyor?

Numaralayarak. Her oktet numaralanır, her onay beklenen numarayı söyler, bir sayaç ile üç yinelenen onay kaybı iki ayrı yoldan yakalar, pencere de gönderenin ne kadar ileri gidebileceğini sınırlar. Yol hiçbir zaman güvenilir olmadı; güvenilirlik iki uçtaki muhasebeden çıktı.

Özet

Peki, ne öğrendik?

  • Sıra numarası. Alan segmentleri değil baytları sayar ve segmentin ilk baytının akış içindeki yerini taşır.
  • Birikimli onay. Onay numarası beklenen bir sonraki baytı gösterir ve kendinden öncekilerin hepsini tek seferde kapatır.
  • Zaman aşımı. Süre ölçülen tek bir gidiş-dönüşten değil, düzleştirilmiş kestirime eklenen sapma payından çıkar.
  • Hızlı yeniden gönderim. Üç yinelenen onay, sayacın dolmasını beklemeden eksik segmenti yola çıkarır.
  • Seçici onay birikimli onayın körlüğünü kapatır. SACK seçeneği “şu aralıklar da elimde” diyerek gönderenin yalnızca gerçekten eksik olanı yollamasını sağlar.
  • Flow control. Alıcının ilan ettiği pencere, gönderenin uçuşta tutabileceği veri miktarına tavan koyar.

Kayıp artık kendi kendine toparlanıyor ve alıcı gönderene ne kadar yer kaldığını söylüyor. Ama yolun ortasındaki kuyruklar kimseye bir şey ilan etmiyor. Gönderen ne kadar hızlı göndereceğine neye bakarak karar veriyor?

60. bölüme devam et: Tıkanıklık Denetimi