Ders 05 / 22
Kaynak Sınırları
Sekiz ayrı arıza nedeni üç hata iletisine ve bir sessizliğe çöküyor: 60 olayın 13'ü hiçbir ileti üretmiyor, yalnız iletiye bakan tanı 21 kez, yalnız sınır okuyan tanı 29 kez, ikisini birleştiren tanı 13 kez yanılıyor.
İçindekiler
Öncelik bir sürecin ne kadar hızlı koşacağını etkiler, ne kadar tüketebileceğini sınırlamaz. Önceki dersin tablosunda geri çekilen süreç yine de dilediği kadar dosya açabilir, dilediği kadar çocuk üretebilir, dilediği kadar bellek isteyebilirdi. Tüketimi sınırlamanın kendi mekanizması vardır.
Bu ders o mekanizmayı ve sınırın aşıldığında ortaya çıkan arızayı ölçer. Soru şudur: hata iletisi, sınırın hangisi olduğunu söylüyor mu — yoksa ayrı nedenler aynı cümleyle mi görünüyor.
Süreç Başına Kısıt
Her sürecin bir kaynak sınırı kümesi vardır ve her sınırın iki değeri bulunur. Yumuşak
sınır yürürlükte olan değerdir; süreç onu katı sınıra kadar kendisi yükseltebilir. Katı
sınır tavandır ve yalnız yetkili bir kullanıcı tarafından yükseltilebilir. Sınırlar kabuğun
ulimit yerleşiğiyle okunur ve yazılır:
$ ulimit -a # kurgudaki sunucunun sinirlari , ornek dokum core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited open files (-n) 1024 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 4096 virtual memory (kbytes, -v) unlimited $ ulimit -Hn # kati sinir 4096 $ ulimit -Sn 2048 # yumusak siniri kati sinira kadar yukselt $ cat /proc/1014/limits Limit Soft Limit Hard Limit Units Max open files 2048 4096 files Max processes 4096 8192 processes
Bu döküm örnektir ve çalıştırılmamıştır. İki okuma yolu görünüyor: ulimit çağıran
kabuğun sınırlarını verir, /proc altındaki dosya ise belirli bir sürecin sınırlarını.
İkisi aynı şey değildir ve fark, bu dersteki tanı hatalarının bir bölümünün kaynağıdır.
Kritik kural kalıtımdır: sınırlar çatallanma anında ana süreçten devralınır ve sonradan
dışarıdan değiştirilemez. Bunun üç sonucu vardır. Birincisi, bir kabukta ulimit ile
yükseltilen sınır yalnız o kabuğun bundan sonraki çocuklarını kapsar. İkincisi, servis
yöneticisinin başlattığı bir süreç operatörün kabuğundan hiçbir şey devralmaz; onun sınırları
birim tanımında yazılır. Üçüncüsü, çalışan bir sürecin sınırını sonradan yükseltmek yerleşik
bir kabuk komutuyla yapılamaz — süreç yeniden başlatılmalıdır. “Sınırı yükselttim ama servis
hâlâ aynı hatayı veriyor” cümlesinin ölçüsü budur.
Süreç başına kısıt tek kısıt türü değildir. Bir süreç öbeğinin toplamına konan kısıtlar ayrı bir mekanizmadır; ad alanı ve denetim grubu bu kursta ele alınmaz ve Çekirdek Arayüzleri ve İzolasyon kursuna bırakılır. Buradaki her sayı tek bir sürecin sınırıdır.
- SY30. Gözlem penceresinde 60 arıza olayı görülür.
- SY31. Arızaların sekiz ayrı nedeni vardır ve nedenler eşit sıklıkta değildir; göreli sıklıkları modelde sabittir.
- SY32. Sekiz neden üç hata iletisi ve bir sessizlik üretir. Her ileti iki ayrı nedene karşılık gelir.
- SY33. Dosya boyutu ve işlemci zamanı sınırları hiçbir ileti üretmez: süreç sinyalle öldürülür ve geriye yalnız bir çıkış durumu kalır.
- SY34. Nedenlerin altısı süreç başına sınırdır; ikisi (sistem geneli tanıtıcı ve boş bellek) süreç başına değildir ve sürecin kendi sınır okumasında görünmez.
- SY35. Birinci tanı yolu yalnız hata iletisidir. İletiden çıkarılabilecek en iyi tanı, o iletiyi üreten nedenlerin en sık görülenidir.
- SY36. İkinci tanı yolu sınır okumasıdır: sayacın hâlâ sınırında oturup oturmadığına bakılır.
- SY37. Olayların bir bölümü geçicidir: bakıldığında sayaç geri düşmüştür ve okuma hiçbir şey göstermez. Kanıt kendiliğinden yok olmuştur.
- SY38. İkinci tohum 20260219’dur.
# --- ortak tanim, birinci dersteki bicimiyle TOHUM, IKINCI_TOHUM = 20260218, 20260219 KULLANICI = ("kok", "uygulama", "yedek", "izleme") KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici", "kuyruk-isleyici", "onbellek-temizleyici") def uretec(tohum): d = tohum def sonraki(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return sonraki def surecler(tohum=TOHUM, sayi=24): r = uretec(tohum) liste = [] for i in range(sayi): tur = r(10) desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir") liste.append({"pid": 1000 + i * 7 + r(5), "kullanici": KULLANICI[r(len(KULLANICI))], "komut": KOMUT[r(len(KOMUT))], "desen": desen, "oncelik": r(11) - 5, "bellek": 20 + r(400), "sinyal_yok_sayar": r(10) < 2}) return liste # --- bu dersin katmani: sekiz neden , uc ileti , bir sessizlik # (ad, ileti, surec basina sinir mi) NEDEN = ( ("surec sayisi siniri", "kaynak gecici olarak kullanilamiyor", True), ("is parcacigi siniri", "kaynak gecici olarak kullanilamiyor", True), ("surec basina tanitici siniri", "cok fazla acik dosya", True), ("sistem geneli tanitici siniri", "cok fazla acik dosya", False), ("adres uzayi siniri", "bellek ayrilamadi", True), ("sistemde bos bellek yok", "bellek ayrilamadi", False), ("dosya boyutu siniri", "", True), ("islemci zamani siniri", "", True), ) SIKLIK = (5, 2, 8, 1, 4, 1, 2, 3) # nedenlerin goreli sikligi HAVUZ = [i for i, w in enumerate(SIKLIK) for _ in range(w)] def arizalar(surecler_, tohum=TOHUM, sayi=60): """Pencere boyunca gorulen ariza olaylari. Kahin: her olayin GERCEK nedeni.""" r = uretec(tohum) olay = [] for _ in range(sayi): s = surecler_[r(len(surecler_))] ad, ileti, surec_basina = NEDEN[HAVUZ[r(len(HAVUZ))]] olay.append({"pid": s["pid"], "neden": ad, "ileti": ileti, "surec_basina": surec_basina, "gecici": r(10) < 4}) # bakildiginda sayac geri dusmus return olay S = surecler() OLAY = arizalar(S) print("ariza olayi:", len(OLAY), "| farkli neden:", len({o["neden"] for o in OLAY})) sayim = {} for o in OLAY: sayim.setdefault(o["ileti"] or "(ileti yok , sinyalle olduruldu)", []).append(o["neden"]) print("ileti olay kac farkli neden") for i, n in sorted(sayim.items()): print(f" {i:38s} {len(n):4d} {len(set(n)):16d}")
ariza olayi: 60 | farkli neden: 8 ileti olay kac farkli neden (ileti yok , sinyalle olduruldu) 13 2 bellek ayrilamadi 12 2 cok fazla acik dosya 19 2 kaynak gecici olarak kullanilamiyor 16 2
Tablo dersin yapısını tek bakışta veriyor. Sekiz neden dört satıra çökmüş; her satır iki
ayrı nedeni taşıyor. En üstteki satırda ileti yoktur: 13 olay hiçbir metin üretmemiştir.
Dosya boyutu sınırını aşan süreç SIGXFSZ, işlemci zamanı sınırını aşan süreç SIGXCPU alır;
işleyici tanımlanmamışsa süreç sessizce ölür ve geriye yalnız 128 artı sinyal numarası biçiminde
bir çıkış kodu kalır. Arızanın metni yoktur, yalnız bir sayı vardır.
İletinin Gizlediği Neden
İleti bir nedeni gösteriyor gibi durur, ama gösterdiği şey nedenin ait olduğu çifttir. “Kaynak geçici olarak kullanılamıyor” iletisi hem süreç sayısı sınırından hem de iş parçacığı sınırından gelebilir; ikisi de çatallanmanın başarısız olması demektir ve çekirdek ikisini ayırt eden bir metin üretmez.
# Onceki blogun uzerine: OLAY, NEDEN oradan gelir. # Iletiden cikarilabilecek EN IYI tani: her iletinin en sik nedeni. ILETI_TANISI = {"kaynak gecici olarak kullanilamiyor": "surec sayisi siniri", "cok fazla acik dosya": "surec basina tanitici siniri", "bellek ayrilamadi": "adres uzayi siniri", "": "bilinmiyor"} def iletiyle_tani(olaylar): return sum(1 for o in olaylar if ILETI_TANISI[o["ileti"]] != o["neden"]) def sinirla_tani(olaylar): """Ileti + `ulimit` okumasi: hangi sayac sinirinda oturuyor. Sayac hala sinirindaysa neden okunur; olay geciciyse sayac geri dusmustur.""" return sum(1 for o in olaylar if o["gecici"]) def birlesik_tani(olaylar): """Once sinir okunur; sayac geri dusmusse iletiye donulur.""" return sum(1 for o in olaylar if o["gecici"] and ILETI_TANISI[o["ileti"]] != o["neden"]) print("tani yolu yanlis tani /", len(OLAY)) print(f" yalniz hata iletisi {iletiyle_tani(OLAY):9d}") print(f" yalniz sinir okumasi {sinirla_tani(OLAY):9d}") print(f" sinir okumasi , yoksa ileti {birlesik_tani(OLAY):9d}") print(" bunlarin icinde gecici olay ", f"{sum(1 for o in OLAY if o['gecici']):9d}") print("kahin: her olayin gercek nedeni biliniyor , kurguyu biz urettik") print() print("neden olay iletiden dogru cikar mi") for ad, ileti, _ in NEDEN: n = sum(1 for o in OLAY if o["neden"] == ad) print(f" {ad:32s} {n:3d} {'evet' if ILETI_TANISI[ileti] == ad else 'hayir'}")
tani yolu yanlis tani / 60 yalniz hata iletisi 21 yalniz sinir okumasi 29 sinir okumasi , yoksa ileti 13 bunlarin icinde gecici olay 29 kahin: her olayin gercek nedeni biliniyor , kurguyu biz urettik neden olay iletiden dogru cikar mi surec sayisi siniri 13 evet is parcacigi siniri 3 hayir surec basina tanitici siniri 16 evet sistem geneli tanitici siniri 3 hayir adres uzayi siniri 10 evet sistemde bos bellek yok 2 hayir dosya boyutu siniri 3 hayir islemci zamani siniri 10 hayir
Alt tablo hangi nedenlerin iletiden okunabildiğini söylüyor: sekiz nedenin üçü doğru çıkarılabiliyor, beşi çıkarılamıyor. Çıkarılamayanlar iki sınıftır — bir çiftin daha seyrek üyesi olanlar ve hiç ileti üretmeyenler. İşlemci zamanı sınırı tek başına 60 olayın 10’unu oluşturuyor ve hakkında yazılmış tek bir kelime yok.
Yalnız iletiye bakan tanı 21 kez yanılıyor. Bu, gerçekte olabilecek en iyi ileti tabanlı tanıdır: her ileti için en sık nedeni seçtik. Operatör dağılımı bilmiyorsa daha da kötüsünü seçer.
Kanıt Kendiliğinden Yok Oluyor
Doğru tepki iletiye güvenmemek ve sınırı okumaktır: sürecin sayaçlarına bakılır, hangisinin tavana dayandığı görülür. Bu yolun kendi zaafı vardır ve tabloda duruyor.
Yalnız sınır okuyan tanı 29 kez yanılıyor — ileti tabanlı tanıdan daha kötü. Nedeni tek kelimeyle söylenebilir: geçicilik. Başarısız bir ayırma denemesi sayacı yükseltmez; denemenin ardından sayaç geri düşer. Operatör olaydan sonra baktığında bütün sayaçlar sınırın altındadır ve okuma “her şey yolunda” der. Altmış olayın 29’u bu durumdadır.
Bu, kursun ikinci iddiasının bu dersteki karşılığıdır: daha ayrıntılı bir tanı yolu, tek başına daha iyi tanı vermez. Sınır okuması iletiden çok daha zengin bir kanıttır — sayı verir, tavanı verir, oranı verir — ama kanıt olay anında yaşar ve sonrasında kaybolur.
İki yolu birleştiren tanı 13 kez yanılıyor: sınır okuması işe yaradığında ondan, geri düşmüş sayaçta iletiden yararlanıyor. Kalan 13 olay, hem kanıtı kaybolmuş hem de iletisi yanıltıcı olan olaylardır ve bu sayı indirilemez — çünkü geriye bakan hiçbir okuma o anki sayacı geri getiremez. Tek çözüm, olayı olduğu anda yakalamaktır: sınıra yaklaşmayı bir eşikten izlemek, arızayı bekleyip sonra bakmak değil.
# Onceki bloklarin uzerine: arizalar, surecler ve uc tani yolu. for tohum in (TOHUM, IKINCI_TOHUM): O2 = arizalar(surecler(tohum), tohum) gecici = sum(1 for o in O2 if o["gecici"]) print(f"tohum {tohum}: olay {len(O2)} | ileti {iletiyle_tani(O2):2d}" f" | sinir {sinirla_tani(O2):2d} | birlesik {birlesik_tani(O2):2d}" f" | gecici {gecici:2d}" f" | sessiz {sum(1 for o in O2 if not o['ileti']):2d}")
tohum 20260218: olay 60 | ileti 21 | sinir 29 | birlesik 13 | gecici 29 | sessiz 13 tohum 20260219: olay 60 | ileti 15 | sinir 25 | birlesik 5 | gecici 25 | sessiz 7
İkinci tohumda bütün sayılar düşüyor: ileti 21 yerine 15, sınır 29 yerine 25, birleşik 13 yerine 5. Sayıların kendisi kurguya bağlıdır. Ayakta kalan şey sıralamadır: her iki tohumda da birleşik yol en iyi, yalnız sınır okuması en kötüdür ve ileti tabanlı tanı ikisinin arasında kalır. Bir tanı yolunun zenginliği, tek başına sıralamadaki yerini belirlemiyor.
Sınırların pratik yönetimi bu ölçümden çıkar. Sınırlar arıza çıksın diye değil, bir sürecin makineyi tüketmesini engellesin diye konur; iyi bir sınır aşıldığında arızayı sınırlar ama nedenini gizler. O yüzden sınır koymak ile sınıra yaklaşmayı izlemek birlikte yapılır. Süreç başına sınır ayrıca kaba bir araçtır: aynı kullanıcının bütün süreçlerini kapsayan bir süreç sayısı sınırı, tek bir hatalı betiği durdururken oturum açmayı da engelleyebilir.
Sınırın Dışındaki Ölüm
Ölçülen sekiz nedenin hepsi bir sınırın aşılmasıydı ve hepsinde ölen ya da başarısız olan süreç, sınırı aşan sürecin kendisiydi. Sınırların dışında kalan bir ölüm biçimi daha vardır ve tanıyı bambaşka bir yönden bozar.
Sistemin belleği gerçekten tükendiğinde çekirdek bir kurban seçer ve onu zorlayan sinyalle öldürür. Seçim, belleği tüketen sürece göre değil, bir puanlamaya göre yapılır; puanlamada sürecin o anki bellek tutumu ağır basar. Sonuç, çoğu zaman en çok bellek tutan sürecin ölmesidir — ki bu, belleği kaçıran süreç olmak zorunda değildir. Sızıntıyı yapan küçük bir süreç, sızıntının bastırdığı sistemde büyük ve masum bir sürecin ölümüne yol açar. Ölen sürecin kendi çıktısında hiçbir iz kalmaz; olayın tek kaydı sistem günlüğündedir.
İkinci bir sessizleştirici, dökümün kendisidir. Yukarıdaki örnek dökümde çekirdek dosyası boyutu sınırı sıfırdır ve bu yaygın bir varsayılan yapılandırmadır. Sıfır olduğunda, sinyalle ölen bir süreç arkasında incelenebilecek hiçbir şey bırakmaz. Bu dersin ilk tablosundaki 13 sessiz olay için elde kalan tek şey çıkış kodudur; döküm sınırı sıfır olduğu sürece o kod da tek başına kalır.
İki gözlem aynı yere çıkar. Bir arızanın nedenini olaydan sonra bulmak, kanıtın olaydan sonra da var olmasına bağlıdır: sayaç sınırında kalmalı, döküm yazılmalı, ölüm bir yere kaydedilmelidir. Üçünün de varsayılan davranışı kanıtı saklamamaktır. Sınır koymanın yanına konması gereken şey bu yüzden bir sayı değil, bir kayıt yoludur — arıza anındaki durumu yazan bir kanca ya da eşik izleme. Ölümün nereye kaydedildiği ve o kaydın ne kadar yaşadığı kursun günlükler konusunda ölçülür.
Özet
- Her sınırın yumuşak ve katı iki değeri vardır; sınırlar çatallanma anında devralınır ve çalışan bir sürecin sınırı kabuktan sonradan değiştirilemez.
- Sekiz arıza nedeni üç hata iletisine ve bir sessizliğe çöküyor; her ileti iki ayrı nedene karşılık geliyor ve 13 olay hiçbir metin üretmiyor.
- İletiden yalnız üç neden doğru çıkarılabiliyor; işlemci zamanı sınırı tek başına 60 olayın 10’unu oluşturuyor ve hakkında hiçbir metin yok.
- Üç tanı yolunun yanlış tanı sayısı: yalnız ileti 21, yalnız sınır okuması 29, ikisinin birleşimi 13. Daha zengin kanıt tek başına daha iyi tanı vermiyor.
- Sınır okumasının zaafı geçiciliktir: 60 olayın 29’unda sayaç bakıldığında geri düşmüştür. Kalan 13 yanlış tanı geriye bakan hiçbir okumayla indirilemez.
- İkinci tohumda sayılar 15, 25 ve 5’e iniyor; ayakta kalan sonuç sıralamadır — birleşik yol en iyi, yalnız sınır okuması en kötüdür.
Sonraki Adım
Bu konu boyunca süreçlere operatörün penceresinden bakıldı: listelenen, aranan, arka plana alınan, sinyal gönderilen, önceliği değiştirilen ve sınırlanan tek tek süreçler. Hepsinin ortak bir zaafı vardı — operatör oradayken çalışıyorlardı. Bir sunucunun asıl işi ise kimse bakmıyorken sürer. Kursun sonraki konusu bu işi kalıcı bir nesneye bağlayan katmanı ele alır: servis yöneticisi, birimler ve aralarındaki bağımlılıklar. Orada ölçülecek ilk şey, bir birimin “çalışıyor” görünmesinin ne anlama geldiğidir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.