6.1 Kısaltmalar Savaşı: BASE vs. ASİT

"Kimyada pH, sulu bir çözeltinin bağıl asitliğini ölçer. pH ölçeği 0'dan (kuvvetli asidik maddeler) 14'e (kuvvetli alkalin maddeler) kadar uzanır; 25°C'deki saf suyun pH değeri 7'dir ve nötrdür.

Veri mühendisleri, işlemlerin güvenilirliği ile ilgili veritabanlarını karşılaştırmak için bu metaforu aldılar."

Muhtemelen fikir şuydu: pH ne kadar yüksekse, yani. veritabanı "alkalin" ("BASE") değerine ne kadar yakınsa, işlemler o kadar az güvenilirdir.

MySQL gibi popüler ilişkisel veritabanları, yalnızca ACID temelinde ortaya çıktı. Ancak son on yılda, bu ad altında çok farklı birkaç veritabanı türünü birleştiren sözde NoSQL veritabanları, ACID olmadan oldukça iyi iş çıkardı. Aslında, NoSQL veritabanları ile çalışan ve işlemleri ve bunların güvenilirliğini hiç umursamayan çok sayıda geliştirici var. Haklı olup olmadıklarına bakalım.

Genel olarak NoSQL veritabanı hakkında konuşamazsınız çünkü bu sadece iyi bir soyutlamadır. NoSQL veritabanları, veri depolama alt sistemlerinin tasarımında ve hatta veri modellerinde birbirinden farklılık gösterir: NoSQL, hem belge odaklı CouchDB hem de grafik Neo4J'dir. Ancak işlemler bağlamında onlar hakkında konuşursak, hepsi bir konuda benzer olma eğilimindedir: sınırlı atomite ve izolasyon versiyonları sağlarlar ve bu nedenle ACID garantileri sağlamazlar. Bunun ne anlama geldiğini anlamak için şu soruyu cevaplayalım: ASİT değilse ne sunuyorlar? Hiç bir şey?

Tam olarak değil. Ne de olsa, ilişkisel veritabanları gibi onların da kendilerini güzel bir pakette satmaları gerekiyor. Ve kendi "kimyasal" kısaltmalarını buldular - BASE.

6.2 Bir antagonist olarak BASE

Ve burada yine harf sırasına göre gitmeyeceğim, ancak temel terim olan tutarlılıkla başlayacağım. Tanıma etkinizi dengelemem gerekecek, çünkü bu tutarlılığın ACID'den gelen tutarlılıkla çok az ilgisi var. Tutarlılık terimiyle ilgili sorun, çok fazla bağlamda kullanılmasıdır. Ancak bu tutarlılığın çok daha geniş bir kullanım bağlamı vardır ve gerçekten de dağıtık sistemler tartışılırken tartışılan tutarlılık tam olarak budur.

Yukarıda bahsettiğimiz ilişkisel veritabanları, farklı düzeylerde işlem yalıtımı sağlar ve bunların en katı olanı, bir işlemin başka bir işlem tarafından yapılan geçersiz değişiklikleri görmemesini sağlar. Bir mağazada kasada duruyorsanız ve o anda hesabınızdan kira parası çekilir, ancak kira parası transferi işlemi başarısız olursa ve hesabınız eski değerine dönerse (para borçlandırılmadıysa), kasadaki ödeme işleminiz bu hareketleri herkes tarafından fark edilmeyecektir - sonuçta, bu işlem hiç gerçekleşmemiştir ve işlem izolasyonu gerekliliğine bağlı olarak, geçici değişiklikleri diğer işlemler tarafından fark edilemez.

Birçok NoSQL veritabanı, yalıtım garantisinden vazgeçer ve sonunda geçerli verileri göreceğiniz "nihai tutarlılık" sunar, ancak işleminizin geçersiz değerleri - yani geçici veya kısmen güncellenmiş veya eskimiş - okuma olasılığı vardır. Okurken ("okuma zamanında tembel") verilerin "tembel" modda tutarlı hale gelmesi mümkündür.

NoSQL, gerçek zamanlı analitik için bir veritabanı olarak tasarlandı ve daha yüksek hız elde etmek için tutarlılıktan fedakarlık ettiler. Ve BASE terimini icat eden aynı adam olan Eric Brewer, sözde "CAP teoremini" formüle etti, buna göre:

Dağıtılmış bilgi işlemin herhangi bir uygulaması için, aşağıdaki üç özellikten en fazla ikisini sağlamak mümkündür:

  • veri tutarlılığı ( tutarlılık ) - farklı düğümlerdeki (örneklerdeki) veriler birbiriyle çelişmez;
  • kullanılabilirlik ( kullanılabilirlik ) - dağıtılmış bir sisteme yapılan herhangi bir istek, doğru bir yanıtla sona erer, ancak tüm sistem düğümlerinin yanıtlarının aynı olacağına dair bir garanti yoktur;
  • bölüm toleransı (bölüm toleransı ) - Düğümler arasında bağlantı olmasa bile birbirlerinden bağımsız olarak çalışmaya devam ederler.

CAP'in çok basit bir açıklamasını istiyorsanız, işte buradasınız.

CAP teoreminin çalışmadığına ve genellikle çok soyut bir şekilde formüle edildiğine dair görüşler vardır. Öyle ya da böyle, NoSQL veritabanları genellikle aşağıdaki durumu açıklayan CAP teoremi bağlamında tutarlılığı reddeder: veriler birkaç örnekle bir kümede güncellendi, ancak değişiklikler henüz tüm örneklerde senkronize edilmedi. Unutmayın, yukarıda DynamoDB örneğinden bahsetmiştim, bu örnek bana: değişiklikleriniz dayanıklı hale geldi - işte size bir HTTP 200 - ama ben değişiklikleri yalnızca 10 saniye sonra gördüm? Bir geliştiricinin günlük hayatından bir başka örnek de alan adı sistemi olan DNS'dir. Bilmeyen varsa, o zaman bu tam olarak http (ler) adreslerini IP adreslerine çeviren "sözlük" dür.

Güncellenen DNS kaydı, önbellek aralığı ayarlarına göre sunuculara yayılır - bu nedenle güncellemeler hemen fark edilmez. Benzer bir zamansal tutarsızlık (yani, sonunda tutarlılık) bir ilişkisel veritabanı kümesinde (örneğin, MySQL) meydana gelebilir - sonuçta, bu tutarlılığın ACID'den gelen tutarlılıkla hiçbir ilgisi yoktur. Bu nedenle, bu anlamda SQL ve NoSQL veritabanlarının, bir kümedeki birkaç örnek söz konusu olduğunda çok farklı olma ihtimalinin düşük olduğunu anlamak önemlidir.

Ek olarak, uçtan uca tutarlılık, yazma isteklerinin sıra dışı yapılacağı anlamına gelebilir: yani, tüm veriler yazılacak, ancak sonunda alınacak değer, yazma kuyruğundaki son değer olmayacaktır.

ACID olmayan NoSQL veritabanları, uçtan uca tutarlılık modeli nedeniyle "yumuşak duruma" sahiptir, bu da sistemin durumunun girdi olmadan bile zaman içinde değişebileceği anlamına gelir. Ancak bu tür sistemler daha fazla erişilebilirlik sağlamaya çalışır. %100 kullanılabilirlik sağlamak önemsiz bir iş değildir, dolayısıyla "temel kullanılabilirlik"ten bahsediyoruz. Ve bu üç kavram birlikte: "temelde mevcut", "yumuşak durum" ("yumuşak durum") ve "nihai tutarlılık", BASE kısaltmasını oluşturur.

Dürüst olmak gerekirse, BASE kavramı bana ASİT'ten daha boş bir pazarlama ambalajı gibi görünüyor - çünkü yeni bir şey vermiyor ve veritabanını hiçbir şekilde karakterize etmiyor. Ve belirli veritabanlarına etiketler (ASİT, BASE, CAP) eklemek, yalnızca geliştiricilerin kafasını karıştırabilir. Yine de sizi bu terimle tanıştırmaya karar verdim, çünkü veritabanını incelerken onu atlamak zor ama artık ne olduğunu bildiğinize göre, bir an önce unutmanızı istiyorum. Ve izolasyon kavramına geri dönelim.

6.3 Yani BASE veritabanları ASİT kriterlerini hiç karşılamıyor mu?

Temel olarak, ACID veritabanlarının ACID olmayanlardan farklı olduğu nokta, ACID olmayanların aslında izolasyondan vazgeçmesidir. Bunu anlamak önemlidir. Ancak veritabanı belgelerini okumak ve onları Hermitage projesindeki adamların yaptığı gibi test etmek daha da önemlidir. Bunun veya bu veritabanının yaratıcılarının beyin çocuklarına tam olarak nasıl isim verdikleri o kadar önemli değil - ASİT veya BAZ, CAP veya CAP değil. Önemli olan şu veya bu veritabanının tam olarak ne sağladığıdır.

Veritabanının yaratıcıları, ASİT garantisi sağladığını iddia ediyorsa, muhtemelen bunun bir nedeni vardır, ancak bunun böyle olup olmadığını ve ne ölçüde olduğunu anlamak için kendiniz test etmeniz önerilir. Veritabanlarının bu tür garantiler sağlamadığını beyan ederlerse, bu şu anlama gelebilir:

  • DB, atomiklik garantisi sağlamaz. Bazı NoSQL veritabanları atomik işlemler için ayrı bir API sunarken (örn. DynamoDB);

  • DB izolasyon garantisi sağlamaz. Bu, örneğin, veri tabanının verileri yazıldığı sırayla yazmayacağı anlamına gelebilir.

Dayanıklılık garantisine gelince, birçok veritabanı performans uğruna bu noktadan ödün verir. Diske yazmak çok uzun bir işlemdir ve bu sorunu çözmenin birkaç yolu vardır. Veritabanı teorisine fazla girmek istemiyorum ama kabaca hangi yönden bakmanız gerektiğini anlamanız için, farklı veritabanlarının dayanıklılık sorununu nasıl çözdüğünü genel hatlarıyla anlatacağım.

Farklı veritabanlarını karşılaştırmak için, diğer şeylerin yanı sıra, belirli bir veritabanının veri depolama ve alma alt sisteminin altında hangi veri yapılarının yattığını bilmeniz gerekir. Kısacası: farklı veritabanlarının farklı indeksleme uygulamaları vardır - yani verilere erişimi organize eder. Bazıları verileri daha hızlı yazmanıza izin verir, diğerleri - daha hızlı okumanızı sağlar. Ancak genel olarak bazı veri yapılarının dayanıklılığı arttırdığı veya azalttığı söylenemez.

6.4 Farklı veritabanlarının verileri nasıl indekslediği ve bunun dayanıklılığı nasıl etkilediği ve daha fazlası

Verileri depolamak ve almak için iki ana yaklaşım vardır.

Verileri kaydetmenin en kolay yolu, günlük benzeri bir şekilde dosyanın sonuna işlemler eklemektir (yani, bir ekleme işlemi her zaman gerçekleşir): verileri eklemek, değiştirmek veya silmek isteyip istemediğimiz önemli değil - hepsi CRUD işlemleri basitçe günlüğe yazılır. Günlükte arama yapmak verimsizdir ve dizin burada devreye girer - verilerin tam olarak nerede depolandığıyla ilgili meta verileri depolayan özel bir veri yapısı. Günlükler için en basit indeksleme stratejisi, anahtarları ve değerleri takip eden bir karma haritadır. Değerler, log (log) olan ve diskte depolanan dosyanın içine yazılan veriler için bayt ofsetine referans olacaktır. Bu veri yapısı, verilerin kendisi diskteyken tamamen bellekte saklanır ve LSM ağacı (log yapılı birleştirme) olarak adlandırılır.

Muhtemelen şunu merak ettiniz: İşlemlerimizi her zaman dergiye yazarsak, o zaman fahiş bir şekilde büyüyecek mi? Evet ve bu nedenle, verileri bir miktar periyodiklikle "temizleyen", yani her anahtar için yalnızca en alakalı değeri bırakan veya silen sıkıştırma tekniği icat edildi. Ve diskte birden fazla oturum açmışsak, ancak birkaç tane varsa ve hepsi sıralanmışsa, o zaman SSTable ("sıralanmış dize tablosu") adlı yeni bir veri yapısı elde edeceğiz ve bu şüphesiz performansımızı artıracaktır. Bellekte sıralama yapmak istiyorsak, benzer bir yapı elde edeceğiz - sözde MemTable, ancak bununla ilgili sorun şu ki, ölümcül bir veritabanı çökmesi meydana gelirse, o zaman en son yazılan veriler (MemTable'da bulunur, ancak henüz yazılmamış) disk) kaybolur. Aslında,

İndekslemeye yönelik başka bir yaklaşım, B-ağaçlarına (“B-ağaçları”) dayanmaktadır. Bir B-ağacında, veriler sabit boyutlu sayfalarda diske yazılır. Bu veri blokları genellikle yaklaşık 4 KB boyutundadır ve anahtara göre sıralanmış anahtar-değer çiftlerine sahiptir. Bir B-ağacı düğümü, bir dizi sayfaya bağlantıları olan bir dizi gibidir. Maks. bir dizideki bağlantıların sayısına dal faktörü denir. Her sayfa aralığı, diğer sayfa aralıklarına bağlantılar içeren başka bir B-ağacı düğümüdür.

Sonunda, sayfa düzeyinde, tek tek sayfaları bulacaksınız. Bu fikir, düşük seviyeli programlama dillerindeki işaretçilere benzer, ancak bu sayfa referanslarının bellek yerine diskte saklanması dışında. Veritabanında INSERT'ler ve DELETE'ler meydana geldiğinde, bazı düğümler dallanma faktörüyle eşleşmek için iki alt ağaca bölünebilir. Veritabanı, işlemin ortasında herhangi bir nedenle başarısız olursa, verilerin bütünlüğü tehlikeye girebilir. Bunun olmasını önlemek için, B ağaçlarını kullanan veritabanları, her bir işlemin kaydedildiği bir "önceden yazma günlüğü" veya WAL tutar. Bu WAL, bozulmuşsa B ağacının durumunu geri yüklemek için kullanılır. Görünüşe göre B ağaçlarını kullanan veritabanlarını dayanıklılık açısından daha iyi yapan da bu. Ancak LSM tabanlı veritabanları, esas olarak WAL ile aynı işlevi gerçekleştiren bir dosyayı da koruyabilir. Bu nedenle, daha önce söylediklerimi ve belki birden fazla kez tekrarlayacağım: Seçtiğiniz veritabanının çalışma mekanizmalarını anlayın.

Bununla birlikte, B-ağaçları hakkında kesin olan şey, işlemsellik için iyi olduklarıdır: her anahtar, dizinde yalnızca bir yerde bulunurken, günlüğe kaydedilen depolama alt sistemleri, aynı anahtarın farklı parçalarda birden çok kopyasına sahip olabilir (örneğin , sonraki sıkıştırma gerçekleştirilir).

Ancak, dizinin tasarımı doğrudan veritabanının performansını etkiler. Bir LSM ağacıyla, diske yazma işlemleri sıralıdır ve B ağaçları birden çok rasgele disk erişimine neden olur, dolayısıyla yazma işlemleri LSM ile B ağaçlarından daha hızlıdır. Aradaki fark, sıralı yazma işlemlerinin rasgele yazmalardan çok daha hızlı olduğu manyetik sabit disk sürücüleri (HDD'ler) için özellikle önemlidir. LSM ağaçlarında okuma daha yavaştır çünkü farklı sıkıştırma aşamalarında olan birkaç farklı veri yapısına ve SS tablosuna bakmanız gerekir. Daha ayrıntılı olarak, böyle görünüyor. LSM ile basit bir veritabanı sorgulaması yaparsak, öncelikle anahtarı MemTable'da arayacağız. Orada değilse, en son SSTable'a bakarız; orada değilse, sondan bir önceki SSTable'a bakarız, vb. İstenen anahtar yoksa, LSM ile bunu en son bileceğiz. LSM ağaçları, örneğin: LevelDB, RocksDB, Cassandra ve HBase'de kullanılır.

Bir veritabanı seçerken birçok farklı şeyi göz önünde bulundurmanız gerektiğini anlamanız için her şeyi o kadar ayrıntılı olarak anlatıyorum: örneğin, daha fazla veri yazmayı mı yoksa okumayı mı bekliyorsunuz? Ve veri modellerindeki farktan henüz bahsetmedim (grafik modelin izin verdiği gibi verileri çaprazlamanız gerekiyor mu? Verilerinizde farklı birimler arasında herhangi bir ilişki var mı - o zaman ilişkisel veritabanları kurtarmaya gelecek mi?), ve 2 tip veri şeması - yazarken (birçok NoSQL'de olduğu gibi) ve okurken (ilişkiselde olduğu gibi).

Dayanıklılık yönüne dönersek, sonuç şu şekilde olacaktır: indeksleme mekanizmalarından bağımsız olarak diske yazan herhangi bir veritabanı, verilerinizin dayanıklılığı için iyi garantiler sağlayabilir, ancak her bir belirli veritabanıyla ilgilenmeniz gerekir. , tam olarak ne sunuyor.

6.5 Bellek içi DB'ler nasıl çalışır?

Bu arada, diske yazan veritabanlarına ek olarak, esas olarak RAM ile çalışan sözde "bellek içi" veritabanları da vardır. Kısacası, bellek içi veritabanları daha yüksek yazma ve okuma hızları uğruna genellikle daha düşük dayanıklılık sunar, ancak bu bazı uygulamalar için uygun olabilir.

Gerçek şu ki, RAM belleği uzun süredir disklerden daha pahalıydı, ancak son zamanlarda hızla ucuzlamaya başladı, bu da yeni bir veritabanı türünün ortaya çıkmasına neden oldu - bu, RAM'den veri okuma ve yazma hızı göz önüne alındığında mantıklı. Ama haklı olarak soracaksınız: Peki ya bu veritabanlarının veri güvenliği? Burada yine uygulamanın detaylarına bakmanız gerekiyor. Genel olarak, bu tür veritabanlarının geliştiricileri aşağıdaki mekanizmaları sunar:

  • Pillerle çalışan RAM kullanabilirsiniz;
  • Değişiklik günlüklerini diske yazmak mümkündür (yukarıda bahsedilen WAL'ler gibi bir şey), ancak verilerin kendisine yazılamaz;
  • Periyodik olarak veritabanı durumunun kopyalarını diske yazabilirsiniz (bu, diğer seçenekleri kullanmadan garanti vermez, yalnızca dayanıklılığı artırır);
  • RAM durumunu diğer makinelere çoğaltabilirsiniz.

Örneğin, esas olarak bir mesaj kuyruğu veya önbellek olarak kullanılan bellek içi Redis veritabanı, ACID'den dayanıklılıktan yoksundur: Redis verileri diske boşalttığı için, başarılı bir şekilde yürütülen bir komutun diskte saklanacağını garanti etmez (eğer kalıcılığın etkinleştirilmiş olması) yalnızca eşzamansız olarak, düzenli aralıklarla.

Ancak bu, tüm uygulamalar için kritik değildir: Her 1-2 saniyede bir temizlenen EtherPad ortak çevrimiçi düzenleyicisinin bir örneğini buldum ve potansiyel olarak kullanıcı birkaç harfi veya bir kelimeyi kaybedebilir ki bu pek de kritik değildi. Aksi takdirde, bellek içi veritabanları, disk dizinleriyle uygulanması zor olan veri modelleri sağlamaları açısından iyi olduğundan, Redis işlemleri gerçekleştirmek için kullanılabilir - öncelik sırası bunu yapmanıza izin verir.