File & Table — Azure Storage #S1B2

Cihat Solak
lTunes Tribe
Published in
7 min readJun 19, 2022

Microsoft Azure Storage #S1B1 bölümüne denk gelmemiş olabilirsiniz. Sizi Google’dan bir rüzgâr buraya yönlendirdiyse, öncelikle #S1B1 bölümünü ziyaret etmenizi öneririm. Çünkü bu içerikte File ve Table servisleri üzerinde duracağız.

File & Table & Queue & Blob — Azure Storage

File Service 📁

Ortak dosya paylaşımını/depolanmasını (Google Drive, OneDrive, Yandex Disk, Dropbox gibi.. Benziyor ama tam da o değil.) sağlamaktadır. Gerçek hayat senaryosundan örnek verelim. Örneğin 20 adet sanal makineye sahip olduğumuzu ve makinelerin paylaşımlı/ortak bir alanda dosya depolamasına/okumasına ihtiyacımız olduğunu düşünelim. Bu senaryoda file servis oluşturup, sanal makinelere 👩🏻‍💻 bağladığımızda (mount) 20 sanal makine de aynı file servis içerisindeki dosyalara erişebilecektir/depolayabilecektir. Genel itibarıyla sanal makinelerin depolaması için merkezî bir konuma ihtiyacı varsa faydalanılabilecek servistir.

Kişisel Bilgisayarıma File Service’i Nasıl Bağlarım?

Azure Portal üzerinden storage hesabımızı görüntüleyip, file service seçeneğine tıklayalım.

File service — Azure Storage Account

🆘 Dosya paylaşımı adları yalnızca küçük harfler, sayılar ve tire (-) içerebilir ve bir harf veya sayı ile başlayıp bitmelidir. Ad, iki ardışık tire içeremez.

File Share — File Service

Oluşturduğumuz file servise tıklayıp detayına gidelim. Buradan alacağımız komut ile kişisel bilgisayarımıza bağlama (mount etme) işlemi gerçekleştireceğiz.

Ben sürüce harfi olarak “L” belirledim, siz istediğinizi belirleyebilirsiniz. 5 numaralı çerçevede yer alan kodu kopyalıyorum ve yönetici olarak powershell arayüzünü açıp, komutu çalıştırıyorum.

Powershell

Bu işlem sonrasında yaptıklarımızın sonucunu görmek adına This PC -> Network locations’ları kontrol edebilir misiniz? Eğer aynı yerdeysek konuya devam ediyorum. Değilsek yukarıdaki işlemleri tekrar etmeni rica ediyorum. Biz devam edelim. Bu işlem sonunda artık ben network locations sekmesinde yer alan vehiclepictures içerisine hangi dosyayı atarsam atayım, cloud ☁️ üzerindeki file storage’a eklenecektir. İşte bu kadar! 😉

Network locations — Azure Storage

Böyle olmadı.. Ben Azure Storage Explorer’da da görmek istiyorum diyenler için buyurun!👌

File Service — Azure Storage Explorer

Table Storage (Not Only SQL)

Genellikle projelerde ilişkisel veri tabanı (RDBMS) olan PostgreSQL, MS SQL, Oracle benzeri birincil/yabancı anahtar ilişkileri olan veri tabanlarına ihtiyaç duyulur. Fakat bu servis, ilişkisel olmayan veri tabanı türevidir.

İhtiyacımıza göre birincil anahtar (primary key), yabancı anahtar (foreign key) ilişkisi olmayan tablolara ihtiyaç duyabiliriz. Haliyle, bu tür senaryoda tercih NoSQL’den yana olacaktır. 💪 Neden? Cevap dinamiklik. Dinamiklikten kasıt varlık (entity) içerisinde bulunan property’lerimizin diğer bir ifadeyle tabloda bulunan sütun sayısının değişebilme ihtimalidir.

Dipnot: İçeriğimiz boyunca hiçbir github gists’ine ihtiyaç duymadım. Bu nedenle öncülük edecek bir github reposuna ihtiyacınız varsa linki bırakıyorum.

DİNAMİKLİK 🏃🏻‍♂️: Örneğin araç satışı yaptığımız ve verileri ilişkisel veri tabanı olan PostreSQL’de depoladığımız bir web sitesine sahip olalım. Haliyle elimizde araca ait bir varlık (entity) sınıfı bulunacaktır. Bu entity sınıfının ismi ‘Vehicle’, özellikleri (properties) ise Brand, Model, SubModel, Color olduğunu varsayalım. Müşteri 3–5 ay sonra sitede aracın model yılını da göstermek istiyoruz dediğinde ne yapacağız? PostgreSQL’e gidip ModelYear adında sütun oluşturup daha öncekiler için değeri NULL/Default Value olarak ayarlıyoruz. (Code First’de olabilir, anlatmak istediklerim için aynı kapıya çıkıyor.) Daha sonra gelecek değerler için model yılı ekleniyor, eğer model yılı yoksa da NULL/Default Value olarak kalıyor. Sonuç olarak, veri tabanında bir sütun oluşturup sütunun tipini belirleyip, ardından boş geçileceği zaman NULL/Default Value kalsın gibi ayarlamalarımızı yapmış olduk. Bakıldığı zaman burada vehicle tablosunu NoSQL (MongoDB, CosmosDB, Table Storage, Redis) veri tabanında tutsaydık, yapmamız gereken tek güncelleme vehicle entity’sine model year adında property eklemekti. Veri tabanı tarafında ekstra yapmamız gereken bir şey bulunmayacaktı. Dinamiklikten kasıt budur. 🏄🏻 Yani bir satıra bir özellik (sütun) eklemeyi kolaylaştırma imkânı sağlıyor.

public int ModelYear { get; set; }

ESNEKLİK 🏌🏼: RDBMS tarafında bir vehicle entity’si düşünelim. Bu vehicle (araç) entity’sinin 20 özelliği varsa her aracın 20 adet özelliğe sahip olacağının kesinliğiyle hareket eder. Fakat NoSQL’de ise bir aracın 10 diğerinin 17 diğerinin ise 33 property’si olabilir. Çünkü NoSQL veritabanın da veriler anahtar-değer (key-value) prensibiyle veri tipinden bağımsız tutulur. RDBMS tarafında işler tam tersidir. Bir sütun oluşturacaksanız veri tipini belirtmeniz zorunludur. NoSQL tarafının bize kazandırdığı Esnekliktir.

PERFORMANS 🚀 : Sahip olunan entity (varlık) sınıfının property’leri dinamik olarak değişkense yani dinamik şekilde satırlarda tutacağınız sütun sayısı değişecekse RDBMS (ilişkisel veri tabanı) kullanmak performanslı olmayacaktır. Not Only SQL (NoSQL) yani sadece SQL kullanma ihtiyaç bulunan yerlerde NoSQL veri tabanı türevlerini de kullan. İkisi birlikte kullanıldığı zaman gerçek gücünün ortaya çıktığı söylenir. Yani tüm yapıyı NoSQL veya SQL şeklinde kurgulamak yerine ihtiyaca binaen seçimler yapmak daha iyi sonuç doğuracaktır.

Eee, NoSQL Veri tabanı Tercih Ederken Nelere Dikkat Edeyim?

Transaction desteği var mı?

Düşünsene projeyi yarılamışsın transaction’a ihtiyacın var ama kullandığın NoSQL veri tabanının transaction desteği olmadığının farkında değilsin. Evlat acısı. 😱 O nedenle en baştan farkında olmak gereklidir. Örneğin Azure Table Storage transaction desteği yoktur fakat MongoDB’nin ya da Azure Table Storage’ın bir üst versiyonu olarak nitelendirebileceğimiz CosmosDB transaction desteği vardır. CosmosDB, Azure Table Storage ile aynı yapıyı kullanan ve Azure Table Storage’dan daha yüksek özelliklere sahip, transaction desteği olan NoSQL veritabanıdır.

Her bir NoSQL veri tabanı türevinde satırlara farklı isimler verilmektedir. SQL Server’daki row, MongoDB’de document, Azure Table Storage veya CosmosDB’de entity olarak isimlendirilmiştir. Yapılan iş aynı, isimlendirmeler farklıdır.

Azure table storage tarafında entity olarak isimlendirilen satırda en fazla 256 sütun, 256 key-value property barındırabiliriz. Ayrıca bir veri kaydettiğimizde her bir tablo için varsayılan (default) olarak 3 adet alan (RowKey, PartitionKey, Timestamp) gelir. Biz tabloya veri kaydetmek istediğimizde bu 3 alanı doldurmamız gerekmektedir.

RowKey, birincil anahtar (primary key) şeklinde nitelendirebiliriz. Bu ilgili tabloda eşsiz bir satır olacağı anlamına gelir. Birincil anahtar ile benzer fakat otomatik artan gibi bir seçeneği bulunmadığı için değerini kendimiz belirlemeliyiz.

PartitionKey, satırları gruplamak ve hızlı arama yapmak için kullanılan özellik (property) dir. Örneğin araçlar ile ilgili tablonuz var ise aracın markasını PartitionKey olarak belirlemek iyi bir seçenek olabilir. İleri zamanlarda Seat markasına ait araçları 🚗 listelemek istediğimizde performans açısından faydalı olacaktır. Çünkü azure storage table’da bir satırı en hızlı bulmanın yolu RowKey ve PartitionKey değerini vermemizdir. PartitionKey’i sabit bir değerde geçebilirsiniz fakat bu ilgili request/response sürenizi olumsuz yönde etkileyecektir. Bana kalırsa RowKey de aracın benzersiz id’sini, PartitionKey de ise aracın markasını tutmak iyi bir alternatif olabilir. Bu kurgu ile aranılan veriye hızlı şekilde ulaşacaksınızdır.

Timestamp, 🕗 zorunlu bir alan değildir, ilgili değeri belirlemezsek table storage satıra eklenilen tarihî baz alır.

Bahsini geçirdiğimiz 3 varsayılan özellik, otomatik olarak indexleme özelliğe sahip olduğundan ötürü ekleyeceğimiz diğer özelliklere nazaran bizlere daha fazla performans sağlayacaktır. Table üzerindeki sorgularımızı elbette diğer eklediğimiz property’ler üzerinden de yapabiliriz fakat best practices 🟢 açısından RowKey ve PartitionKey üzerinden yapmak uygun olacaktır.

Azure storage table’ın diğer bir özelliği sorgulama yaparken LINQ desteklemesidir.

CosmosDB’nin Azure Table Storage’dan Farkı Nedir?

🔸CosmosDB, Azure Table Storage’ın atası olan NoSQL veri tabanıdır.

🔸Her iki veri tabanı da aynı SDK’yı kullandığından ötürü veri tabanları arasında geçiş yapmak için bağlantı dizisi (connection string) değiştirmek yeterli olacaktır.

🔸CosmosDB fiyatı 💵 yüksektir.

🔸CosmosDB içerisindeki tüm property’ler indexlendiğinden dolayı tüm property’de arama yapabilirsiniz. Azure table storage’da RowKey ve PartitionKey indexlenirken diğer property’leri indexleyemezsiniz.

🔸CosmosDB’nin saniyeler ⏱ içerisinde replikasını yapabilirsiniz.

🔸CosmosDB ilgili datayı milisaniyeler içerisinde erişebileceğinizin garantisi verir.

🔸CosmosDB, scale up/down ve özellikle ölçeklenebilirlik konusunda azure table storage’a göre çok daha avantajlıdır.

Genelde veri tabanları hibrit (karma) şeklinde kullanılır. Hibritten kasıt bir projede ilişkisel (RDBMS) ve ilişkisel olmayan NoSQL veritabanının birlikte kullanılmasıdır.

Table Storage’da Veri Güncellerken ETag Enum’ının Önemi Nedir?

Eş zamanlılıktır. 〽️ Hemen örneklendirelim. Birbirinden bağımsız User A ve User B adlarında müşterimiz olsun. Bu iki müşteri yönetim panelinden 1234 birincil anahtar değerine sahip Volkswagen Golf marka aracın bilgilerini güncellemeyi hedeflediklerini düşünelim. İkisi de aracın detay sayfasına tıkladı fakat o sırada User B’nin ufak bir işi çıktı. User A, User B’den habersiz 1234 id’li golf marka aracı güncelledi. Kahvesini ☕️ alıp gelen User B her şeyden habersiz aracın markasını güncelleyecekken işte tam olarak burada birkaç farklı yol tercihine girmemiz gerekiyor. Ya User B’ye “bak arkadaşım bu bilgi daha önce güncellendi, gel sen bu verileri güncelle” diyebilir veya hiç kullanıcıya bilgi vermeden User B’nin yazmış olduğu verileri veritabanına yansıtır, User A’nın verilerini override etmiş oluruz.

Peki, ETag Bu İşin Neresinde? Bana Tam Olarak Ne Sağlıyor?

Yukarıdaki örnekten devam edecek olursam, User A ilgili satırı çektiği zaman User B de ilgili satırı çektiğinde o anda tabloda bulunan timestamp ⏱ değerini alacaklardır. User A güncelleme işlemini tamamladığında tablodaki timestamp değeri güncellenir. Bunun arkasından User B eski veri üzerinde işlem yaptığı zaman (sayfayı yenilemedi, User A’da güncelleme yaptı) haliyle o anda bulunduğu sayfadaki veri bayat veri ve timestamp değeri de eski. Çünkü User A güncelleme yaptığı için tablodaki timestamp değeri güncellenmiş oldu.

Entity framework bu timestamp değerlerinin farklı olduğunu gördüğü an geçmiş olsun hata (StorageException) fırlatacaktır. Bu hata ile birlikte kullanıcıya güncellemekte olduğu verinin bir başkası tarafından güncellendiğini söyleyebiliriz. Hayır ben bu şekilde bir davranış sergilemek istemiyorum diyorsanız etag propert’sine * (yıldız) koyarak verileri override edebiliriz. Bu durumda timestamp değerleri karşılaştırılmayacağı için veriyi en son güncelleyen kullanıcının işlemi veri tabanına yansıyacaktır.

--

--