İçeriğe geç
academia.sh

Ders 08 / 22

Yeni Servis Tanımlama

Birim dosyasının bölümleri ve alanları kurulur; üç yeniden başlatma politikasının üç çıkış türünde ne gizlediği dokuz bileşimde sayılır ve başlatma sınırının görünmez süreyi kaça indirdiği taranır.

İçindekiler

Önceki ders yeniden başlatma politikasının arızayı gizlediğini saydı: altı birimin dördü “çalışıyor” görünürken altısı da arızalıydı. Tablonun bir satırı açıkta kalmıştı. isleme biriminin politikası “arızada”ydı, yani “her zaman”dan daha ölçülü bir seçim, ama sonuç aynıydı: altmış yeniden başlatma, altı yüz saniye görünmezlik. İki politika arasındaki fark o koşumda hiç ortaya çıkmadı.

Bu ders farkı ortaya çıkarır. Bunun için önce politikanın yazıldığı yere, birim dosyasına bakılır; sonra üç politika üç ayrı çıkış türüyle çarpılır ve dokuz bileşimde hangi arızanın kaybolduğu sayılır. Sonunda gizlemeyi kıran mekanizma ölçülür: başlatma sınırı.

Birim Dosyasının Bölümleri

Birim dosyası bölümlere ayrılmış düz bir metindir ve servis birimlerinde üç bölüm bulunur. Birinci bölüm birimi grafiğe yerleştirir: açıklaması, neyi gerektirdiği, neyden sonra başlayacağı burada yazılır. İkinci bölüm birimin nasıl çalıştırılacağını söyler: hangi komut, hangi kullanıcı, hangi çalışma dizini, hangi ortam değişkenleri, birim türü ve yeniden başlatma politikası. Üçüncü bölüm etkinleştirmenin ne anlama geldiğini söyler: bu birim hangi hedefin altına bağlanacak. Üçüncü bölümü yazmayan bir birim dosyası kurulabilir ve elle başlatılabilir, ama etkinleştirilemez; önceki dersteki “etkin değil ama çalışıyor” bileşiminin bir üretim yolu budur.

Aşağıdaki dosya kurgu sunucunun veri-alma birimini tanımlar. Çalıştırılmamıştır; alanların yerleşimini göstermek için yazılmıştır ve alan adları servis yöneticisine göre değişir:

[Unit]
Description=Veri alma birimi
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/veri-alma --yapilandirma /etc/veri-alma.conf
User=uygulama
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

İki alan bu dersin konusuyla doğrudan ilgili. Type alanı yöneticinin birimi ne zaman “başlatıldı” sayacağını belirler; bildirim bekleyen tür, önceki derste anlatılan hazır olma boşluğunu kapatır. Restart alanı ise yeniden başlatma politikasıdır ve bu dersin ölçtüğü şeydir. RestartSec yeniden başlatmadan önce beklenecek süreyi verir; sıfıra yakın bir değer, çöken bir birimi saniyede birkaç kez diriltip işlemciyi meşgul eder.

Dosya yazıldıktan sonra yöneticiye yeniden okuması söylenmezse hiçbir şey değişmez; grafiğin bellekteki kopyası eski kalır. Bu, birinci derste kurulan noktanın uygulamadaki karşılığıdır. Dosyadaki bir sözdizim hatası da yazma anında değil, yeniden okuma ya da başlatma anında görünür; yönetici hatalı satırı atlar ve birimi eksik tanımla yükler. Yazdıktan sonra birimin birleşik tanımını basan komutla ne yüklendiğini görmek, dosyayı bir kez daha okumaktan daha bilgilendirici olur.

Birim Türü Ne Zaman “Başlatıldı” Denileceğini Belirler

Type alanı küçük görünür ve zincirin tamamını etkiler. En yalın türde yönetici komutu çalıştırır ve çalıştırma başarılı döndüğü anda birimi başlatılmış sayar. Çatallanan türde süreç kendini arka plana atar, ilk süreç sonlanır ve yönetici asıl süreci bir kimlik dosyasından ya da süreç ağacından bulur; bu tür, yönetici ile programın birbirine yalan söylemesine en açık olanıdır. Tek seferlik türde birim bir iş yapar ve çıkar; çıkması arıza değildir ve bu tür, önceki derste gördüğümüz “çıktı” durumunun meşru sahibidir. Bildirim yapan türde ise program hazır olduğunda yöneticiye açıkça haber verir ve zincir ancak o zaman ilerler.

Türün yanlış seçilmesi, hiçbir hata iletisi üretmeden yanlış davranış üretir. Kendini arka plana atan bir programı en yalın türle tanımlamak, yöneticinin arka plana atılmadan önceki kısa ömürlü süreci izlemesine ve o süreç çıkınca birimi çökmüş saymasına yol açar. Yeniden başlatma politikası “her zaman” ise sonuç, ikinci derste ölçülen döngünün ta kendisidir: birim saniyede bir yeniden başlar, durum hep “çalışıyor” görünür.

Elle Çalışan Komut Birim Olarak Çalışmıyor

Birim dosyası yazanların en sık karşılaştığı arıza, komutun kabukta çalışıp birim olarak çalışmamasıdır. Nedeni tek cümlede toplanır: yönetici bir kabuk değildir. Oturum açılırken okunan yapılandırma dosyaları okunmaz, arama yolu operatörünkinden farklıdır, çalışma dizini belirtilmemişse kök dizindir, ortam değişkenleri boştur, kullanıcı belirtilmemişse süreç yönetici ile aynı ayrıcalıkla çalışır. Kabuk genişletmesi de yoktur: yıldız, tırnak ve borulama beklenildiği gibi işlemez, çünkü komut satırı bir kabuğa verilmez.

Bunun sonucu, arızanın yanlış yerde aranmasıdır. Program dosya bulamadığı için çıkar, hata iletisi “dosya yok” der ve operatör dosyayı arar; dosya yerindedir, eksik olan çalışma dizinidir. Doğru alışkanlık, birim dosyasında yolları mutlak yazmak, çalışma dizinini ve kullanıcıyı açıkça belirtmek, gereken ortam değişkenlerini ayrı bir dosyadan okutmaktır. Birimin ürettiği çıktının nereye gittiği ve orada nasıl bulunacağı bu konunun değil, günlükler konusunun sorusudur.

Üç Politika, Üç Çıkış Türü

Bir sürecin çalışmayı bırakmasının tek yolu yok. Temiz çıkış: süreç kendi kendine, başarı bildiren bir çıkış koduyla sonlanır. Hatalı çıkış: sıfırdan farklı bir kodla sonlanır. Sinyalle sonlanma: dışarıdan gelen bir sinyalle ya da çekirdeğin müdahalesiyle öldürülür. Yeniden başlatma politikaları bu üç türü ayırır ve ayırdıkları yer birbirinden farklıdır.

Politika “hayır” hiçbir durumda yeniden başlatmaz. Politika “arızada” hatalı çıkışta ve sinyalle sonlanmada yeniden başlatır, temiz çıkışta başlatmaz. Politika “her zaman” üçünde de yeniden başlatır. Aradaki fark ancak temiz çıkış varken görünür ve tam olarak orada tehlikelidir: uzun ömürlü olması beklenen bir servisin sıfır koduyla çıkması bir arızadır, ama “arızada” politikası onu arıza saymaz.

SV21 — birim uzun ömürlü olmak üzere tasarlanmıştır; her çıkış, kodu ne olursa olsun bir arızadır. SV22 — dokuz bileşimin dokuzunda da birim gerçekte arızalıdır; kâhin bunu bilir. SV23 — çöküş aralığı 8 ile 12 saniye arasında tohumlu seçilir. SV24 — yeniden başlatma anlıktır ve başarısız olmaz. SV25 — temiz çıkışta yeniden başlatılmayan birimin durumu “çıktı”dır, arızalı değil. SV26 — hatalı çıkışta ya da sinyalle sonlanmada yeniden başlatılmayan birimin durumu “arızalı”dır. SV27 — yeniden başlatılan birimin durumu “çalışıyor”dur. SV28 — operatörün tanısı üç durum sözcüğünden üretilir: “çalışıyor” ise sağlıklı, “çıktı” ise normal bitti, “arızalı” ise arızalı.

TOHUM = 20260218
DONEM = 600
POLITIKA = ("hayir", "arizada", "her zaman")
CIKIS = ("temiz", "hata", "sinyal")


def uretec(tohum):
    d = tohum

    def sonraki(n):
        nonlocal d
        d = (d * 1103515245 + 12345) % 2147483648
        return d % n
    return sonraki


def yeniden_baslar(politika, cikis):
    if politika == "her zaman":
        return True
    if politika == "arizada":
        return cikis in ("hata", "sinyal")
    return False


def cokme_anlari(tohum=TOHUM, sure=DONEM, en_az=8, en_cok=12):
    """Birim duzensiz arayla cokuyor; aralik tohumlu secilir."""
    r = uretec(tohum)
    t, liste = 0, []
    while True:
        t += en_az + r(en_cok - en_az + 1)
        if t >= sure:
            return liste
        liste.append(t)


def kosum(politika, cikis, anlar, sinir=0, pencere=100, sure=DONEM):
    """`sinir` kadar yeniden baslatma `pencere` saniyede asilirsa yonetici vazgecer."""
    if not yeniden_baslar(politika, cikis):
        return {"yeniden": 0, "durum": "cikti" if cikis == "temiz" else "arizali",
                "gorunmez": sure if cikis == "temiz" else 0}
    yapilan = []
    for t in anlar:
        if sinir and sum(1 for x in yapilan if x >= t - pencere) >= sinir:
            return {"yeniden": len(yapilan), "durum": "arizali", "gorunmez": t}
        yapilan.append(t)
    return {"yeniden": len(yapilan), "durum": "calisiyor", "gorunmez": sure}


A = cokme_anlari()
print("kahin: birim", DONEM, "saniyede", len(A), "kez cokuyor")
print()
print("politika    cikis   yeniden  gorunen durum  operatorun tanisi  dogru mu")
yanlis = 0
for p in POLITIKA:
    for c in CIKIS:
        k = kosum(p, c, A)
        tani = {"calisiyor": "saglikli", "cikti": "normal bitti",
                "arizali": "arizali"}[k["durum"]]
        dogru = tani == "arizali"
        yanlis += 0 if dogru else 1
        print(f"  {p:10s} {c:7s} {k['yeniden']:7d}  {k['durum']:13s}"
              f"  {tani:17s}  {'evet' if dogru else 'HAYIR'}")
print("  yanlis tani:", yanlis, "/ 9")
print()
print("baslatma siniri  yeniden  gorunen durum  gorunmez sure  yanlis tani")
for sinir in (0, 20, 10, 5, 3):
    k = kosum("her zaman", "hata", A, sinir=sinir)
    yt = len([t for t in range(0, DONEM, 10) if t < k["gorunmez"]])
    print(f"  {'yok' if sinir == 0 else str(sinir):15s} {k['yeniden']:7d}"
          f"  {k['durum']:13s}  {k['gorunmez']:13d}  {yt:11d}")
kahin: birim 600 saniyede 60 kez cokuyor

politika    cikis   yeniden  gorunen durum  operatorun tanisi  dogru mu
  hayir      temiz         0  cikti          normal bitti       HAYIR
  hayir      hata          0  arizali        arizali            evet
  hayir      sinyal        0  arizali        arizali            evet
  arizada    temiz         0  cikti          normal bitti       HAYIR
  arizada    hata         60  calisiyor      saglikli           HAYIR
  arizada    sinyal       60  calisiyor      saglikli           HAYIR
  her zaman  temiz        60  calisiyor      saglikli           HAYIR
  her zaman  hata         60  calisiyor      saglikli           HAYIR
  her zaman  sinyal       60  calisiyor      saglikli           HAYIR
  yanlis tani: 7 / 9

baslatma siniri  yeniden  gorunen durum  gorunmez sure  yanlis tani
  yok                  60  calisiyor                600           60
  20                   60  calisiyor                600           60
  10                   10  arizali                  106           11
  5                     5  arizali                   62            7
  3                     3  arizali                   41            5

Her Politika Ne Gizliyor

Dokuz bileşimin 7’sinde operatörün tanısı yanlış. Gizlenenler politikaya göre farklı yerlerde duruyor.

Politika “hayır” üç çıkış türünün yalnız 1’ini gizliyor: temiz çıkışı. Hatalı çıkışta ve sinyalle sonlanmada birim “arızalı” görünüyor ve tanı doğru çıkıyor. En az gizleyen politika, hiçbir dayanıklılık sunmayan politika. Politika “arızada” 3 türün üçünü de gizliyor ama iki farklı biçimde: hata ve sinyal durumunda birimi diriltip “çalışıyor” gösteriyor, temiz çıkışta ise diriltmeyip “çıktı” gösteriyor. İkinci biçim daha sinsidir, çünkü “çıktı” durumu tek seferlik görevler için normal bir sonuçtur ve gözden kaçar. Politika “her zaman” 3 türün üçünü de aynı biçimde gizliyor: hepsi “çalışıyor”.

Sonuç ters sıralanıyor. Dayanıklılık arttıkça görünürlük azalıyor ve ikisi arasında hiçbir ayar kendiliğinden denge kurmuyor. “Her zaman” politikası bir sunucuyu ayakta tutmanın en dolaysız yolu ve aynı zamanda arızayı en iyi saklayan seçenek.

Tablonun ikinci okuması, politika seçiminin çıkış türü bilgisi olmadan yapılamayacağını söylüyor. “Arızada” politikası, programın arızayı sıfırdan farklı bir kodla bildirdiği varsayımına dayanır. Bu varsayım her programda tutmaz: yapılandırmasını okuyamayan bir program hata basıp sıfır koduyla çıkabilir, kapanma yolunda bir hata yutulmuş olabilir, sarmalayıcı bir betik kendi çıkış kodunu döndürüp asıl programınkini gizleyebilir. Çıkış kodu sözleşmesi M03/K02 Kabuk Programlama kursunda kurulmuştu; burada o sözleşmenin bozulmasının bedeli, dokuz bileşimin iki satırında “normal bitti” olarak görünüyor.

Buradan çıkan seçim kuralı üç maddedir. Uzun ömürlü servis için “her zaman” seçilir ve yanına mutlaka bir tavan konur. Tek seferlik görev için “hayır” seçilir; o birimin çıkması gerçekten normaldir. “Arızada” ancak programın çıkış kodu sözleşmesine uyduğu doğrulanmışsa seçilir ve doğrulama, koda bakmayı ya da programı bilerek bozup çıkış kodunu okumayı gerektirir.

Başlatma Sınırı Gizlemeyi Kırıyor

Servis yöneticileri bu tuzağı kapatmak için ikinci bir mekanizma taşır: başlatma sınırı. Bir birim belirlenen pencere içinde belirlenen sayıdan çok yeniden başlatılırsa yönetici denemeyi bırakır ve birimi arızalı işaretler. Sınır, dayanıklılığın kapatılması değil, dayanıklılığın bir tavanı olmasıdır.

Tarama tablosu tavanın etkisini gösteriyor. Yüz saniyelik pencerede sınır yoksa birim 600 saniye boyunca 60 kez yeniden başlıyor ve hiç arızalı görünmüyor: on saniyede bir bakan operatör 60 kez yanlış tanı koyuyor. Sınır 20 iken tablo değişmiyor, çünkü kurgudaki çöküş hızı yüz saniyelik pencerede yirmiyi hiç bulmuyor: konulan sınır, sınır olmamakla aynı. Sınır 10 olduğunda birim 106. saniyede vazgeçiliyor ve yanlış tanı 11’e düşüyor. Sınır 5 iken görünmez süre 62 saniye, yanlış tanı 7; sınır 3 iken 41 saniye ve 5.

Sınır 20 satırı ayrıca bir uyarı taşıyor. Yapılandırmaya konmuş, çıktıda görünen, doğru sözdizimle yazılmış bir sınır burada hiçbir şey yapmıyor. Kâhinle karşılaştırılmadığı sürece bir ayarın etkili olup olmadığı yapılandırmadan okunamaz; ayar var olmakla iş görmek aynı şey değildir. Sınırın etkili olması, çöküş hızının pencere içinde sınırı geçmesine bağlıdır ve çöküş hızı yapılandırmada yazmaz.

Aradaki kazanç büyük: görünmez süre 600 saniyeden 41 saniyeye, yanlış tanı 60’tan 5’e iniyor. Bedeli de açık: sınıra takılan birim artık kendi kendine geri gelmez. Sınır 3 iken kırk saniyelik bir dalgalanma servisi kalıcı olarak durdurur. Sınırın doğru değeri, arızanın görünür olmasıyla servisin ayakta kalması arasındaki takasın nereye konduğudur ve bu takas ortama göre değişir, tek doğru sayısı yoktur.

SV29 — başlatma sınırı penceresi 100 saniyedir. SV30 — sınıra takılan birim elle başlatılana kadar arızalı kalır. SV31 — operatör on saniyede bir yokluyor; yanlış tanı, vazgeçme anından önceki yoklamaların sayısıdır.

Üç Sayı ve İkinci Tohum

Kâhin: birim 600 saniyede 60 kez çöküyor ve dokuz bileşimin dokuzunda da arızalı. Araç çıktısı: dokuz bileşimde beş kez “çalışıyor”, iki kez “çıktı”, iki kez “arızalı”; başlatma sınırı taramasında yeniden başlatma sayısı 60, 60, 10, 5, 3. Yanlış tanı: politika tablosunda 7; sınır taramasında sınır yokken 60, sınır 10 iken 11, sınır 5 iken 7, sınır 3 iken 5.

İkinci tohumla (20260219) çöküş anları yeniden üretildiğinde çöküş sayısı yine 60 çıkıyor ve görünmez süreler şöyle oluyor: sınır yokken 600 ve 600, sınır 10 iken 106 ve 107, sınır 5 iken 62 ve 56, sınır 3 iken 41 ve 36. Büyüklük düzeni iki tohumda da aynı. Tek tek saniyeler kurguya bağlıdır; sınır konduğunda görünmez sürenin bir büyüklük düzeni azalması değildir. Dokuz bileşimlik tablo tohumdan hiç etkilenmiyor, çünkü orada sayılan şey çöküş anları değil politikanın kararı; o tablo yalnız modelin kendisine bağlıdır.

Özet

  • Birim dosyası üç bölümdür: grafiğe yerleştirme, çalıştırma ve etkinleştirme. Üçüncü bölümü olmayan birim elle başlatılır ama etkinleştirilemez.
  • Bir sürecin sonlanmasının üç türü vardır — temiz çıkış, hatalı çıkış, sinyalle sonlanma — ve politikalar bu türleri farklı yerlerde ayırır.
  • Dokuz bileşimin 7’sinde durum sözcüğünden çıkarılan tanı yanlış: “hayır” bir türü, “arızada” ve “her zaman” üç türü de gizliyor.
  • Temiz çıkışı arıza saymayan “arızada” politikası, uzun ömürlü bir servisin sessizce durmasını normal bitti diye gösterir.
  • Başlatma sınırı gizlemeyi kırar: görünmez süre 600 saniyeden sınır 3 ile 41 saniyeye, yanlış tanı 60’tan 5’e iner.
  • Sınırın bedeli, takılan birimin kendi kendine geri gelmemesidir; doğru değer ortama göre belirlenen bir takastır.

Sonraki Adım

Buraya kadar tek bir birim ölçüldü: kendi başına çöken, kendi başına dirilen bir birim. Kurgu sunucuda birimler yalnız kendileri değil; birinci derste kurulan grafik hâlâ orada duruyor ve bir birimi yeniden başlatmak yalnız onu ilgilendirmiyor. Sonraki ders makinenin açılmasıyla başlayan zinciri — ürün yazılımından önyükleyiciye, çekirdekten ilk sürece ve hedeflere — kurar ve bir birimi yeniden başlatmanın kaç birimi durdurup başlattığını sayar. Komut tek satır basıyor; kâhinin sayısı beş.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat