Ders 08 / 11
Veri Çarpıklığı
Dengesiz bölüşümün ölçülmesi ve işçi eklemenin neden bir çözüm olmadığının sayılması: aynı 2200 satır abone anahtarıyla bölüştürüldüğünde dört işçinin yükü 539 ile 561 arasında kalıyor ve çarpıklık 1,02 çıkıyor, bolge anahtarıyla bölüştürüldüğünde yük 374, 0, 0 ve 1826 oluyor, çarpıklık 3,32'ye çıkıyor ve iki işçi hiç satır almıyor. Yanlış anahtarla işçi sayısı artırıldığında çarpıklık 1,66'dan 3,32'ye, 6,64'e ve 6,88'e çıkıyor, boş işçi sayısı 0'dan 13'e yükseliyor; tek işçide 2250 olan süre iki işçiyle 3691'e çıkıyor ve tabanın altına ancak on altı işçide iniyor, bu arada toplam iş 2200'den 8635'e taşınıyor. Doğru anahtarla ise hiçbir işçi sayısında satır taşınmıyor, toplam iş 2200'de sabit kalıyor ve süre 215'e kadar iniyor. Üç bölüşüm de bölge toplamlarının birebir aynısını üretiyor.
İçindekiler
Bir önceki dersin bütün tablolarında bir sayı sessizce duruyordu: olgu tarafının işçi yükü
[374, 0, 0, 1826]. Dört işçinin ikisi hiç satır almamıştı ve bütün süre hesapları en yüklü
işçinin 1826 satırı üzerinden yapılmıştı. İki ders boyunca yavaşlığın kaynağı hareket olarak
arandı; oysa bu düzende işçilerin yarısı hiç çalışmıyordu ve bu, hareketten bağımsız bir
kayıptır.
Bu ders bölüşümün kendisine bakar. Ölçülen şey satırların işçilere ne kadar dengesiz dağıldığı, bu dengesizliğin nereden geldiği ve dengesiz bir bölüşümde işçi eklemenin ne işe yaradığıdır. Sonuncusu bu kursun ikinci iddiasının en açık örneğidir.
- DB19. Kaynak, tüketim satırları ve küme kurgudur ve ders içinde üretilir. Hiçbir dağıtık işleme çatısı, kaynak yöneticisi ya da dosya sistemi çağrılmaz. Tohum 20260218.
- DB20. Veri çarpıklığı (data skew) en yüklü işçinin işçi başına düşen ortalamaya oranıdır. 1,00 kusursuz dengedir; büyüdükçe bir işçi ötekilerden fazla iş yapıyor demektir.
- DB21. Süre en yüklü işçinin işidir, dolayısıyla çarpıklık doğrudan süreye yazılır. Süre bu modelin kendi birimidir. Toplam iş ayrı sayılır.
- DB22. Bölüşüm anahtarın karmasıyla yapılır ve aynı anahtar değeri hep aynı işçiye gider. Bunun iki sonucu vardır: bir anahtar değerinin satırları bölünemez, ve iki ayrı değer aynı işçiye çakışabilir.
- DB23. İndirgeme bütün tablolarda
aboneanahtarı üzerinden yapılır; değişen tek şey satırların hangi anahtarla bölüştürüldüğüdür.abonebu yüzden doğru,bolgeyanlış bölüşüm anahtarıdır. - DB24.
AG_BEDELI= 3 veGOREV_SABIT= 50 birer seçimdir. Bu dersin çarpıklık sayıları ikisinden de bağımsızdır; süre ve toplam iş sayıları değildir. - DB25. Taban çizgisi tek işçidir: karıştırma yok, çarpıklık 1,00, süre 2250, toplam iş 2200.
- DB26. Bütün bölüşümler birebir aynı sonucu üretir; ölçülen tek şey bedeldir.
- DB27. Kümenin çözünürlüğü: satır 2200, işçi en çok 16. Dört işçide çarpıklığın adımı 0,0018’dir; bu ölçüde okunan farklar bu adımın çok üstündedir.
Çarpıklık Bölüşümün Ölçüsüdür
Aşağıdaki blok aynı 2200 satırı üç ayrı anahtarla dört işçiye böler, her bölüşümün çarpıklığını hesaplar ve üçünün ürettiği bölge toplamlarını karşılaştırır.
# KURGUDUR. Olcum aginin sayac okumalari , tuketim satirlari ve kume ders icinde # uretilir; hicbir dagitik isleme catisi ya da kaynak yoneticisi cagrilmaz. Tohum 20260218. TOHUM, M32 = 20260218, 0xFFFFFFFF def uretec(t): x = ((t ^ (t >> 16)) * 2246822507) & M32 x = ((x ^ (x >> 13)) * 3266489909) & M32 s = [(x ^ (x >> 16)) & M32] def sonraki(): s[0] = (s[0] * 1664525 + 1013904223) & M32 return s[0] / 4294967296 return sonraki BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"] TIP = ["mesken", "isyeri"] DONEM = [f"2026-{a:02d}" for a in range(1, 13)] ISCI, AG_BEDELI, GOREV_SABIT = 4, 3, 50 ABONE = {} for i in range(200): r = uretec(TOHUM + 37 * i) ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)], "baslangic": 10000 + int(r() * 60000)} def satirlar(): """Hattan cikan tuketim satirlari. Saglam kaynakta ayikla ve tekille asamalari satir dusurmez; tuketim onceki donemin endeksinden cikarilarak bulunur.""" ham = [] for i, (ab, a) in enumerate(ABONE.items()): e = a["baslangic"] for d in DONEM: r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d)) e += 4 + int(r() * 46) ham.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"], "endeks": e, "birim": "m3"}) tablo, cikti = {(k["abone"], k["donem"]): k for k in ham}, [] for k in ham: i = DONEM.index(k["donem"]) onceki = tablo.get((k["abone"], DONEM[i - 1])) if i else None if onceki is not None: cikti.append(dict(k, m3=k["endeks"] - onceki["endeks"])) return cikti def izno(m): h = 2166136261 for c in str(m): h = ((h ^ ord(c)) * 16777619) & 0xFFFFFFFF return h def dagit(kayitlar, anahtar, isci=ISCI): """Satirlari anahtara gore isciye atar. Ayni anahtar hep ayni isciye gider.""" kova = {i: [] for i in range(isci)} for k in kayitlar: kova[izno(k[anahtar]) % isci].append(k) return kova def yuk(kova): """Carpiklik: en yuklu iscinin ortalamaya orani.""" n = [len(v) for v in kova.values()] return {"toplam": sum(n), "en_yuklu": max(n), "en_az": min(n), "carpiklik": round(max(n) / (sum(n) / len(n)), 4)} def karistir(kova, yeni_anahtar, isci=ISCI): """Yeniden bolustur. Isci degistiren satir agdan gecer.""" yeni, tasinan = {i: [] for i in range(isci)}, 0 for eski, kayitlar in kova.items(): for k in kayitlar: hedef = izno(k[yeni_anahtar]) % isci if hedef != eski: tasinan += 1 yeni[hedef].append(k) return yeni, tasinan def maliyet(kova, tasinan=0, isci=ISCI): """Sure = en yuklu iscinin isi (paralel). Toplam is ayrica sayilir.""" n = [len(v) for v in kova.values()] return {"sure": max(n) + tasinan * AG_BEDELI // isci + GOREV_SABIT, "toplam_is": sum(n) + tasinan * AG_BEDELI, "tasinan": tasinan} def bolge_toplam(kova): """Her isci once kendi payinin bolge toplamini cikarir , sonra birlestirilir.""" son = {} for kayitlar in kova.values(): ara = {} for k in kayitlar: ara[k["bolge"]] = ara.get(k["bolge"], 0) + k["m3"] for b, v in ara.items(): son[b] = son.get(b, 0) + v return tuple(sorted(son.items())) TUM = satirlar() print(f"hattan cikan satir {len(TUM)} , isci {ISCI} , ag bedeli {AG_BEDELI}") print("bolge basina satir: " + " , ".join(f"{b} {sum(1 for k in TUM if k['bolge'] == b)}" for b in BOLGE)) print("bolge hangi isciye dusuyor: " + " , ".join(f"{b} {izno(b) % ISCI}" for b in BOLGE)) print("\nanahtar farkli deger isci yuku en yuklu en az carpiklik") for a in ("abone", "bolge", "donem"): k, y = dagit(TUM, a), yuk(dagit(TUM, a)) print(f"{a:<8} {len(set(x[a] for x in TUM)):>12} {str([len(v) for v in k.values()]):<24}" f"{y['en_yuklu']:>6} {y['en_az']:>6} {y['carpiklik']:>10}") SONUC = {a: bolge_toplam(dagit(TUM, a)) for a in ("abone", "bolge", "donem")} print(f"\nuc bolusumun urettigi sonuc tek mi: {len(set(SONUC.values())) == 1}") print("bolge toplami: " + " , ".join(f"{b} {v}" for b, v in SONUC["abone"]))
hattan cikan satir 2200 , isci 4 , ag bedeli 3 bolge basina satir: dogu 374 , bati 341 , kuzey 506 , guney 440 , merkez 539 bolge hangi isciye dusuyor: dogu 0 , bati 3 , kuzey 3 , guney 3 , merkez 3 anahtar farkli deger isci yuku en yuklu en az carpiklik abone 200 [539, 550, 561, 550] 561 539 1.02 bolge 5 [374, 0, 0, 1826] 1826 0 3.32 donem 11 [600, 600, 400, 600] 600 400 1.0909 uc bolusumun urettigi sonuc tek mi: True bolge toplami: bati 9164 , dogu 9695 , guney 11721 , kuzey 13338 , merkez 14536
Son iki satır bütün dersin ön koşuludur. Üç bölüşüm de birebir aynı bölge toplamlarını
üretir; hangi anahtarla bölüşüldüğünden bağımsız olarak her satır hesaba tam bir kez girer. Bu
kursun üçüncü iddiasıdır ve buradaki biçimi en sert olanıdır: sonucu denetleyen hiçbir sınama
bolge bölüşümündeki dengesizliği göremez. Çarpıklık bir doğruluk sorunu değil, yalnızca
sayıldığında görünen bir bedeldir.
İlk tablo çarpıklığın nereden geldiğini gösterir. abone anahtarında 200 farklı değer vardır,
dört işçiye 539 ile 561 arasında dağılırlar ve çarpıklık 1,02’dir. donem anahtarında 11
farklı değer vardır — hattın ilk dönemi tüketim hesaplanamadığı için düşmüştür — ve 11 değer dört
işçiye 3, 3, 2, 3 olarak bölündüğü için yük 600, 600, 400, 600 ve çarpıklık 1,0909 olur.
bolge anahtarında ise yalnız 5 farklı değer vardır ve çarpıklık 3,32’ye çıkar.
Üçüncü satırın nedeni ikinci satırda yazılıdır. Beş bölgenin dördü de üçüncü işçiye düşer:
341 artı 506 artı 440 artı 539 tam olarak 1826 eder. Geriye kalan tek bölge dogu, tek başına
sıfırıncı işçidedir ve iki işçi hiç satır almaz. Burada iki ayrı mekanizma üst üste biner.
Birincisi anahtarın azlığıdır: beş farklı değer en çok beş işçiyi doldurabilir. İkincisi
karma çakışmasıdır: beş değerden dördü aynı kovaya düşmüştür.
Bunun ayırt edilmesi gereken bir sonucu var. Bölgeler kendi içlerinde çok dengesiz değildir; en küçüğü 341, en büyüğü 539 satır taşır ve aralarındaki oran ikinin altındadır. Yani veri, kendi başına, çarpık değildir. Çarpıklığı üreten şey anahtar ile işçi sayısının birlikte davranışıdır. “Veri çarpıktı” cümlesi bu yüzden eksiktir; çarpıklık verinin bir özelliği değil, bölüşümün bir özelliğidir ve bölüşüm bir karardır.
İşçi Eklemek Bir Çözüm Değildir
Dengesiz bir bölüşümde akla gelen ilk düzeltme daha çok işçidir. Aşağıdaki blok aynı süpürmeyi
iki anahtarla yapar: yanlış olanla (bolge) ve doğru olanla (abone). İndirgeme her ikisinde de
abone üzerindendir.
# Bu blok ilk bloktaki satirlar() , izno() , dagit() , yuk() , karistir() , # maliyet() ve TUM tanimlarini surdurur. Indirgeme her iki tabloda da abone # anahtari uzerinden yapiliyor; degisen tek sey bolusum anahtari. def supur(bolusum): print(f"bolusum anahtari {bolusum} , indirgeme abone") print("isci carpiklik en yuklu bos isci tasinan sure toplam is") for isci in (1, 2, 4, 8, 16): k = dagit(TUM, bolusum, isci) _, t = karistir(k, "abone", isci) m, y = maliyet(k, t, isci), yuk(k) print(f"{isci:>4} {y['carpiklik']:>10} {y['en_yuklu']:>9}" f" {sum(1 for v in k.values() if not v):>9}" f" {t:>8} {m['sure']:>6} {m['toplam_is']:>10}") supur("bolge") print() supur("abone")
bolusum anahtari bolge , indirgeme abone isci carpiklik en yuklu bos isci tasinan sure toplam is 1 1.0 2200 0 0 2250 2200 2 1.66 1826 0 1210 3691 5830 4 3.32 1826 2 1738 3179 7414 8 6.64 1826 6 1958 2610 8074 16 6.88 946 13 2145 1398 8635 bolusum anahtari abone , indirgeme abone isci carpiklik en yuklu bos isci tasinan sure toplam is 1 1.0 2200 0 0 2250 2200 2 1.0 1100 0 0 1150 2200 4 1.02 561 0 0 611 2200 8 1.04 286 0 0 336 2200 16 1.2 165 0 0 215 2200
İlk tablonun ikinci satırı bu kursun ikinci iddiasıdır: tek işçide süre 2250 iken, ikinci işçi eklendiğinde 3691‘e çıkar. İşçi eklemek işi kötüleştirmiştir. Nedeni okunabilir: tek işçide karıştırma yoktur, çünkü bütün satırlar zaten aynı yerdedir. İkinci işçi ortaya çıktığı anda indirgeme anahtarı bölüşüm anahtarından ayrışır, 1210 satır ağdan geçer ve toplam iş 2200’den 5830’a sıçrar. Paralellik bedava değildir ve bu düzende ilk adımı negatiftir.
Süre ancak dörtten sonra inmeye başlar, ama tek işçilik tabanın altına ancak on altı işçide
iner (1398). Dört işçide 3179, sekiz işçide 2610 — her ikisi de 2250’nin üstündedir. Yani
bolge anahtarıyla bölüştürülmüş bir iş, sekiz işçilik bir kümede tek bir işçiden hâlâ
yavaştır. Bu tablo yazılmadan “kümeyi büyüttük, hızlandı” cümlesinin doğru olup olmadığı
bilinemez.
En yüklü işçi sütunu bunun mekanizmasını verir ve tablonun en çarpıcı sayısı odur: iki, dört ve sekiz işçide en yüklü işçinin yükü 1826’da sabittir. İşçi sayısı dört katına çıkarken o işçi tek bir satır bile devretmez, çünkü ona düşen dört bölge her üç bölüşümde de aynı kovada kalır. Süredeki iniş (3691, 3179, 2610) yükün azalmasından değil, yalnızca taşıma payının daha çok işçiye bölünmesinden gelir. Yük ilk kez on altı işçide kırılır ve 946’ya iner.
Çarpıklık sütunu işçi eklendikçe kötüleşir: 1,66, 3,32, 6,64, 6,88. Boş işçi sayısı 0’dan
2’ye, 6’ya ve 13’e çıkar. On altı işçilik kümede yalnız üç işçi satır almaktadır. Bunun
sınırı anahtarın kendisinde yazılıdır: bolge beş farklı değer taşır, dolayısıyla kaç işçi
eklenirse eklensin en çok beş işçi satır alabilir. Bir anahtar değerinin satırları
bölünemediği için en yüklü işçi de en büyük bölgenin altına, yani 539 satırın altına inemez.
Süre bu yüzden kaç işçi eklenirse eklensin görev sabitiyle birlikte 589’un altına inemez.
İkinci tablonun on altıncı satırı bunu bir karşılaştırmaya çevirir: abone anahtarıyla süre
zaten 215’tir ve o eşiğin çok altındadır. Bölüşüm anahtarı yanlışsa işçi sayısı bir çözüm
değildir, çünkü yanlış anahtar kümeye bir tavan koyar.
Çarpıklığın artarken sürenin azalması ilk bakışta çelişkili görünür ve ayrı ayrı okunması gerekir. Çarpıklık bir orandır: işçi sayısı arttıkça ortalama küçülür, en yüklü işçinin yükü ise aynı hızda küçülmez, dolayısıyla oran büyür. Süre bir mutlak sayıdır ve taşıma payı işçilere dağıldığı için düşer. İkisi aynı şeyi söylemez: süre işin ne zaman bittiğini, çarpıklık kaç işçinin boşa ayrıldığını ölçer. On altı işçide 1398 süre, on üç işçinin boş beklemesi ve 8635 birimlik toplam iş karşılığında alınmıştır.
İki tablo yan yana konduğunda kursun kuralı görünür. bolge tablosunda süre 3691’den 1398’e
inerken toplam iş 5830’dan 8635’e çıkar; iki ölçü ters yönlere gider ve “dört kat hızlandı”
gibi bir cümle hangisinin ölçüldüğü yazılmadan eksiktir. abone tablosunda ise toplam iş
beş satırda da 2200’de durur, çünkü taşınan satır her işçi sayısında sıfırdır. Doğru
anahtarın kazandırdığı şey yalnız süre değildir: kümeye eklenen her işçinin karşılığında bir
şey ürettiği tek düzen budur.
Özet
- Veri çarpıklığı en yüklü işçinin ortalamaya oranıdır:
abonebölüşümünde 1,02,donembölüşümünde 1,0909,bolgebölüşümünde 3,32. Son düzende dört işçinin ikisi boştur ve yük[374, 0, 0, 1826]’dır. - Çarpıklık verinin değil bölüşümün özelliğidir. Bölgeler 341 ile 539 satır arasındadır, yani veri kendi başına dengelidir; çarpıklığı üreten şey anahtarın yalnız 5 farklı değer taşıması ve bu beş değerden dördünün aynı işçiye çakışmasıdır (341 + 506 + 440 + 539 = 1826).
- İşçi eklemek işi kötüleştirebilir: tek işçide süre 2250, iki işçide 3691‘dir, çünkü ikinci işçiyle birlikte 1210 satır ağdan geçer ve toplam iş 2200’den 5830’a çıkar. Süre tek işçilik tabanın altına ancak on altı işçide iner.
- Yanlış anahtarla işçi eklendikçe çarpıklık 1,66’dan 6,88‘e, boş işçi 0’dan 13’e çıkar.
Beş farklı değerli bir anahtar en çok beş işçi doldurabilir ve en büyük bölge 539 satır olduğu
için süre 589’un altına hiçbir işçi sayısında inemez;
aboneanahtarıyla süre on altı işçide zaten 215’tir. - Üç bölüşüm de bölge toplamlarının birebir aynısını üretir. Doğruluğu denetleyen hiçbir sınama
bu farkı göstermez;
bolgetablosunda süre 3691’den 1398’e inerken toplam iş 5830’dan 8635‘e çıkar,abonetablosunda toplam iş beş satırda da 2200’de durur.
Sonraki Adım
Üç derste yavaşlığın kaynağı iki başlıkta toplandı: satırların hareketi ve işçilerin dengesizliği. Her iki ölçüde de tek bir hesabın tek bir kez yapıldığı varsayıldı; aynı ara sonuca iki ayrı sorunun ihtiyaç duyması ya da bir işçinin iş bitmeden düşmesi hiç konuşulmadı. Oysa dağıtık bir işte aynı hesabın iki kez yapılması sık rastlanan bir kalemdir ve bir işçinin düşmesi, o ana kadar yapılmış işin ne kadarının geri isteneceği sorusunu doğurur. Sonraki ders ara sonucun saklanmasını ölçer: aynı veriyi iki kez hesaplamakla bir kez hesaplayıp tutmak arasındaki farkı sayar ve tutmanın kendi bedelini yazar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.