Designing Data-Intensive Applications Üzerine Notlar

Mert Özler
14 min readMar 7, 2024

--

Bu yazıda gündelik iş hayatımda sıklıkla çözüm geliştirmeye çabaladığım problemleri daha iyi anlamak için okuduğum Martin Kleppman’ın 2017 yılında yayımlamış olduğu Designing Data-Intensive Applications kitabından aldığım notları ve her bölüm üstüne küçük özetleri aktaracağım. Günümüz teknolojilerinde eğer sizde yüksek yük alan bir sistemde çalışan bir yazılım mühendisiyseniz bu kitapta yaşadığınız problemleri ve çözümlerini görebilir, bakış açınızı genişletebilirsiniz.

Yazıya girişmeden önce bir uyarı yapmak istiyorum; buradaki notlar kitabın aslı yerine geçemez. Bu yalnızca kişisel bir inceleme, kitaptan aldığım izlenimler ve notlar olarak okunmalı. Kendi adıma bu kitabı okumaya girişmeden önce bu makale gibi bir ön okuma olanağımın olmasını istediğim için bu yazıyı yazıyorum. Takdir edersiniz ki burada kitapta bahsedilen tüm konuları işlemek mümkün olmayacaktır. Kitaptan aldığım bazı notları chapterler altında “tırnak” içerisinde alıntılarak kendi çevirimle buraya aktaracağım. Bu çevirilerde sektörde kullandığımız ve consensus sağlandığını düşündüğüm bazı kavramları Türkçeye çevirmedim (örneğin; transaction, query, read, write vb.) çünkü bunları Türkçeye çevirmek yazının anlaşılmasını zorlaştıracaktı.

Çevirimde hatalarım olursa lütfen bana ulaşınız, yazıyı düzenleyeceğim. Tekrardan bu yazıyı yüzeysel bir not veya ön okuma olarak kabul edebilirsiniz, eğer ki fikirleri merak ediyorsanız kitabı okumanızı tavsiye ederim.

Part 1: Foundations of Data Systems

Kitabın ilk part’ında data-intensive applicationları oluşturan unsurları detaylıca işliyor. İster tek sunucuda ister distributed sunucularda olsun, data application oluşturan bu unsurlara göz gezindiriyor. Bu part, 4 adet chapterden oluşuyor. Kitap ilerledikçe buradaki küçük parçalar ve kitapta bahsedilen bu küçük parçaların kendine has sorunlarına büyük ölçekte değiniliyor.

Chapter 1: Reliable, Scalable, and Maintainable Applications

Mini özet:

Bu bölümde data intensive applications üstünde temel düşünme yöntemlerini keşfetmeye çalışıyor. Buradaki bazı prensipleri kitabın başında veriyor ki ileride çeşitlenecek problemlere temel olsun. Bir uygulamanın fonksiyonel gereklilikleri (ne yapmalı, data nasıl ve nerede store edilmeli, nasıl retrive, search ve işlenmeli) ve bazı non-functional gereklilikleri (security, reliability, compliance, scability, compability and maintainability) özelliklerini inceliyor.

Reliability (Güvenilirlilik): Reliability’nin anlamı hata alındığı durumlarda bile sistemin doğru çalışmasıdır. Bu hata donanımda, yazılımda veya direkt insanda olabilir. Bir uygulamanın fault-tolerance tekniklerine göre tasarlanması gerekmektedir.

Scability (Ölçeklenebilirlik): Scability’nin anlamı bir uygulamanın yüksek yükte bile iyi perfomans göstermesidir. (Kitapta bunun için celebrity twitter kullanıcılarını örnek gösteriyor. Problem olarak; milyonlarca takipçiye sahip biri tweet attığında her bir takipçiye o tweetin anlık olarak ulaşması gerekiyor. Detaylı bilgi için araştırabilirsiniz.)

Maintainability (Sürdürülebilirlik): Maintainability’nin bir çok özelliği olduğunu fakat genel olarak uygulamayı geliştiren mühendisin ve operasyon ekiplerinin sistemde daha sağlıklı çalışabilmesini hedefler. İyi bir soyutlaman complexity’i azaltır ve open-closed prensiplerine uygun geliştirme yapmayı mümkün kılar. İyi işlevselliğin anlamı sistem sağlığı hakkında iyi görünürlülük (monitoring, alerting vb.) yakalamayı da kapsar.

Bu bölümden aldığım bazı notlar:

“Monitoring bize erken uyarı sinyallerini gösterebilir ve hangi koşulun ihlal edilip edilmediğini kontrol etmemize olanak tanır. Bir problem meydana geldiğinde, metrics problemin teşhis edilmesinde çok önemli olabilir.”

“Latency ve response time sıklıkla eş anlamlı olarak kullanılır ancak aynı şey değildir. Response time, müşterinin gördüğü şeydir; isteği işlemek için geçen sürenin (service time) yanı sıra, ağ gecikmeleri ve queue gecikmelerini (delay) de içerir. Latency, bir isteğin işlenmeyi beklediği süredir; bu süre zarfında gizli olarak hizmet beklenir.”

“Amazon, response time’daki 100ms’lik bir artışın satışları %1 oranında azalttığını gözlemledi ve diğerleri, 1 saniyelik yavaşlamanın müşteri memnuniyeti ölçümünü %16 oranında azalttığını bildirdi.”

“Bir requestin sonlanması için birden fazla backend call gerektiğinde, son kullanıcının requestinin tamamını yavaşlatmak için tek bir request yeterlidir.”

Bu bölümde bir uygulamanın bu üç özelliği sağlamanın zorlayıcı olacağından bahsediyor, çözüm önerileri için sonraki chapterlere geçiyoruz.

Chapter 2: Data Models and Query Languages

Mini Özet:

Bu bölümde data modellerine kısa bir bakış atıyoruz. Özette kitabın üstünden yüzeysel geçmeme rağmen kitapta da bütün data modellerinden bahsedemediğinden yakınıyor. Genel bir izlenimle yetiniyor. Tarihsel olarak data’nın one big tree ile başladığını fakat bunun realitonal databaseler için iyi bir çözüm olmadığından bahsediyor. NoSQl ve SQL databaselerini inceliyor. Böylelikle hem veritabanlarına giriş yapıyoruz, hem de reel hayat problemlerine karşı geliştirdiğimiz çözümlerin modellerimize etkisini görüyoruz.

Bu bölümden aldığım notlar:

“Data models belki de yazılım geliştirmenin en önemli parçasıdır çünkü çok derin bir etkiye sahiptir; yalnızca yazılımın nasıl yazıldığı üzerinde değil, aynı zamanda çözdüğümüz problem hakkında nasıl düşündüğümüz üzerinde de.”

“ID kullanmanın avantajı, insanlar için bir anlamı olmadığından hiçbir zaman değişmesine gerek olmamasıdır: ID, tanımladığı bilgiler değişse bile aynı kalabilir. İnsanlar için anlamlı olan herhangi bir şeyin gelecekte bir zamanda değişmesi gerekebilir ve eğer bu bilgi duplicate edilirse, tüm yedek kopyaların duplicate edilmesi gerekir. Bu, yazma (write) masraflarına yol açar ve tutarsızlık (inconsistency) riskine neder olur (bilginin bazı kopyaları güncellenirken diğerleri güncellenmez). Bu tür duplicationların kaldırılması, veritabanlarındaki normalizationların ardındaki temel fikirdir.”

“Document veritabanlarına bazen şemasız denir, ancak bu yanıltıcıdır, çünkü verileri okuyan kod alışılmadık bir şekilde bir tür yapı üstlenir — yani örtülü bir şema vardır, ancak bu veritabanı tarafından zorunlu kılınmaz.”

“Imperative (emir) dili, bilgisayara belirli işlemleri belirli bir sırayla gerçekleştirilmesini söyler. Kodda satır satır ilerlediğinizi, koşulları değerlendirdiğinizi, değişkenleri güncellediğinizi ve döngüyü bir kez daha dönüp dolaşmayacağınıza karar verdiğinizi düşünebilirsiniz.”

“SQL veya ilişkisel cebir gibi declarative (bildirimsel) sorgu dillerinde, yalnızca istediğiniz veri modelini belirtirsiniz — sonuçların hangi koşulları karşılaması gerekir ve verilerin nasıl dönüştürülmesini istersiniz (örneğin; sıralanır, gruplanır ve toplanır) ancak bu hedefe nasıl ulaşılacağını belirtmezsiniz. Hangi indexlerin ve hangi birleştirme yöntemlerinin kullanılacağına ve sorgunun çeşitli bölümlerinin hangi sırayla çalıştırılacağına karar vermek veritabanı sisteminin query optimizer’ına kalmıştır.”

Chapter 3: Storage and Retrieval

Mini Özet:

Bu bölümde veritabanlarının storage (depolama) ve retrieval (datayı geri çekme) işlemlerini nasıl yönettiğine odaklanıyor. Bir datayı veritabanında depoladığımızda ne oluyor ve bir query attığımızda bu data nasıl geri getiriliyor.

Bu bölümden aldığım notlar:

“En temel seviyede, bir veritabanı 2 işi yapmalıdır: herhangi bir data verdiğinizde, datayı store (depolamalı) etmeli ve tekrardan sorduğunuzda, aynı datayı size vermeli.”

“Index, birincil veriden türetilen ek bir yapıdır. Birçok veritabanı index eklemenize izin verir ve bu veritabanının içeriğini etkilemez; yalnızca sorguların performansını etkiler. Ek yapıların bakımı, özellikle write (yazma) işleminde ek yüke sebep olur. Writes (yazmalarda) bir dosyaya basitçe ekleme yapma performansını aşmak zordur çünkü bu mümkün olan en basit yazma işlemidir. Her türlü index genellikle yazma işlemini yavaşlatır çünkü her veri yazıldığında indexin de güncellenmesi gerekir.”

“(Index seçimi) önemli bir trade-off (takas)’dur; iyi seçilmiş bir index read sorgularını hızlandırır fakat her index write perfomansınızı yavaşlatır.”

Chapter 4: Encoding and Evolution

Mini Özet:

Bu bölümde veri yapılarını network veya disklerdeki byte’lara convert etmenin yollarını araştırıyor. Encoding’in detaylarının yalnızca verimini etkilemediğini, daha önemlisi uygulamanının yapısını ve gelecekte evrimleşme olanaklarını da etkilediğinden bahsediyor.

Bu bölümden aldığım notlar:

“Bir sistemin pürüzsüz bir şekilde çalışabilmesi için bizim compability’i (uyumluluk) iki yönlü sürdürmemiz gerekir;

Backward compability: Yeni kod eski kod tarafından yaratılmış eski datayı okuyabilmeli.

Forward compability: Eski kod yeni kod tarafından yaratılmış yeni datayı okuyabilmeli.”

“Programlama diline özgü kodlamlar tek bir programlama diliyle sınırlıdır ve çoğu zaman forward ve backward compability’i sağlamakta başarısız olur.”

“JSON, XML ve CSV gibi metinsel formatlar geniş ve compability özellikleri nasıl kullanıldığına bağlıdır.”

Part 2: Distributed Data

Kitabın ilk bölümünde data’nın tek bir makine üstünde depolandığı durumlarda geçerli olabilecek durumları detaylıca inceliyor. İkinci bölümde ise vites arttırıp soruyor; eğer birden fazla makinede çalışan bir datayı store ve retrieve edersek ne olur?

Bu bölüm daha yüksek bir ölçekte çalışma durumlarını inceliyor. Replication, partitioning, shared-nothing architectures yöntemleri sisteme implement etme caselerini inceliyor. Bu kadar yüksek bir ölçekte ve distribtued bir system’de transactionların nasıl olacağından ve consistency, consensus’un nasıl sağlanacağından bahsediyor. Bunun yanı dışı distributed systemlerde çalışmanın doğurduğu birçok challenger durumdan bahsediyor.

Chapter 5: Replication

Mini Özet:

Bu bölümde genel olarak replication problemlerine odaklanıyor. Replication’un birkaç amaca hizmet ediyor.

High Avability: Bir makine çöktüğü zaman bile (birkaç makine veya bütün datacenter) sistemin çalışabilir olması.

Disconnected Operation: Network kesintileri yaşandığı durumlarda bile uygulamanın çalışmaya izin vermesi.

Latency: Data’yı coğrafi olarak kullanıcılara yakın olması ve böylelikle kullanıcıların data ile daha hızlı erişime girebilmesi.

Scability: Yüksek ölçekte read’in tek bir makineden yapılmasındansa read replicalarından yapılması.

Bu basit hedefin yanı sıra — aynı datanın birkaç makine üstünde kopyalanması- replication’un birçok problem yaratabileceğinden bahsediyor. Problem üstüne detaylıca düşünüldüğünde concurrency ve her şey ters gidebilir.

Bu bölümde birkaç replication yönteminden bahsediyor;

Single-leader replication: Client’lar tüm write’ları tek node’a (the leader) yönlendirir, bu the leader node’u ise tüm data değişikliklerinin eventlerini diğer replicalara (followers) yollar. Read queryleri perfomanslı bir şekilde yapılabilir fakat followers üstünden yapılan read queryleri eksik olabilir.

Multi-leader replication: Client her write’ı birden fazla leader node’una yönlendirir. Leader node data change eventlerini her birine yollar.

Leaderless replication: Client her write’ı birden fazla node’a yönlendirir, ve birden fazla node paralelde doğru node’dan datayı alır.

Bu bölümden aldığım bazı notlar:

“Daha yüksek bir ölçeklendirme gerekiyorsa en basit yaklaşım daha güçlü bir makine satın almaktır. Bu tür shared-memory mimarisinde tüm bileşenler tek bir makine gibi ele alınabilir.”

“Buna karşılık, shared nothing architecture (bazen yatay ölçeklendirme olarak da adlandırılır) oldukça fazla popülerlik kazanmıştır. Bu yaklaşımda veritabanı yazılımını çalıştıran her makineye veya sanal makineye node adı verilir. Her node kendi CPU’larını, RAM’ini ve disklerini bağımsız olarak kullanır.”

“Verilerin birden fazla node’a dağıtılmasının iki yaygın yolu vardır;

Replication: Aynı verilerin bir kopyasını birkaç farklı düğümde, potansiyel olarak farklı konumlarda tutmak. Replication ve yedeklilik sağlar: Bazı node’lar kullanılmıyorsa veriler yine de kalan node’lardan sunulabilir. Replication perfomansı arttırmayı da sağlar.

Partitioning: Büyük bir veritabanını, farklı node’lara farklı bölümlerin atanabilmesi için partitioning adı verilen daha alt küçük kümelere bölmek (sharding olarak da bilinir.”

Chapter 6: Partitioning

Mini Özet:

Bu bölümde veriyi scale etmenin bir diğer yöntemi olan partitioningi inceliyor. Partitioning yukarıda da bahsettiğimiz gibi basitçe büyük bir veritabanını daha küçük bölümlere bölmeyi içerir. Temel amaç; data ve queryleri birden fazla makine üstünde yaymaktır, bir node’un tek başına yüksek bir yüke ulaşmasını engellemektir.

Partitioning’i anlamak için burada bir analojiden bahsediyor; anskilopedi. Anksikolopedi veya eskiden kullandığımız telefon rehberlerini partitioningi anlamak için kullanabiliriz. Burada key bazlı atamalar yapılıyor, örneğin anksilopedi için V harfinin bir partition olduğunu kabul edersek ve ben Venn Diagram’ı arıyorsam. V için yazılmış olan anskilopedinin içerisinde Venn Diagram’ını aramak sırasız ve karmaşık bir veriseti içerisinde aramaktan çokça faydalı olacaktır.

Bu bölümde tıpkı replication’da olduğu gibi birçok stratejiden bahsediyor fakat bunları burada detaylıca aktarmayacağım.

Bu bölümden aldığım bazı notlar:

“Partitioning’in temel amacı scability’dir.”

“Tek bir partitionda işlem yapan sorgular için, her node kendi partition’u için sorguları bağımsız olarak yürütebilir, bu nedenle query işlem hızı daha fazla node eklenerek ölçeklendirilebilir. Büyük, karmaşık query’ler potansiyel olarak birçok düğüm üzerinde paralel olarak yürütülebilir, ancak bu önemli ölçüde zorlanır.”

“Aralıklar (partitionlar için ayarlanan range) arasındaki sınırları bildiğinizde, belirli bir key’in hangi partition’da bulunduğunu kolayca belirleyebilirsiniz. Ayrıca, hangi partition hangi node’a atanmış olduğunu da bildiğinizde, isteğinizi doğrudan ilgili node’a iletebilirsiniz (veya ansiklopedide doğru kitabı raftan kaldırabilirsiniz.”

“Her bir partition’un kendi ikincil indexine (local index)sahip olmasındansa tüm partitiondaki verileri kapsayan global bir index oluşturabiliriz. Ancak bu index’i sadece bir node’da saklayamayız, çünkü büyük olasılıkla bottleneck haline gelir ve partitioning amaçlarını bozar.”

“Partitioning’in amacı, veri ve query yükünü birden çok makineye eşit bir şekilde yaymak, sıcak noktaları (oranla yüksek yüke sahip node’lar) önlemektir. Bu, verinize uygun bir patitioning şeması seçmeyi ve düğümlerin kümeden eklenmesi veya çıkarılması durumunda bölümleri yeniden dengelemeyi gerektirir.”

Chapter 7: Transactions

Mini Özet:

Bu bölümde transactionların uygulamamızın belirli concurrency, donanım ve yazılım hatalarında doğru davranabilmesi için kullanıması gereken bir soyutlama olduğundan bahsediyor. Transaction’un birçok problemi çözebileceğinden, transaction’u uygulamanın ve kullanmanın doğurabileceği bazı problemlerde bahsediyor. Bunlar için genel geçer prensipleri ve patternleri inceliyor.

Bu bölümden aldığım bazı notlar:

“Transaction’lar doğanın kanunu değildir; bir veritabanına erişen uygulamalar için programlama modelini basitleştirmek amacıyla oluşturulmuştur.”

“Atomicity, isolation, and durability veritabanının özellikleriyken consistency (ACID anlamında) uygulamanın bir özelliğidir. Uygulama tutarlılığı sağlamak için veritabanının atomicity’sine ve isolation özelliklerine güvenebilir, ancak bu yalnızca veritabanına bağlı değildir. Bu nedenle C harfi aslında ACID’e ait değildir.”

“Distributed data store’ların birçoğu partitionlar arasında uygulanması zor olduğundan çok multi-object transaction’lardan vazgeçmiştir ve high avability veya perfomansın gerekli olduğu bazı senaryolarda buna engel olabilirler.”

“İki transaction aynı verilere dokunmuyorsa, ikisi de sıraya bağlı olmadığından güvenli bir şekilde paralel olarak çalıştırılabilirler. Concurrency sorunları (race conditions) yalnızca bir transaction başka bir transaction tarafından eşzamanlı olarak değiştirilen verileri okuduğudna veya iki işlem aynı verileri aynı anda değiştirmeye çalıştığında devreye girer.”

“Buradaki fikir (snapshot isolation) her transaction’un veritabanının tutarlı bir anlık görüntüsünden (snapshot) okunmasıdır; yani transaction, transaction başlangıcında veritabanında işlenen tüm verileri görür. Veriler daha sonra başka bir transaction tarafından değiştirilse bile, her transaction yalnızca o belirli zaman noktasına ait eski verileri görür (…) Performans açısından bakıldığında snapshot isolation’un temel ilkesi, reader’ların writer’ları engellememesi ve writer’ların da reader’ları asla engellememesidir.”

Chapter 8: The Trouble with Distributed Systems

Mini Özet:

Bu bölümde distributed systemlerde çalışmanın zorluklarından bahsediyor. Örnek olarak; herhangi bir packet’i network üstünden iletmeye çalıştığınızda gecikmeler veya paket kayıpları yaşanabilir. Bir node’un saati diğer node’lardan farklı olarak çalışabilir ve bu anlık olarak zamanda ileri veya geriye zıplamaya yol açabilir. Bir process’in işlemi sırasında pause durumları yaşanabilir. Multi datacenter bir sistemde bir node’dan diğer bir node’a istek atılırken o node ölü olabilir ve bu gibi durumlarda timeout senaryoları yaşanabilir.

Fault tolerate geliştirmek için ilk adım hataları tespit etmektir, ki bu oldukça zordur.

Bu bölüden aldığım bazı notlar:

“Distributed system’lerde çalışmak, tek bir bilgisayarda yazılım yazmaktan temel olarak farklıdır ve temel fark, işlerin ters gitmesine yol açacak pek çok yeni ve heyecan verici yolun bulunmasıdır.”

“Distributed system’lerin çalışmasını istiyorsak, kısmi arıza (fault) olasılığını kabul etmeli ve yazılıma fault tolerance mekanizmaları kurmalıyız. Başka bir deyişle, unreliable (güvenilir olmayan) bileşenlerden reliable (güvenilir) bir sistem kurmamız gerekiyor.”

“Uzun bir timeout, bir node’un öldüğünü bildirene kadar uzun süre beklemek anlamına gelir (ve bu süre zarfında kullanıcıların beklemesi veya hata mesajları görmesi gerekebilir.) Kısa bir timeout, arızları daha hızlı tespit eder, ancak aslında yalnızca geçici bir yavaşlamaya maruz kalan bir node’un yanlışlıkla ölü olarak ilan edilmesi riski daha yüksektir.”

“Distributed bir sistemde zaman zor bir iştir çünkü iletişim anlık (sync) değildir; bir mesajın network üzerinde bir makineden bir diğerine ulaşması zaman alır. Bir mesajın alındığı zaman her zaman gönderildiği zamandan daha geç olur, ancak ağdaki değişken gecikmeler nedeniyle ne kadar sonra olduğunu bilemeyiz. Bu gerçek bazen birden fazla söz konusu olduğunda olayların meydana gelme sırasını belirlemek zorlaşır.”

Chapter 9: Consistency and Consensus

Mini Özet:

Bu bölümde distributed system’lerde consistency yani tutarlılık ve consensus yani uzlaşmanın nasıl sağlanması gerektiği konusunu irdeliyor. Birden fazla node’da çalışan applicationların network üzerinde gezinen dataların ve event driven mimarilerin doğurabileceği challengeleri çözmek için pattern ve stratejileri inceliyor. Linearizability’e ve CAP teoremine derin bir bakış atıyor.

Bu bölümden aldığım bazı notlar:

“Fault tolerance sistemler oluşturmanın en iyi olur, yararlı garantilere sahip bazı genel amaçlı soyutlamalar bulmak, bunları bir kez uygulamak ve daha sonra bu uygulamaların bu garantilere güvenmesine izin vermektir.”

“Distributed systemler için en önemli soyutlamalardan biri consensus’tur; yani tüm düğümlerin bir şey üzerinde anlaşmasını sağlamak.”

“Lineriazability, bir kaydın (bireysel bir obje) okuma ve yazma işlemlerinin güncellik garantisidir. İşlemleri transaction’lar halinde gruplandırmaz, dolayısıyla conflict (çakışmaları) somutlaştırmak gibi ek önlemler almadığınız sürece write conflict gibi sorunları önlemez.”

“CAP bazen Consistency, Availability, Partition olarak sunulur; üçünden ikisini seçin. Ne yazık ki, bunu bu şekilde koymak yanıltıcıdır çünkü ağ bölünmeleri bir tür hatadır, dolayısıyla bunlar hakkında seçim yapabileceğiniz bir değildir; bunlar gerçekleşecektir beğenseniz de beğenmeseniz de.”

“Consensus, distributed hesaplamadaki en önemli ve temel sorunlardan biridir. Görüneşe göre basit duruyor; gayri resmi olarak amaç, birkaç node’un bir şey üzerinde anlaşmaya varmasını sağlamaktır. Bunun çok da zor olmaması gerektiğini düşünebilirsiniz. Ne yazık ki birçok bozuk sistem, bu sorunun çözülmesinin kolay olduğu yanılgısıyla inşa edilmiştir.”

“2PC, dağıtılmış bir veritabanınca atomic taahüt sağlar; bunları tamamen ayrı kavramlar olarak düşünmek ve adlardaki talihsiz benzerliği göz ardı etmek en iyisidir.”

Part 3: Derived Data

Bu bölümü kitabın diğer bölümlerinin hazırladığı challenger bölüm olarak yorumlayabiliriz. Bu bölümde genel olarak tekrardan vites arttırarak derived yani türetilmiş data konusu başlığı altında batch ve streaming processingi inceliyor. Kitabın son chapter’inde ise distributed systemlerin geleceğini inceliyor.

Bölüme geçmeden önce yüksek seviyede datanın işlenmesi ve store edilmesi ile ilgili 2 ana kategorinin olduğunu hatırlatalım;

Systems of record: Gerçeğin kaynağı (source of truth) olarak da bilinen bir kayıt sistemi, verilerinizin yetkili bir sürümünü tutar. Örneğin kullanıcı girişi olarak yeni veriler geldiğinde, ilk önce buraya yazılır. Her gerçek tam olarak bir kez temsil edilir (temsil genelden normalization prensiplerine uygun yapılır). Başka bir sistem ile record sistemi arasında herhangi bir tutarsızlık var, record sistemindeki değer (tanım gereği) doğru olandır.

Derived data systems: Türetilmiş bir sistemdeki veri, mevcut bazı verilerin başka bir sistemden alınarak dönüştürülmesi veya bir şekilde işlenmesi sonucudur. Türetilmiş verileri kaybederseniz orjinal kaynaktan yeniden oluşturabilirsiniz. Klasik bir örnek önbellektir: Veriler varsa önbellekten sunulabilir, ancak önbellek ihtiyacınız olanı içermiyorsa temeldeki veritabanına geri dönebilirsiniz. Normalleştirilmemiş değerler, indexler ve materyalleştirilmiş view’lar da bu kategoriye girer.

Tenik olarak konuşursak aslında derived datalar, mevcut bilgilerin kopyalanması anlamında gereksizdir. Ancak read sorgularında iyi performans elde etmek için genellikle gereklidir. Genellikle denormalize edilir. Tek bir kaynaktan birkaç farklı veri kümesi türetilebilir, böylece verilere farklı “bakış açılarından” bakabilirsiniz.

Mini not: buradaki bölümleri özümsemek oldukça zorlayıcı, bu yüzden burada notlarla detaylandırmak yerine mini özetlerle yetineceğim. Umuyorum ki önümüzdeki senelerde bu kitabı tekrardan okuduğumda makalenin bu kısmını daha fazla detaylandırabilirim.

Chapter 10. Batch Processing

Mini Özet:

Bu bölümde batch processing konusunu keşfediyoruz. Unix tool’lardan bazılarını ve MapReduce ve bazı dataflow engine’lerin tasarım felsefelerini inceliyor. Bu bazı tasarım ilkelerinden bazıları, inputların immutable (değişmez) olması, outputların (çıktıların) başka (henüz bilinmeyen) bir programın input’u olmasının amaçlanması ve karmaşık sorunları “bir şeyi iyi yapan” küçük araçlar olutşurarak çözmesidir.

“Distributed batch processing frameworklerin çözmesi gereken 2 ana problem şunlardır;

Partitioning: MapReduce’da mapper’lar giriş dosyası bloklarına göre partition’a ayrılır. Mapper’ların output’u yeniden partition’lanır, sıralanır ve yapılandırabilir sayıda reducer paritition’lara ayrılır.

MapReduce sonrası data flow engine’leri gerekmedikçe sıralamadan kaçınmaya çalışır, ancak aksi takdirde partitioning’e genel olarak benzer bir yaklaşım sergilerler.

Fault Tolerance: MapReduce sıklıkla diske yazar; bu tüm işi yeniden başlatmadan başarısız olan tek bir tasktan kurtarmayı kolaylaştırır, ancak hatasız durumda yürütmeyi yavaşlatır. Data flow engines ara durumun daha az gerçekleştirilmesini sağlar ve bellekte daha fazlasını tutar; bu bir node başarısız olursa daha fazla veriyi yeniden hesaplamaları gerektiğin anlamına gelir.”

Chapter 11. Stream Processing

Mini Özet:

Bu bölümde event streams’in hangi amaçlara hizmet ettiğini ve nasıl işleneceğini anlatıyor. Bazı yönlerden batch processing’e çok benzediğini sabit boyutlu bir input yerien sürekli olarak sınırsız (hiç bitmeyen) stream üzerinde gerçekleştirir.

Genel olarak distributed system’lerde kullandığımız Kafka ve RabbitMQ gibi çözümlerin implementasyonuna, event bazlı işlemlerin yapılandırılmasına, bir event’in birden fazla consume edilerek bir data üstünden farklı iş akışlarının yürütebilmesine değiniyor.

Bunun yanı sıra join’lerden bahsediyor.

Chapter 12. The Future of Data Systems

Mini Özet:

Bu bölümde genel olarak kitap boyunca incelenen problemlerin Martin Klepmann tarafından gelecekte hangi yönlerde yeni sorunlar doğurabileceğini ve bu sorunlar için nasıl çözümler geliştirilebileceği anlatılıyor.

Yazılımın ve data’nın dünya üzerinde çok etkisinin olmasıyla birlikte biz yazılım mühendislerinin ahlaki bir sorumluluğa sahip olmamız gerektiğinden bahsediyor.

Bu bölümden aldığım bazı notlar:

“Teknolojinin kendisi ne iyi ne kötüdür — önemli olarak nasıl kullanıldığı ve insanları nasıl etkilediğidir. Yazılım mühendislerinin yalnızca teknolojiye odaklanıp sonuçlarını görmezden gelmeleri yeterli değil diye düşünüyorum; Etik sorumluluk da bizlere düşüyor. Sorumluluk hakkında akıl yürütmek zordur fakat görmezden gelmemek de çok önemlidir.”

“Bir yazılım ve data’nın dünya üzerinde o kadar büyük bir etkisi var ki, biz mühendisler yaşamak istediğimiz türden bir dünyaya doğru çalışma sorumluluğu taşıdığımızı hatırlamalıyız: insanlara insanca ve saygılı davranan bir dünya. Umarım bu hedefe doğru birlikte çalışabiliriz.”

Kapanış:

Anlaşılması zor ve içeriği bir o kadar dolu olan bu kitap üstüne aldığım notlar ve mini özetleri içeren bu yazının sonuna geldik. Yazının sonuna gelmişken birkaç yorum yapmak istiyorum; şu anda aktif olarak çalıştığım ekipte data-intensive ve distributed system üstünde çalışıyorum. Dolayısıyla bu kitapta bahsedilen challenge’ları her sprint deneyimliyorum.

Bu kitabı okumak ve anlamak (her ne kadar tam olarak anlamak mümkün olmasa ve gelecekte tekrar döneceğim türden bir kitap olsa bile) işime ve çalıştığım scope’daki system’e bakış açımı zenginleştirdi.

Sektörde çalışan çoğu arkadaşımızın da bu gibi benzer problemlerle uğraşıyor. Umuyorum ki bu mini özet sizi bu kitabı daha derin incelemeye ve kitap için ön okuma niyetiyle bakıldığında faydalı olacaktır. Bu yazıda kitapta bahsedilen birçok şeyi atlamak zorunda kaldım aksi halde bu kitabı kopyalamak olurdu.

Bu yazının sizin için faydalı olması dileğiyle.

--

--