Azure'da Blob Storage'a giriş SDK(2.5)

0 dakikada yazıldı

16242 defa okundu

Düzenle

Uzun süredir Azure yazılarında sürekli olarak :) uygulamamızın çalıştığı
sanal makinenin diskinin aslında kalıcı veri saklama alanı olarak
kullanılamayacağından bahsediyorum. Nedenini sanırım bugüne kadar
netleştirebilmişizdir :) Peki o zaman en basit haliyle kullanıcıdan
aldığımız bir resim dosyasını nereye saklayacağız? Nereye saklamalıyız
ki role'ümüzün tüm instance'ları bu dosyaya aynı şekilde ulaşabilsin?

Windows Azure Storage Servisleri

Paylaşımlı ve kalıcı bir dosya saklama alanı olarak Windows Azure
Storage servisleri
içerisinden Blob Storage'ı kullanmamız gerekiyor.
Windows Azure Storage servislerinde toplam üç tane farklı servis var;
blog, table ve queue. Biz bu yazımızda sadece Blob Storage konusunu
inceleyeceğiz. İleriki yazılarda tabi ki diğer konulara da bakarız ;)

İlk Storage Account'umuzu yaratırken
İlk Storage Account'umuzu yaratırken

Yeni bir Storage Account yaratırken bir DataCenter veya Affinity Group seçmenin yanı sıra bir de "Replication" modelini seçmemiz gerekiyor. Replication modeli olarak default gelen model "Geo-Redundant" modeli. Şimdilik o seçenek ile ilerleyelim. Sonraki yazılarda Replication modellerinin detaylarına göz atacağız.

Not: Bir Storage Account yaratmak Microsoft'a para ödeyeceğiniz
anlamına gelmez. Storage Accountlar içerisindeki tüm servislerin
ücretlendirilme şekli kullanım üzerindendir. O nedenle yaratıp kenarda
bıraktığınız bir storage account'un sizin için bir maliyeti olmaz.

Storage Account'un endpointleri.
Storage Account'un endpointleri.

Storage Account'unuz yaratıldıktan Dashboard'da yukarıdaki gibi bilgileri bulabilirsiniz. Her Storage Account'ta blob,
table ve queue servisleri bulunur. Her servisin ise kendi endpointleri
vardır. Endpointlerin listesi malum ekran görüntüsünde görülüyor. Zaten
genel kural account adının sonuna servis adı sonrasına da
core.windows.net eklenmesi şeklinde. Yine tekrar etmek istiyorum :)
bunları yaratıp kullanmazsanız herhangi bir maliyeti yok :)

Storage account içerisindeki servislere ulaşırken ihtiyacınız olacak iki
şey var, birincisi account adı veya endpoint adresi, ikincisi ise
"Access Key" yani erişim anahtarı. Erişim anahtarı olarak iki tane
erişim anahtarı veriliyor. Her iki anahtar da aynı işi görüyor. Peki
neden ik tane var?

Access Key'leri yenilemek için.
Access Key'leri yenilemek için.

Diyelim ki keyleri yenilemek istediniz. Bunu hemen "Regenerate" diyerek yapabilirsiniz. Karşınıza gelecek yeni ekradan
iki access key'den hangisini yenilemek istediğiniz sorulacaktır. Durum
öyle ki :) access key'i yenile dediğiniz anda eskisi direk pasif oluyor.
Peki canlı yayında olan uygulamanıza yeni access key'i verene kadar ne
olacak? Uygulama aşağı mı inecek? Tabi ki olmaz. O nedenle key
değiştirme senaryolarında eğer birinci key'i kullandıysanız onu önce bir
ikinci key ile değiştiriyorsunuz :) ikinci key CSCFG ile tamamen tüm
instancelara yayıldıktan sonra panele gelip birinci key'i regenrate
ediyorsunuz. Birinci key ile beraber CSCFG yine tüm instancelara
dağıldıktan sonra artık isterseniz ikinci key'i de regerate
edebilirsiniz. İşte bu senaryo nedeniyle aynı işe yarayan iki access
keyimiz mevcut.

Bloblar!

Blob kelimesinin açılımı "Binary Large Object". Bloblar Azure içerisinde
paylaşımlı dosya saklama yerimiz.

Blob iç yapısı.
Blob iç yapısı.

Blob yapısı en dıştan bir "Account" ile başlıyor. Bunu zaten bir önceki
adımda hesabımızı yaratırken gördük. Her account'un bir adı var ve en
dış nesne olarak doğrudan account'un kendisi varsayabiliriz. Her account
içerisinde birden çok Container olabiliyor. Container'ları şu noktada
birer klasör gibi de düşünebilirsiniz ama bir istisna var :(
container'ları içiçe koymak mümkün değil. Her container içerisinde de
istediğiniz kadar Blob olabiliyor, yani dosya veya binary obje.

Her blobun bir de dışarıya açık HTTP Endpoint'i var. Yani bir container
içerisine koyduğunuz bir bloba eğer uygun izinleri verdiyseniz bu blob /
dosya doğrudan dışarıdan bir GET talebi ile alınabiliyor. GET talebinin
gönderileceği yani dosyanın web adresi için şu şekilde oluşuyor;

http://{storage account adı}.blob.core.windows.net/{container
adı}
/{blob adı}

Her bir storage account şu an için en fazla 100TB veri saklayabiliyor.
Bu sınıra storage account içerisindeki diğer servislerin (table, queue)
sakladığı verilerin de dahil olacağını unutmamak gerek.

Page, Block Blob

Bloblar kendi içerlerinde ikiye ayrılıyorlar :) Page ve Block Blob'lar
şeklinde... Genelde dosyalar eğer ki deli random read/write olmayacak
block blob'larda tutulurlar. Bir block blob tek başına en fazla 200GB
veri alabilir. Bir Page Blob ise tek başına 1TB veri saklayabilir.

Page blob ile block blob arasındaki farklılığın detaylarına biraz girmek
gerekirse; Page Bloblar 512 byte'lık seriler şeklinde veriyi saklarken
Block Blob'larda bloklar 4MB'a kadar çıkabilir. Block bloblar kendi
içlerinde asenkron upload, birden çok kanal açımı, kaba bir transaction
yapısı sunarken Page Blob'larda herşey anında commit olur. Genel olarak
baktığımızda random read/write gerektiğinde, kabaca bir filesystem
stream access gerektiğinde Page Blob'lar daha mantıklı olacaktır fakat
chunk file / toplu dosya işlemlerinin bulunduğu senaryolarda block
bloblar çok daha pratik olur. Örneğin son kullanıcıdan aldığınız bir
resmi veya videoyu block blob'a kaydetmelisiniz :)

İlk blob kullanımımız!

Eh hadi bakalım :) İlk blob kullanımımıza doğru yola çıkalım. Temiz bir
Azure projesini yine tertemiz bir web role ile aldıktan sonra WebRole'ün
ayarlarına giderek Storage Account erişim bilgilerimizi tutacak yeni bir
ayar bilgisini CSDEF ve CSCFG'ye koyalım.

Hesap ayarlarımızı Azure projesine eklerken.
Hesap ayarlarımızı Azure projesine eklerken.

Yukarıdaki ekran görüntüsünden de yakalayabileceğiniz üzere "Add
Settings" diyerek istediğimiz isimde bir ayar tanımlayıp bunun da
"Connection String" olacağını belirttikten sonra sağda belirlen mini
düğmeye tıklayıp Storage Account bilgilerimizi girebileceğimiz ekrana
geliyoruz. Burada istersenis Account Name ile Key'i girerek doğrudan
Azure'daki Storage Account'tan blob servisini kullanın isterseniz "Microsoft Azure storage emulator" diyerek SDK ile beraber
bilgisayarınıza yüklenen emülatörü kullanın. Programatik açıdan emülatör
ile live servis arasında bir fark yok ;) o nedenle son testler haricinde
local emülatörü kullanarak devam edebilirsiniz.

[C#]

CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
CloudBlobClient blobClient = account.CreateCloudBlobClient();

Ayarladığımız blobConnection connection stringini almak yerine ben şimdilik doğrudan DevelopmentStorageAccount kullanıyorum. Bunun üzerinden hemen
kendimize bir CloudStorageAccount nesnesi yaratıyoruz. Unutmayın ki
Storage Account ile ilgili tüm servisler normalde REST API'leri ile
açılmış durumdalar. Bu REST API'leri C#'dan böyle rahat
kullanabilmemizi sağlayan wrapper'lar Azure SDK sayesinde projemizde
zaten bulunuyor. ASP.NET projemize referanslı gelen
Microsoft.WindowsAzure.Storage.dll wrapper'ımızın ta kendisi. Eğer sizin
projenizde referanslı değilse rahatlıkla Azure SDK'in kurulu olduğu
klasörden bularak elle de referans alabilirsiniz.

Account nesnemizi yarattıken sonra bu nesne üzerinden de bir BlobClient
yaratıyoruz. Böylece artık Storage Account üzerindeki blob servisi ile
ilgili işlem yapacağımızı da belirlemiş olduk.

[C#]

CloudBlobContainer container = blobClient.GetContainerReference("dosyalar");
container.CreateIfNotExists();

Biliyorsunuz bloblardaki herhangi bir blobu saklayabilmek için en
azından bir container sahibi olmamız gerekiyor. O nedenle yukarıdaki
kodda da hemen bir container yaratıyoruz. Elimizdeki blobclient
üzerinden dosyalar adında bir container'ın referansını alıyoruz. Aslında
böyle bir container şu anda yok :) ama zaten GetContainerReference
dediğinizde bir REST API call gerçekleşmiyor. Tabi tüm bu kodları yazarken
aslında sürekli olarak arka planda bir REST API Call'un yaratılmasını
sağladığımızı ve o mantığa uygun kod yazdığımızı akılda bulundurmak
gerek. Farklı bir benzetme ile :) belki de bunu yazdığımız anda SQL'e
gönderilmeyen LINQ2SQL sorgularına da benzetebiliriz :) Çok farklı bir
benzetme oldu farkındayım :)

Not: Container isimleri kesinlikle küçük harflerden oluşmalı. 3-63
karakter uzunluğunda olmalı.

Konumuza dönersek :) referansını aldığımız container'ın yaratılması
için container nesnesi üzerinden CreateIfNotExists diyoruz ve işlem
bitiyor. Artık "dosyalar" adında bir container nesnemiz var ve içine
dosya atabiliriz :)

[C#]

var blob = container.GetBlockBlobReference(FileUploadControl.FileName);
blob.UploadFromStream(FileUploadControl.FileContent);

Herşey ne kadar basit ilerliyor değil mi? :) Elimizdeki container
üzerinden bu sefer de bir BlockBlobReference alıyoruz. Blob reference alırken
blob ismi olarak FileUpload kontrolünden gelen dosyanın ismini
veriyoruz. Tabi yine container'da olduğu gibi şu anda böyle bir blob
yok, sadece referansı var. Bir sonraki adımda o referans üzerinden
UploadFromStream diyerek FileUpload'daki içeriği verdiğimiz anda Upload
işlemi gerçekleşiyor ve blob fiziksel varlığına kavuşuyor :)

Eh hadi.. F5'e basın... ;)

Peki bu upload ettiğimiz resme nasıl ulaşacağız? Bunun için aşağıdaki gibi blob'dan URL istememiz gerekecek.

[C#]

var blob = container.GetBlockBlobReference(FileUploadControl.FileName);
blob.UploadFromStream(FileUploadControl.FileContent);
Response.Write(blob.Uri.ToString());

URL'i aldıktan sonra doğrudan tarayıcıya yazıp dosyayı görmek isterseniz dosyaya ulaşamadığınızı göreceksiniz. Ama bu noktadan önce linkin formatına dikkat edelim :) Daha önce konuştuğumuz storage account ve blob link yaratma şeklinde pek benzemiyor gibi. Normalde container adı ve sonra da blob adı gelmesi gerekirdi. Tabi onun için account adının da domain başında subdomain tadında durması gerekiyordu. Eğer bu projeyi Azure'daki canlı bir Storage Account'a yönlendirirseniz herşey aynen daha önce konuştuğumuz gibi olacaktır. Ama local emülatörde çalışıyorsanız maalesef bu linklerin yapısı daha farklı olacak. Lokal emülatörde sadece tek bir storage account olabiliyor ve table, queue, blob gibi servisler farklı IP'ler yerine farklı portlardan yayınlanıyor. Durum böyle olunca default account adı olan "devstoreaccount1" i de URL içerisinde görüyoruz. Özetle, bu emülatöre özel geçici bir durum :)

Dosyamıza ulaşamıyoruz.
Dosyamıza ulaşamıyoruz.

Dosyaya ulaşamama problemimize geri dönersek. Problemin nedeni Container'ın izinleri ile alakalı. Varsayılan ayarlarla bir Container yaratıldığında sadece elinde key olan kişiler ulaşabiliyor. Yani biz zaten ConnectionString ile gittiğimiz için bizim için bir problem yok. Ama dışarıdan gelen bir kullanıcı URL ile doğrudan erişebilsin istiyorsak söz konusu Container'a ek izinler vermemiz şart.

[C#]

CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
CloudBlobClient blobClient = account.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("dosyalar");
container.CreateIfNotExists();

BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(containerPermissions);

var blob = container.GetBlockBlobReference(FileUploadControl.FileName);
blob.UploadFromStream(FileUploadControl.FileContent);
Response.Write(blob.Uri.ToString());

Yukarıdaki koddaki tek farklılık container'a tüm bloblar için public access yani genele erişim hakkı vermemiz. Kodu tekrar çalıştırırsanız artık bu hak verilmiş ve container içerisinde her dosyaya kendi linki ile erişilebiliyor olacaktır. Toplamda Blob'larda üç çeşit ana erişim hakkı var.

[C#]

CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
CloudBlobClient blobClient = account.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("dosyalar");

foreach (var item in container.ListBlobs())
{
    ((ICloudBlob)item).Delete();
}

Hızlıca konumuza devam edecek olursak :) Örneğin bir Container içerisinde blobların listesine nasıl ulaşırım derseniz sanırım yukarıdaki kod yardımcı olabilir. Container üzerinden ListBlobs demeniz yeterli. Sonra tek tek gibip her blob'tan Uri'sini alabilir veya doğrudan "Delete" diyerek silebilirsiniz. Blob'lardaki dosyalarınızı geri almak isterseniz DownloadToStream size yardımcı olabilir.

[C#]

foreach (var blobItem in container.ListBlobs())
{
    using (var fileStream = System.IO.File.OpenWrite(Path.GetTempFileName()))
    {
        ((CloudBlob)blobItem).DownloadToStream(fileStream);
    } 
} 

Sonuç olarak

Birincisi şunu söyliyim :) Blob konusu bitmedi :) ama sanırım akıllardaki çoğu soru işaretini cevaplamıştır. Azure ortamında 180 instance çalışan web role'ünüzün kalıcı dosya saklama yeri kesinlikle Blob'lar olacaktır. İşin güzel tarafı özellikle dışarıya açılacak dosyalarda blobların bunu doğrudan yapıyor olması. Böylece dosya downloadları, resimler gibi birçok şeyin trafiği aslında sunucunuz üzerinden geçmiyor bile. Blobların performansından, arka planda doğru şekilde dağılmasında Microsoft sorumlu çünkü orada zaten hem bandwidth :) hem REST API transaction başına para alıyorlar. Tabi storage alanı için de para alınıyor :)

Kolay gelsin.