İçeriğe geç
academia.sh

Ders 17 / 19

Dağıtık Yapılandırma

Merkezî bir yapılandırma değeri dışarıda değişir, ama bunu kim gördüğü bileşenin kapsamına bağlıdır — tekil bir bileşen kurulduğu andaki değeri sonsuza kadar taşır, her istekte yeniden kurulan bileşen değişikliği bir sonraki kurulumda görür. Sınırlayıcı ölçüm, kursun en sessiz kusurunu ölçer — hiçbir hata çıkmaz, aynı anda var olan iki bileşen aynı anahtara iki farklı yanıt verir ve fark ancak yan yana konduğunda görünür.

İçindekiler

Önceki ders bir bileşenin iç durumunun dışarı nasıl sızdığını ölçtü — hangi alanın işaretlendiği, hangisinin işaretlenmediği. Bu ders tersini soruyor: dışarıdaki bir değer içeri nasıl giriyor, ve bir kez girdikten sonra o değer değiştiğinde hangi bileşen bunu görüyor. Merkezî yapılandırma modelleniyor — değerler uygulamanın dışında tutuluyor, bir bileşenin kodunda değil — ve dışarıdaki bir değer değiştiğinde hangi bileşenin bunu ne zaman gördüğü ölçülüyor. Merkezî yapılandırmanın ve dış yapılandırma deposunun kavramı M22/K05 Kod Olarak Altyapı ile M22/K08 Platform Mühendisliği kurslarında kuruldu ve burada tekrarlanmıyor; bu ders yalnız değerin hangi bileşene ne zaman ulaştığını ölçüyor. Sınırlayıcı ölçüm kursun en sessiz kusurunu taşıyor: hiçbir hata çıkmıyor, iki bileşen aynı anda iki farklı değeri doğru sanıyor.

MerkeziAyarlar bu derste tek bir Java sınıfı olarak modelleniyor — gerçek bir dağıtık sistemde bu depo ayrı bir süreçte, hatta ayrı bir makinede yaşar ve bileşenler ona ağ üzerinden ulaşır. Gerçek bir ağ çağrısı burada yok; modellenen şey ağın kendisi değil, ağın yarattığı zamanlama sorunu — bir değer bir yerde değişir, ve bu değişikliğin başka bir yere ulaşması sıfır zaman almaz. Statik bir Java alanı bu gecikmeyi taklit etmiyor, ama “dışarıda tutulan tek bir değer, birden çok bileşen tarafından farklı anlarda okunuyor” yapısını birebir taşıyor — ölçülen de tam bu yapı.

Dışarıda Değişen Bir Değer

MerkeziAyarlar, uygulamanın hiçbir bileşenine ait olmayan, dışarıda tutulan bir anahtar-değer deposu. Bir bileşen bu değeri ne zaman okursa, o an depoda ne varsa onu görür — ama bu okuma yalnız bir kez mi oluyor, yoksa her seferinde mi, bu bileşenin kapsamına bağlı. Kapsam kavramı framework-core konusunda kuruldu: tekil bir bileşen bir kez kurulur ve o örnek sürekli yeniden kullanılır, her istekte kurulan bileşen ise her istek için yeniden inşa edilir.

// MerkeziAyarlar.java — uygulamanin disinda tutulan, disaridan degistirilebilen anahtar-deger deposu (yardimci kaynak, main yok)
import java.util.*;

class MerkeziAyarlar {
    static final Map<String, String> degerler = new HashMap<>();
    static { degerler.put("mod", "normal"); }

    static String getir(String anahtar) { return degerler.get(anahtar); }
    static void guncelle(String anahtar, String yeni) { degerler.put(anahtar, yeni); }
}
// TekilBilesen.java — degeri yalnizca kuruldugu anda okuyup alanda saklayan tekil bilesen (yardimci kaynak, main yok)
class TekilBilesen {
    final String modDegeri;
    TekilBilesen() { modDegeri = MerkeziAyarlar.getir("mod"); }
    String mod() { return modDegeri; }
}
// HerIstekteBilesen.java — her istekte yeniden kuruldugu icin degeri her seferinde yeniden okuyan bilesen (yardimci kaynak, main yok)
class HerIstekteBilesen {
    final String modDegeri;
    HerIstekteBilesen() { modDegeri = MerkeziAyarlar.getir("mod"); }
    String mod() { return modDegeri; }
}
// Olcum.java — sonuc yazdirma yardimcisi (yardimci kaynak, main yok)
class Olcum {
    static void goster(String etiket, Object deger) {
        System.out.printf("%-52s: %s%n", etiket, deger);
    }
}

TekilBilesen ile HerIstekteBilesen’in yapıcıları birebir aynı satırı taşıyor: MerkeziAyarlar.getir("mod"). Aralarındaki fark kodda değil, kaç kez kurulduklarında — TekilBilesen’in yapıcısı uygulamanın ömrü boyunca yalnız bir kez çalışıyor, HerIstekteBilesen’inki her yeni istek geldiğinde yeniden.

// DisardaDegisen.java — ayni okuma satiri, tekil bilesende bir kez, her istekte kurulan bilesende her kurulumda calisiyor
public class DisardaDegisen {
    public static void main(String[] args) {
        TekilBilesen tekil = new TekilBilesen();
        Olcum.goster("tekil bilesen, degisiklikten once", tekil.mod());

        MerkeziAyarlar.guncelle("mod", "bakim");
        Olcum.goster("disaridaki deger degisti mi", MerkeziAyarlar.getir("mod"));

        Olcum.goster("ayni tekil bilesen, degisiklikten sonra", tekil.mod());

        HerIstekteBilesen yeniIstek = new HerIstekteBilesen();
        Olcum.goster("degisiklikten sonra yeniden kurulan bilesen", yeniIstek.mod());
    }
}
tekil bilesen, degisiklikten once                   : normal
disaridaki deger degisti mi                         : bakim
ayni tekil bilesen, degisiklikten sonra             : normal
degisiklikten sonra yeniden kurulan bilesen         : bakim

GT22. Merkezî yapılandırma dışarıda tutulur, hiçbir bileşenin kendi alanında değil; değerin ne zaman okunduğu, framework-core konusunda kurulan kapsam ayrımına bağlı — tekrarlanmıyor, yalnız burada değerin zamanlamasını belirlediği ölçülüyor. GT23. Tekil bir bileşen değeri yalnız kurulduğu anda okur ve alanında saklar; dışarıdaki değişiklik o örneğe hiç ulaşmaz — tekil.mod() üçüncü satırda hâlâ normal diyor, oysa depo çoktan bakim’e döndü. GT24. Her istekte yeniden kurulan bir bileşen değeri her seferinde yeniden okur; değişiklikten sonra kurulan yeniIstek, aynı satırı çalıştırıp güncel değeri görüyor.

Bu fark her istekte kurulan bileşenin “daha doğru” olduğu anlamına gelmiyor — yalnız daha güncel. Tekil bileşen bir kez kurulup sürekli yeniden kullanıldığı için ucuz; her istekte kurulan bileşen her seferinde yapıcısını yeniden çalıştırdığı için daha pahalı, ama karşılığında dışarıdaki her değişikliği bir sonraki kurulumda görüyor. İki kapsamın hangisi seçilirse seçilsin, seçim kaynakta bir kez yazılıyor ve o sınıfın bütün örnekleri için aynı kalıyor; bir bileşenin bazen tekil bazen her istekte davranması bu modelde yok.

Yenileme Bir Çağrıdır, Otomatik Değil

Bir tekil bileşenin dışarıdaki değişikliği hiç görmemesi her zaman istenen bir şey değil. Bazı bileşenler kendilerine açıkça bir yenileme yöntemi ekliyor — ama bu yöntem çağrılmadığı sürece hiçbir şey değişmiyor.

// YenilenebilirBilesen.java — tekil, ama disaridan cagrilan bir yontemle degerini yeniden okuyabiliyor (yardimci kaynak, main yok)
class YenilenebilirBilesen {
    String modDegeri;
    YenilenebilirBilesen() { modDegeri = MerkeziAyarlar.getir("mod"); }
    String mod() { return modDegeri; }
    void yenile() { modDegeri = MerkeziAyarlar.getir("mod"); }
}
// YenilemeCagridir.java — disaridaki deger degisiyor, ama yenile() cagrilana kadar bilesen bunu gormuyor
public class YenilemeCagridir {
    public static void main(String[] args) {
        MerkeziAyarlar.guncelle("mod", "normal");
        YenilenebilirBilesen bilesen = new YenilenebilirBilesen();
        Olcum.goster("yenilenebilir bilesen, kurulusta", bilesen.mod());

        MerkeziAyarlar.guncelle("mod", "bakim");
        Olcum.goster("disaridaki deger degisti, yenile() hic cagrilmadi", bilesen.mod());

        bilesen.yenile();
        Olcum.goster("yenile() cagrildiktan sonra", bilesen.mod());
    }
}
yenilenebilir bilesen, kurulusta                    : normal
disaridaki deger degisti, yenile() hic cagrilmadi   : normal
yenile() cagrildiktan sonra                         : bakim

GT25. Yenileme kendiliğinden olmaz, açık bir çağrıdır; yenile() çağrılmadıkça tekil bir bileşen eski değeri tutmaya devam eder, dışarıdaki değişiklik ile bileşenin gördüğü değer arasındaki fark yalnız o çağrı geldiğinde kapanır. Bu satır TekilBilesen’in hiç sahip olmadığı bir şey ekliyor: dışarıdaki değişikliği görme imkânı. Ama imkân otomatik uygulanma anlamına gelmiyor — YenilenebilirBilesen de tıpkı TekilBilesen gibi ikinci satırda hâlâ normal diyor, çünkü yenile() henüz çağrılmadı. Yenileme bir varsayılan değil, bir karar.

Bu üç bileşen türü — tekil, her istekte kurulan, yenilenebilir tekil — dışarıdaki bir değişikliğe karşı üç ayrı duruş sergiliyor: birincisi hiç görmüyor, ikincisi otomatik görüyor ama pahalı, üçüncüsü ucuz kalıyor ama görmesi için birinin yenile()’yi çağırması gerekiyor. Kim çağıracak sorusu bu dersin sınırları dışında — gerçek bir sistemde bu çağrıyı bir zamanlayıcı, bir dış sinyal ya da bir sonraki istek tetikleyebilir; burada önemli olan, çağrı gelmedikçe hiçbir şeyin kendiliğinden değişmediği.

Sessiz Kusur: Aynı Anda İki Farklı Gerçek

Önceki iki bölümün gösterdiği fark bir sırayla ilgiliydi — önce ve sonra. Bu bölüm aynı sorunu eşzamanlılıkla soruyor: bir uygulamanın birden çok bileşeni varken, hepsi aynı merkezî değere aynı anda mı bakıyor?

// SessizFark.java — ayni anda var olan uc bilesen, disaridaki tek bir degere iki farkli yanit veriyor
import java.util.*;

public class SessizFark {
    public static void main(String[] args) {
        MerkeziAyarlar.guncelle("mod", "normal");
        TekilBilesen eskiTekil = new TekilBilesen();

        MerkeziAyarlar.guncelle("mod", "bakim");
        HerIstekteBilesen yeniIstek1 = new HerIstekteBilesen();
        HerIstekteBilesen yeniIstek2 = new HerIstekteBilesen();

        Olcum.goster("eskiTekil.mod()", eskiTekil.mod());
        Olcum.goster("yeniIstek1.mod()", yeniIstek1.mod());
        Olcum.goster("yeniIstek2.mod()", yeniIstek2.mod());

        long farkliGorusSayisi = new HashSet<>(List.of(eskiTekil.mod(), yeniIstek1.mod(), yeniIstek2.mod())).size();
        Olcum.goster("bu ucunden herhangi biri hata verdi mi", "hayir");
        Olcum.goster("ayni anda gozlenen farkli deger sayisi", farkliGorusSayisi);
    }
}
eskiTekil.mod()                                     : normal
yeniIstek1.mod()                                    : bakim
yeniIstek2.mod()                                    : bakim
bu ucunden herhangi biri hata verdi mi              : hayir
ayni anda gozlenen farkli deger sayisi              : 2

eskiTekil bilinçli olarak değişiklikten önce kuruluyor, yeniIstek1 ile yeniIstek2 değişiklikten sonra — sıralama koşumda açıkça yazılı, çünkü gerçek bir uygulamada hangi bileşenin ne zaman kurulduğu genellikle bu kadar net görünmez; istekler saniyeler, hatta milisaniyeler arayla gelir ve aralarına sıkışan bir değişiklik hiçbir zaman fark edilmeyebilir. Üç çağrı da başarıyla dönüyor, üçü de bir değer veriyor, hiçbiri istisna fırlatmıyor. GT26. Aynı anda var olan iki bileşen dışarıdaki aynı anahtara iki farklı yanıt verebilir, ikisi de hatasız: eskiTekil uygulamanın normal modda olduğunu söylerken, yeniIstek1 ve yeniIstek2 bakım modunda olduğunu söylüyor — üçü de aynı mod anahtarına bakıyor, üçü de “doğru” cevap verdiğinden emin. GT27. Bu fark hiçbir yerde hata olarak görünmez; günlüğe hiçbir uyarı düşmez, hiçbir istisna fırlamaz, çünkü her bileşen kendi okuduğu değere göre tutarlı davranıyor. Fark ancak eskiTekil.mod() ile yeniIstek1.mod() yan yana konduğunda, dışarıdan bakan biri ikisini karşılaştırdığında görünüyor — kod içinde bu karşılaştırmayı kimse yapmıyor, çünkü eskiTekil ile yeniIstek1 birbirinin varlığından habersiz. Kursun daha önceki sessiz kusurları (yanlış yazılmış ayar adı, yanlış işaretlenmiş ölçüm alanı) en azından tek bir bileşenin içindeydi; bu kusur bileşenler arasında, ve hiçbir tek bileşenin kaynağı bakılarak görülemez.

Üç bileşen türünün dışarıdaki değişikliğe verdiği yanıt tek tabloda özetlenebilir:

Bileşen türü Değişiklikten sonra ne görüyor Değişikliği ne zaman görüyor
TekilBilesen eski değer, sonsuza kadar asla
HerIstekteBilesen güncel değer bir sonraki kurulumda
YenilenebilirBilesen eski değer, yenile() çağrılana kadar yalnız çağrıldığında

Tablonun hiçbir satırı “yanlış” değil — üçü de kendi kuralına göre tutarlı çalışıyor. Sorun kuralın kendisinde değil, aynı uygulamanın farklı bileşenlerinin farklı kurallarla kurulmuş olabilmesinde: eskiTekil ile yeniIstek1 aynı MerkeziAyarlar’a bakıyor, ikisi de doğru çalışıyor, ve yine de birbirinden farklı bir gerçeği söylüyorlar.

Özet

  • Merkezî yapılandırma dışarıda tutulur; bir bileşenin bu değeri ne zaman gördüğü kendi kapsamına bağlıdır.
  • Tekil bir bileşen değeri yalnız kurulduğu anda okur; dışarıdaki değişiklik o örneğe hiç ulaşmaz.
  • Her istekte yeniden kurulan bir bileşen değeri her seferinde yeniden okur; değişiklik bir sonraki kurulumda görünür.
  • Yenileme kendiliğinden olmaz, açık bir çağrı gerektirir; çağrılmadıkça tekil bileşen eski değeri tutmaya devam eder.
  • Aynı anda var olan iki bileşen dışarıdaki aynı değere iki farklı, ikisi de hatasız yanıt verebilir; fark yalnız yan yana karşılaştırıldığında görünür.

Sonraki Adım

Bu ders bir değerin hangi bileşene ulaştığını ölçtü; sıradaki ders bir çağrının hangi hedefe ulaştığını soruyor. Bir bileşen başka bir bileşeni çağırmak istediğinde o hedefi nereden buluyor — kaynakta yazılı bir adresten mi, bir kayıttan mı, yoksa kabın kendi çözümünden mi? Gerçek bir ağ çağrısı yok, ama hedefin nasıl belirlendiği yine ölçülebilir.

İ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