BLOGas.lt
Sukurk savo BLOGą Kitas atsitiktinis BLOGas

Meet Windows Azure LIVE - jau šiandien

Parašė Sergejus | 2012-06-07 10:42

Jau šiandien 23 val. Lietuvos laiku meetwindowsazure.com svetainėje galėsime stebėti Scott Guthrie pristatymą, kuriame jis aptars Windows Azure naujoves (kurių bus labai-labai-labai daug). Būtinai rekomenduoju žiūrėti transliaciją!

P.S.

Tam tikros užuomenos apie naują funkcionalumą čia.

Rodyk draugams

Savaitės video – Moving Application to The Cloud

Parašė Sergejus | 2011-09-28 20:57

Šios savaitės video – aš pasakoju apie aplikacijų migravimą į debesis.

Rodyk draugams

Ketverti metai kaip MVP

Parašė Sergejus | 2011-07-02 16:52

Vakar gavau man labai svarbų laišką:

Dear Sergejus Barinovas,
Congratulations! We are pleased to present you with the 2011 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Windows Azure technical communities during the past year.

Rodyk draugams

Windows Azure SDK 1.3 ir naujasis Windows Azure Platform portalas jau prieinami

Parašė Sergejus | 2010-11-30 20:56

Lygiai prieš savaitę rašiau apie Windows Azure naujoves, o šiandien dalis minėtų galimybių tapo prieinama viešai, o dalis – beta testuotojams.

Naudingos nuorodos:

Windows Azure SDK and Windows Azure Tools for Microsoft Visual Studio (November 2010)
Windows Azure Platform Training Kit - November Update
Windows Azure komandos straipsnis apie SDK1.3 naujoves ir naują portalą

Tiems kam smalsu, bet neturi prieigos prie Windows Azure, žemiau pateikiu naujojo Windows Azure Platform portalo paveiksliuką

azure-portal1

Rodyk draugams

Pingy - #5 Windows Azure Queue ir PingTaskRepository

Parašė Sergejus | 2010-10-19 21:22

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiai Windows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

Praeitoje dalyje mes užbaigėme PingItemRepository, o šitoje – aptarsime Windows Azure Queue bei jos panaudojimą aprašant PingTaskRepository.

Windows Azure Queue apžvalga

Eilės – labai galingas mechanizmas. Jų pagalba galima ne tik padalinti apkrovą tarp nurodytų serverių, bet ir logiškai atskirti servisus-gamintojus nuo apdorojimo servisų. Taip, N servisų-gamintojų gali siųsti pranešimus (uždavinius) į eilę, o M servisų imti tuos uždavinius paeiliui ir apdoroti. Windows Azure turi nuosavą eilių realizaciją – Windows Azure Queue. Iš plečiamumo pusės, mes galime keisti servisų-gamintojų ir apdorojimo servisų skaičių pagal poreikį nepriklausomai vienas nuo kito. Jeigu ateis momentas, kad lėčiausia vieta taps Windows Azure Queue – reikės naudoti kelias eiles skirtingoms užduotims atlikti (taip vadinamas eilių padalijimas, angl. Queue partitioning).

Windows Azure Queue pranešimų apdorojimui naudoja taip vadinamą dviejų fazių patvirtinimą:

  • Pasiima pranešimą (užduotį) iš eilės ir pažymį jį kaip nematomą
  • Jeigu pranešimo apdorojimo metu kils klaida, po tam tikro laiko pranešimas vėl taps matomu ir bus grąžintas į eilę
  • Jeigu pranešimas buvo sėkmingai apdorotas – jis turi būti išreikštinai pašalintas iš eilės

PingTask ir susijusios klasės

Prisiminkime pirmoje dalyje aprašytą architektūrą:

alt

Kaip matyti, kreipimasis į serverius yra inicijuojamas Ping Scheduler serviso, patalpinant atitinkamą pranešimą (užduotį) į eilę. Tada kiekvienas iš Pinger servisų iš eilės pasiima po užduotį ir pradeda jas vykdyti. Užduoties esybę mes modeliuosime naudojant klasę PingTask:

public class PingTask
{
    public string Id { get; set; }
    public string PopReceipt { get; set; }
    public int DequeueCount { get; set; }

    public PingItem PingItem { get; set; }
}

Čia PingItem – prieš tai aprašyta esybė, kuri gaunama ir Azure Table saugyklos. Kitos savybės yra nustatomos Windows Azure Queue pusėje ir reikalauja detalesnio aprašymo:

  • Id – unikalus pranešimo identifikatorius (automatiškai generuojamas)
  • PopReceipt – gavėjas, kuris išėmė pranešimą iš eilės
  • DequeueCount – nusako kiek kartų pranešimas buvo išimtas iš eilės (dažnai reiškia, kiek kartų jau buvo bandoma nesėkmingai apdoroti pranešimą, po ko nulūždavo apdorojimo servisas ir pranešimas buvo grąžinamas atgal į eilę)

Kadangi Windows Azure Queue turi nuosavą pranešimo klasę CloudQueueMessage, mums reikalingas labai paprastas esybių konverteris:

public static class PingTaskConverter
{
    public static PingTask ToPingTask(this CloudQueueMessage message)
    {
        return new PingTask
        {
            Id = message.Id,
            PopReceipt = message.PopReceipt,
            DequeueCount = message.DequeueCount,
            PingItem = message.AsString.FromJson<PingItem>()
        };
    }
}

CloudQueueMessage pranešimo turinys pasiekiamas dviem būdais – savybės AsByte arba AsString pagalba, todėl papildysime mūsų Helper klasę iš 3 dalies dviem metodais: ToJson ir FromJson:

internal static class Helper
{
    public static string SanitizeUrl(this string s)
    {
        var str = s.ToLower();
        str = Regex.Replace(str, @"(http|https)://", String.Empty);
        str = Regex.Replace(str, @"[^a-z0-9_.]", "-");

        return str;
    }

    public static string ToJson<T>(this T obj)
    {
        string json;

        var serializer = new DataContractJsonSerializer(typeof(T));
        using (var stream = new MemoryStream())
        {
            serializer.WriteObject(stream, obj);
            json = Encoding.Default.GetString(stream.ToArray());
        }

        return json;
    }

    public static T FromJson<T>(this string json)
    {
        T obj;

        var serializer = new DataContractJsonSerializer(typeof(T));
        using (var stream = new MemoryStream(Encoding.Default.GetBytes(json)))
        {
            obj = (T)serializer.ReadObject(stream);
        }

        return obj;
    }
}

PingTask repozitorija

Darbui su eile, aprašysime labai paprastą repozitorijos interfeisą IPingTaskRepository:

public interface IPingTaskRepository
{
    PingTask GetTask();
    void AddItem(PingItem item);
    void DeleteTask(PingTask task);
    void ClearTasks();
}

Šio interfeiso realizacija pateikiama žemiau:

public class PingTaskRepository : IPingTaskRepository
{
    private readonly CloudQueue queue;
    private readonly string queueName = typeof(PingTask).Name.ToLowerInvariant();
    private readonly TimeSpan visibilityTimeout = TimeSpan.FromMinutes(3);

    public PingTaskRepository(CloudStorageAccount account)
    {
        var client = account.CreateCloudQueueClient();
        queue = client.GetQueueReference(queueName);
        queue.CreateIfNotExist();
    }

    public void AddItem(PingItem item)
    {
        var message = new CloudQueueMessage(item.ToJson());
        queue.AddMessage(message);
    }

    public PingTask GetTask()
    {
        PingTask task = null;

        var message = queue.GetMessage(visibilityTimeout);
        if (message != null)
        {
            task = message.ToPingTask();
        }

        return task;
    }

    public void DeleteTask(PingTask task)
    {
        queue.DeleteMessage(task.Id, task.PopReceipt);
    }

    public void ClearTasks()
    {
        queue.Clear();
    }
}

Kodas yra pakankamai paprastas, bet verta paminėti du dalykus:

  • nematomumo periodas nustatomas trims minutėms po kurio jeigu pranešimas nėra ištrintas, jis bus grąžintas atgal į eilę
  • eilės pavadinimas privalo būti iš mažųjų raidžių, todėl išreikštinai darome ToLowerInvariant

Kitoje dalyje…

Pamatę PingTaskRepository realizaciją, gali kilti klausimas dėl jos panaudojimo (tiksliau kaip teisingai apdoroti skirtingas išskirtines situacijas). Kitoje dalyje pabandysiu aprašyti visas įmanomas problemas, kurios gali kilti apdorojant Windows Azure Queue pranešimus bei pateiksiu teisingo apdorojimo šabloną.

Rodyk draugams

Aš jau nebe C# MVP…

Parašė Sergejus | 2010-10-08 18:30

… o Windows Azure MVP. Nuo spalio 1 dienos, atsiradus naujai MVP sričiai – Windows Azure, mano kompetencijos sritis irgi buvo pakeista. Man yra didelė garbė būti tarp pirmų šios srities nominantų.

Rodyk draugams

Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod

Parašė Sergejus | 2010-10-04 19:23

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiaiWindows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

Praeitoje dalyje mes apibrėžėme pagrindinę PingItem esybę bei su ja susijusią repozitoriją. Šiandien aš parodysiu kaip viena, reliacinėse duomenų bazėse triviali, užklausa gali NoSQL sprendime priversti dubliuoti duomenis.

Metodas GetItemsByPeriod

Priminsiu, praeitame straipsnyje mes turėjome tokį PingItemRepository interfeisą:

public interface IPingItemRepository
{
    IEnumerable<PingItem> GetClientItems(string client);
    bool Exists(PingItem item);
    void AddItem(PingItem item);
    void RemoveItem(PingItem item);
    void RemoveClientItems(string client);
}

Prisiminkime, kad mums reikia ne tik saugoti informaciją, bet ir kreiptis į nurodytus URL. Pas mus tas mechanizmas bus realizuotas pakankamai paprastai: kiekvienai PingPeriod išvardijimo reikšmei bus sukurta po giją, kuri kas nurodytą laiką užklaus į kokius URL reikia kreiptis ir patalpins atitinkamas užduotis į eilę. Už tai atsakys servisas Ping Scheduler. Specialiai jam mums reikia atnaujinti IPingItemRepository metodu GetItemsByPeriod:

public interface IPingItemRepository
{
    IEnumerable<PingItem> GetItemsByPeriod(PingPeriod period);
    IEnumerable<PingItem> GetClientItems(string client);
    bool Exists(PingItem item);
    void AddItem(PingItem item);
    void RemoveItem(PingItem item);
    void RemoveClientItems(string client);
}

NoSQL ypatumai

Iš pirmo žvilgsnio, metodo realizacija gali pasirodyti triviali ir atrodyti taip:

public IEnumerable<PingItem> GetItemsByPeriod(PingPeriod period)
{
    return CreateContext().CreateQuery<PingEntity>(pingEntityTable)
                          .Where(e => e.Period == (int)period)
                          .AsTableServiceQuery()
                          .Execute()
                          .Select(e => e.ToPingItem());
}

Pagrindinė šios realizacijos problema – ypatingai lėta greitaveika ir ribotas plečiamumas. Prisiminkime, duomenys Windows Azure Table saugykloje gali būti saugomi skirtinguose fiziniuose įrenginiuose. Tai reiškia, kad išreikštinai nenurodant PartitionKey bus ieškoma visose saugyklose! Be abejo tai yra labai neoptimalu, todėl reikia optimizuoti užklausą – saugoti PingItem esybes sugrupuotas pagal esamus periodus. Vienintelis būdas pasiekti tai su Windows Azure Table –  dubliuoti duomenis apibrėžiant naują lentelę ir jai skirtą modelį PeriodicPingEntity:

public class PeriodicPingEntity : TableServiceEntity
{
    public string Client { get; set; }
    public string Url { get; set; }
}

Šiame modelyje PingPeriod yra naudojamas kaip PartitionKey. Papildykime mūsų pagalbinę esybių konvertavimui skirtą klasę PingItemConverter:

public static class PingItemConverter
{
    public static PingItem ToPingItem(this PingEntity item)
    {
        return new PingItem
        {
            Client = item.PartitionKey,
            Url = item.Url,
            Period = (PingPeriod)item.Period,
        };
    }

    public static PingEntity ToPingEntity(this PingItem item)
    {
        return new PingEntity
        {
            PartitionKey = item.Client,
            RowKey = String.Format("{0}_{1}", item.Client, item.Url.SanitizeUrl()),
            Url = item.Url,
            Period = (int)item.Period,
        };
    }

    public static PingItem ToPingItem(this PeriodicPingEntity item)
    {
        return new PingItem
        {
            Client = item.Client,
            Url = item.Url,
            Period = (PingPeriod)Int32.Parse(item.PartitionKey),
        };
    }

    public static PeriodicPingEntity ToPeriodicPingEntity(this PingItem item)
    {
        return new PeriodicPingEntity
        {
            PartitionKey = ((int)item.Period).ToString(),
            RowKey = String.Format("{0}_{1}", item.Client, item.Url.SanitizeUrl()),
            Client = item.Client,
            Url = item.Url,
        };
    }
}

PingItemRepository atnaujinimas

Kadangi PeriodicPingEntity modeliai iš esmės tiesiogiai susiję su PingEntity, mums reikės ne tik įgyvendinti GetItemsByPeriod metodą, bet ir papildyti kitus metodus operacijomis su PeriodicPingEntity. Pilna (ir galutinė) PingItemRepository realizacija atrodo taip:

public class PingItemRepository : IPingItemRepository
{
    private readonly CloudStorageAccount account;
    private readonly string pingEntityTable = typeof(PingEntity).Name;
    private readonly string periodicPingEntityTable = typeof(PeriodicPingEntity).Name;

    public PingItemRepository(CloudStorageAccount account)
    {
        this.account = account;

        var client = account.CreateCloudTableClient();
        client.CreateTableIfNotExist(pingEntityTable);
        client.CreateTableIfNotExist(periodicPingEntityTable);
    }

    public IEnumerable<PingItem> GetItemsByPeriod(PingPeriod period)
    {
        return CreateContext().CreateQuery<PeriodicPingEntity>(periodicPingEntityTable)
                              .Where(e => e.PartitionKey == ((int)period).ToString())
                              .AsTableServiceQuery()
                              .Execute()
                              .Select(e => e.ToPingItem());
    }

    public IEnumerable<PingItem> GetClientItems(string client)
    {
        return CreateContext().CreateQuery<PingEntity>(pingEntityTable)
                              .Where(e => e.PartitionKey == client)
                              .AsTableServiceQuery()
                              .Execute()
                              .Select(e => e.ToPingItem());
    }

    public bool Exists(PingItem item)
    {
        var entity = item.ToPingEntity();
        return CreateContext().CreateQuery<PingEntity>(pingEntityTable)
                              .Where(e => e.PartitionKey == entity.PartitionKey)
                              .Where(e => e.RowKey == entity.RowKey)
                              .FirstOrDefault() != null;
    }

    public void AddItem(PingItem item)
    {
        var context = CreateContext();

        var pingEntity = item.ToPingEntity();
        context.AddObject(pingEntityTable, pingEntity);
        context.SaveChanges();

        var periodicPingEntity = item.ToPeriodicPingEntity();
        context.AddObject(periodicPingEntityTable, periodicPingEntity);
        context.SaveChanges();
    }

    public void RemoveItem(PingItem item)
    {
        var context = CreateContext();

        var pingEntity = item.ToPingEntity();
        context.AttachTo(pingEntityTable, pingEntity, "*");
        context.DeleteObject(pingEntity);
        context.SaveChanges();

        var periodicPingEntity = item.ToPeriodicPingEntity();
        context.AttachTo(periodicPingEntityTable, periodicPingEntity, "*");
        context.DeleteObject(periodicPingEntity);
        context.SaveChanges();
    }

    public void RemoveClientItems(string client)
    {
        var context = CreateContext();

        var pingEntities = context.CreateQuery<PingEntity>(pingEntityTable)
                                  .Where(e => e.PartitionKey == client)
                                  .AsTableServiceQuery()
                                  .Execute()
                                  .ToList();

        foreach (var entity in pingEntities)
        {
            context.DeleteObject(entity);
        }
        context.SaveChanges();

        foreach (var pingEntity in pingEntities)
        {
            var periodicPingEntity = pingEntity.ToPingItem().ToPeriodicPingEntity();
            context.AttachTo(periodicPingEntityTable, periodicPingEntity, "*");
            context.DeleteObject(periodicPingEntity);
        }
        context.SaveChanges();
    }

    protected TableServiceContext CreateContext()
    {
        return new TableServiceContext(account.TableEndpoint.ToString(), account.Credentials);
    }
}

Kitoje dalyje…

Kaip matote, programuojant debesims ir mąstant apie plečiamumą, kartais iš pirmo žvilgsnio paprastas uždavinys gali pavirsti visai netrivialiu. Kitoje dalyje mes pereisime prie kreipimosi į URL užduočių formavimo, o tiksliau prie PingTaskRepository klasės ir Windows Azure Queue panaudojimo.

Rodyk draugams

Pingy - #3 PingItem ir PingItemRepository

Parašė Sergejus | 2010-09-18 17:25

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiaiWindows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

Šioje dalyje mes aprašysime esybę PingItem bei jos saugojimui skirtus Azure Table Storage objektus. Papildomai, įgyvendinsime pirmai iteracijai reikalingą PingItemRepository funkcionalumą.

PingItem ir susijusios klasės

Pati esybė atrodo labai paprastai:

public class PingItem
{
    public string Client { get; set; }
    public string Url { get; set; }
    public PingPeriod Period { get; set; }
}

Kreipimosi į serverį periodas nurodomas išvardijimo PingPeriod pagalba:

public enum PingPeriod
{
    QuarterHour = 15,
    HalfHour = 30,
    OneHour = 60,
    TwoHours = 120,
    SixHours = 360,
    TwelveHours = 720
}

Kaip matyti, reikšmės yra nurodomos minutėmis (tai bus svarbu vėliau). PingItem yra modelio POCO klasė, todėl mums reikalinga specialiai Windows Azure Table skirta klasė. Pavadinkime šią klasę PingEntity:

public class PingEntity : TableServiceEntity
{
    public string Url { get; set; }
    public int Period { get; set; }
}

Kodėl PingEntity neturi laukelio Client? Atsimenate PartitionKey? Mūsų atveju kaip PartitionKey ir bus naudojamas konkretus klientas. Tai leis visą su klientu susijusią informaciją saugoti kartu vienoje fizinėje saugykloje. Apibrėžkime pagalbine klasę PingItemConverter, kuri leis konvertuoti objektus iš ir į PingItem klasę:

public static class PingItemConverter
{
    public static PingItem ToPingItem(this PingEntity item)
    {
        return new PingItem
        {
            Client = item.PartitionKey,
            Url = item.Url,
            Period = (PingPeriod)item.Period,
        };
    }

    public static PingEntity ToPingEntity(this PingItem item)
    {
        return new PingEntity
        {
            PartitionKey = item.Client,
            RowKey = String.Format("{0}_{1}", item.Client, item.Url.SanitizeUrl()),
            Url = item.Url,
            Period = (int)item.Period,
        };
    }
}

Atkreipkite dėmesį į metodą SanitizeUrl. Kadangi tiek PartitionKey, tiek RowKey turi ribojimus dėl leistinų simbolių, šis metodas užtikrina korektišką URL konvertavimą:

internal static class Helper
{
    public static string SanitizeUrl(this string s)
    {
        var str = s.ToLower();
        str = Regex.Replace(str, @"(http|https)://", String.Empty);
        str = Regex.Replace(str, @"[^a-z0-9_.]", "-");

        return str;
    }
}

PingItem repozitorija

Pats laikas pereiti prie klasės PingItemRepository, kuri išsaugos mūsų PingItem objektą Windows Azure Table saugykloje. Mums reikalingas interfeisas atrodo taip:

public interface IPingItemRepository
{
    IEnumerable<PingItem> GetClientItems(string client);
    bool Exists(PingItem item);
    void AddItem(PingItem item);
    void RemoveItem(PingItem item);
    void RemoveClientItems(string client);
}

Realizacija yra pateikiama žemiau, bet prieš tai norėtųsi pabrėžti, kad su Windows Azure Table duomenų kontekstą geriausiai kurti su kiekviena užklausa, o nesaugoti lokaliai.

public class PingItemRepository : IPingItemRepository
{
    private readonly CloudStorageAccount account;
    private readonly string pingEntityTable = typeof(PingEntity).Name;

    public PingItemRepository(CloudStorageAccount account)
    {
        this.account = account;

        var client = account.CreateCloudTableClient();
        client.CreateTableIfNotExist(pingEntityTable);
    }

    public IEnumerable<PingItem> GetClientItems(string client)
    {
        return CreateContext().CreateQuery<PingEntity>(pingEntityTable)
                              .Where(e => e.PartitionKey == client)
                              .AsTableServiceQuery()
                              .Execute()
                              .Select(e => e.ToPingItem());
    }

    public bool Exists(PingItem item)
    {
        var entity = item.ToPingEntity();
        return CreateContext().CreateQuery<PingEntity>(pingEntityTable)
                              .Where(e => e.PartitionKey == entity.PartitionKey)
                              .Where(e => e.RowKey == entity.RowKey)
                              .FirstOrDefault() != null;
    }

    public void AddItem(PingItem item)
    {
        var context = CreateContext();

        var pingEntity = item.ToPingEntity();
        context.AddObject(pingEntityTable, pingEntity);
        context.SaveChanges();
    }

    public void RemoveItem(PingItem item)
    {
        var context = CreateContext();

        var pingEntity = item.ToPingEntity();
        context.AttachTo(pingEntityTable, pingEntity, "*");
        context.DeleteObject(pingEntity);
        context.SaveChanges();
    }

    public void RemoveClientItems(string client)
    {
        var context = CreateContext();

        var pingEntities = context.CreateQuery<PingEntity>(pingEntityTable)
                                  .Where(e => e.PartitionKey == client)
                                  .AsTableServiceQuery()
                                  .Execute()
                                  .ToList();

        foreach (var entity in pingEntities)
        {
            context.DeleteObject(entity);
        }
        context.SaveChanges();
    }

    protected TableServiceContext CreateContext()
    {
        return new TableServiceContext(account.TableEndpoint.ToString(), account.Credentials);
    }
}

Jeigu atidžiai išnagrinėjote PingItemRepository kodą, tai tikriausiai pastebėjote metodą AsTableServiceQuery(). Jo dėka paprasta WCF Data Services užklausa yra konvertuojama į CloudTableQuery užklausą, kuri yra specialiai pritaikyta darbui su Windows Azure Tables (automatiškai nuskaito visus įrašus, o ne po 1000 kaip yra pagal nutylėjimą, įvykus ryšio klaidai, pakartoja operaciją ir t.t.). Taip pat jums gali kilti klausimas, kodėl metode Exists() aš panaudojau FirstOrDefault() vietoje, pavyzdžiui, Any(). Atsakymas paprastas – Any() nėra palaikomas su Windows Azure Tables.

Kitoje dalyje…

Taigi šioje dalyje mes apibrėžėme mūsų PingItem modelį bei susijusią Windows Azure Tables klasę ir įgyvendinome repozitoriją. Kitoje dalyje mes susidursime su pirmais NoSQL sunkumais: norint kitaip surūšiuoti lentelę, mums teks kurti visiškai naują lentelę su tais pačiais duomenimis.

Rodyk draugams

Mano pristatymas iš Azure Lenkijos klausytojams

Parašė Sergejus | 2010-09-14 19:15

Populiariausio Lenkijoje .NET programuotojų portalo CodeGuru.pl prašymu, šį ketvirtadienį (rugsėjo 16 dieną) 20:30 Lietuvos laiku darysiu pristatymą iš Windows Azure platformos. Pristatymas vyks Live Meeting pagalba, todėl dalyvauti galite ir jus! Daugiau informacijos bei prisijungimas prie Live Meeting – čia.

Rodyk draugams

Pingy - #2 Windows Azure Table ir NoSQL mąstymas

Parašė Sergejus | 2010-09-07 21:33

Primenu, Pingy – tai mano bandymas sukurti paslaugą, kuri kas tam tikrą laiką kreiptųsi į vartotojo nurodytą URL, taip neduodant IIS užmigti. Tuo pačiu metu bus renkama statistika apie serverio būseną, atsakos laikas ir pan. Pingy yra kuriamas specialiai Windows Azure mokymosi tikslais.

Turinys

Pingy - #1 Architektūra
Pingy - #2 Windows Azure Table ir NoSQL mąstymas
Pingy - #3 PingItem ir PingItemRepository
Pingy - #4 PingItem repozitorijos atnaujinimas metodu GetItemsByPeriod
Pingy - #5 Windows Azure Queue ir PingTaskRepository
Pingy - #6 Windows Azure Queue korektiškas žinučių apdorojimas
Pingy - #7 Pinger serviso kūrimas
Pingy - #8 PingReportItem ir PingReportRepository

Dėl informacijos gausos, nusprendžiau šiai temai skirti atskirą straipsnį. Prieš tęsiant, labai rekomenduoju perskaityti mano įvadą į Windows Azure Table.

Windows Azure Table trumpai

Trumpai priminsiu, Windows Azure Table yra paskirstyta (angl. distributed) NoSQL (neturi fiksuotos lentelių struktūros bei ryšių) tipo duomenų bazė. Tai reiškia, kad dalis jūsų duomenų bus saugoma vienoje saugykloje, o kita dalis – kitoje. Akivaizdu, kad duomenų gavimas iš skirtingų fizinių saugyklų reikalauja ne tik duomenų ištraukimo, bet ir perdavimo tinklu (kas nėra labai greita operacija). Dėl šios priežasties paskirstytose duomenų bazėse stengiamasi logiškai susijusią informaciją saugoti kartu, vienoje fizinėje saugykloje. Būtent šiam tikslui Windows Azure Table saugykloje ir egzistuoja PartitionKey sąvoka. Visos esybės, kurioms nurodytas tas pats PartitionKey, bus ne tik saugomos kartu, bet ir galės dalyvauti transakcijoje (paskirstytose duomenų bazėse transakcijos tarp skirtingų particijų nėra palaikomos). RowKey, kaip ir seka iš pavadinimo, yra įrašo raktas, kuris turi būti unikalus savo particijoje. Kitaip tariant, tikrąjį įrašo ID sudaro pora { PartitionKey; RowKey }.

Windows Azure Table klasių aprašymas

Norint saugoti duomenis Windows Azure Table saugykloje, reikia apibrėžti klasę, kuri paveldėtų iš TableStorageEntity arba turėtų savybes PartitionKey, RowKey ir Timestamp. PartitionKey ir RowKey paskirtį mes jau aptarėme, o savybės Timestamp paskirtis yra aiški – nusako paskutinio atnaujinimo laiką. TableStorageEntity klasės aprašas nurodytas žemiau:

public abstract class TableServiceEntity
{
    protected TableServiceEntity(string partitionKey, string rowKey);
    protected TableServiceEntity();
    public DateTime Timestamp { get; set; }
    public virtual string PartitionKey { get; set; }
    public virtual string RowKey { get; set; }
}

Mažiau žinoma, bet svarbu žinoti

Yra keletas svarbių aspektų, kurios būtina žinoti apie TableServiceEntity:

  • norint gauti konkretų įrašą, reikia nurodyti tiek PartitionKey, tiek RowKey; kitaip gausite visus nurodytos particijos duomenis arba visų particijų įrašus su nurodytu RowKey;
  • nepaisant fakto, kad Windows Azure Table leidžia nurodyti Where sąlyga bet kokiam esybės stulpeliui, niekada to nedarykite, nes indeksuoti yra tik PartitionKey ir RowKey stulpeliai;
  • įrašai yra automatiškai rūšiuojami pirma pagal PartitionKey, po to pagal RowKey ir to pakeisti negalima;
  • norėdami turėti duomenis išrūšiuotus pagal skirtingus stulpelius, teks pradubliuoti duomenis kiekvienam rūšiavimo variantui;
  • PartitionKey reikia parinkti tokį, kad prie jo galima būtų pririšti kuo daugiau susijusios informacijos; tuo pačiu metu PartitionKey neturi būti nei per daug konkretus, nei per daug platus.

Kitoje dalyje…

Tiek trumpai bendros informacijos apie Windows Azure Table saugyklą, kitoje dalyje pereisime prie PingItem esybės aprašymo bei susijusios repozitorijos kūrimo.

Rodyk draugams