ITishnikai #13 – IT renginių apžvalga

Parašė Sergejus | 2012-03-13 19:51

Naujame ITishnikai epizode pas mus vėl svečiuojasi Alan Mendelevič, kuris dalijasi savo įspūdžiais iš Mobile Worlds Congress, TechDay Belgium ir kitų renginių. Kaip visada laida prieinama mūsų Facebook puslapyje bei parsiuntimui. Labai laukiam jūsų atsiliepimų bei komentarų!

Rodyk draugams

Lietuvos .NET vartotojų grupės susitikimai

Parašė Sergejus | 2012-03-11 00:00

Šį kartą jūsų laukia du labai praktiški pristatymai iš WCF greitaveikos optimizavimo (arba kaip išspausti maksimumą iš WCF) ir įvadas į Git - paskirstytą versijų valdymo kontrolės sistemą.

Susitikimai vyks kovo 21 Vilniuje Crowne Plaza ir kovo 22 Kaune Technopolyje.

18:00 – 19:00 – WCF greitaveikos optimizavimas, Donatas Mažionis, Adform

19:30 – 20:30 – Įvadas į GIT, Mindaugas Mozūras, Adform

21:00 – … Boulingas!

Registruokitės Vilniuje ir Kaune. Iki susimatymo!

Rodyk draugams

ZeroMQ – Push / Pull šablono įgyvendinimas (3 dalis)

Parašė Sergejus | 2012-03-08 23:59

Praeitoje (2-oje) dalyje aš parodžiau kaip įgyvendinti Request / Reply šabloną ZeroMQ pagalba. Šį kartą įgyvendinsiu Push / Pull šabloną, kuris yra vienkrypčio komunikavimo pagrindas.

Push / Pull šablonas

Supaprastinai, Push / Pull šablonas atrodo taip:

image

Paprasčiausia serverio realizacija atrodytų taip:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.PULL))
{
    socket.Bind("tcp://*:9001");

    while (true)
    {
        var clientMessage = socket.Receive(Encoding.Unicode);
        Console.WriteLine(clientMessage);

        Console.WriteLine("--------------------------------");
    }
}

Tikriausiai, jau įsivaizduojate kaip atrodo kliento dalis:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.PUSH))
{
    socket.Connect("tcp://localhost:9001");

    for (var i = 0; ; i++)
    {
        var clientMessage = "CLIENT> Request #" + i;
        socket.Send(clientMessage, Encoding.Unicode);
        Console.WriteLine(clientMessage);

        Console.WriteLine("--------------------------------");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
}

Jeigu palygintumėte Pull / Push serverio / kliento realizaciją su Request / Reply, pastebėtume, kad jos yra praktiškai vienodos, skiriasi tik du dalykai:

  • soketų tipai
  • komunikavimas tarp kliento ir serverio yra vienkryptis

ZeroMQ pagalba su minimaliais pakeitimais mes iš esmės pakeitėme komunikavimo šabloną!

ZeroMQ apkrovos paskirstymo galimybė

ZeroMQ pasižymi ne tik palaikomų komunikavimo šablonų bei protokolų įvairove, bet ir apkrovos paskirstymo galimybe (angl. load balancing) su automatiniu ryšio problemų aptikimu. Tarkime, visą apkrovą mes norime paskirstyti tarp 3 serverių, šiuo atveju aukščiau pateiktas kliento kodas atrodytų taip:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.PUSH))
{
    socket.Connect("tcp://localhost:9001");
    socket.Connect("tcp://localhost:9002");
    socket.Connect("tcp://localhost:9003");

    for (var i = 0; ; i++)
    {
        var clientMessage = "CLIENT> Request #" + i;
        socket.Send(clientMessage, Encoding.Unicode);
        Console.WriteLine(clientMessage);

        Console.WriteLine("--------------------------------");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
}

Kaip matote, užtenka tiesiog pridėti dar 2 Connect iškvietimus, ir ZeroMQ yra pakankamai sumanus, kad automatiškai pradėti balansuoti siunčiamus pranešimus tarp trijų serverių (round robin principu).

Kas atsitinka, kaip vienas iš serverių nepasiekiamas? Kaip jau rašiau pirmoje dalyje, ZeroMQ visus siunčiamus bei gaunamus pranešimus buferizuoja eilėse atmintyje. Soketui galima nustatyti SendHighWatermark ir ReceiveHighWatermark parametrus, kurie ir nusako siuntimo / gavimo buferių dydį. Pagal nutylėjimą į buferius telpa 1000 pranešimų, kuriems užsipildžius, tolimesnis siuntimas / gavimas tiesiog užsiblokuoja. ZeroMQ automatinis ryšio problemų aptikimas yra paremtas buferio dydžiais, tad kai siuntimo buferis užsipildo, serveris išimamas iš apkrovos balansavimo. Kadangi 1000 neišsiųsti žinučių gali būti pakankamai daug, greitesniam problemų aptikimui galima sumažinti SendHighWatermark iki 10:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.PUSH))
{
    socket.SendHighWatermark = 10;

    socket.Connect("tcp://localhost:9001");
    socket.Connect("tcp://localhost:9002");
    socket.Connect("tcp://localhost:9003");

    for (var i = 0; ; i++)
    {
        var clientMessage = "CLIENT> Request #" + i;
        socket.Send(clientMessage, Encoding.Unicode);
        Console.WriteLine(clientMessage);

        Console.WriteLine("--------------------------------");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
}

Kitoje dalyje

Tiek šiam kartui, tikiuosi man pavyko parodyti koks lankstus ir galingas ZeroMQ yra. Kitoje dalyje įgyvendinsime kitą labai svarbų komunikavimo šabloną – Publish / Subscribe.

Rodyk draugams

Nauji Microsoft produktai

Parašė Sergejus | 2012-03-07 19:33

Per praeitą savaitę buvo išleisti kaip niekada daug Microsoft produktų, tad nusprendžiau skaitytojų patogumui išvarinti produktus su atitinakamomis nuorodomis parsiuntimui.

Atkreipkite dėmesį į SQL Server. Taip, šiandien oficialiai pasirodė galutinė SQL Server 2012 versija!

Rodyk draugams

ZeroMQ – Request / Reply šablono įgyvendinimas (2 dalis)

Parašė Sergejus | 2012-03-06 20:33

Praeitoje dalyje aš aprašiau pagrindines ZeroMQ galimybes bei apribojimus, o šioje dalyje pateiksiu paprasčiausią Request / Reply principu veikiantį kliento / serverio pavyzdį.

Prieš pradedant

Norėdami pridėti ZeroMQ į sprendimą, Package Manager konsolėje įvykdykite komandą Install-Package clrzmq –Pre.

Request / Reply šablonas

Supaprastintai, Request / Reply šablonas atrodo taip:

Untitled

ZeroMQ dėka paprasčiausia serverio realizacija telpa į 10 eilučių:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.REP))
{
    socket.Bind("tcp://*:9001");

    while (true)
    {
        var clientMessage = socket.Receive(Encoding.Unicode);
        Console.WriteLine(clientMessage);

        var serverMessage = "SERVER> Response" + Regex.Match(clientMessage, "#\\d+").Value;
        socket.Send(serverMessage, Encoding.Unicode);

        Console.WriteLine("--------------------------------");
    }
}

Kaip matyti, serverio pusėje mes sukuriame Reply tipo soketą, kuriam nurodome naudoti 9001 portą bei TCP protokolą. Kliento realizacija yra labai panaši į serverio:

using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.REQ))
{
    socket.Connect("tcp://localhost:9001");

    for (var i = 0; ; i++)
    {
        var clientMessage = "CLIENT> Request #" + i;
        socket.Send(clientMessage, Encoding.Unicode);

        var serverMessage = socket.Receive(Encoding.Unicode);
        Console.WriteLine(serverMessage);

        Console.WriteLine("--------------------------------");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
}

Kliento pusėje sukuriamas Request tipo soketas iš kurio bandoma prisijungti prie anksčiau aprašyto serverio. Pažymėtina, kad mes galime paleisti iš karto kelis klientus, kurie lygiagrečiai dirbs su tuo pačiu serveriu.

Kitoje dalyje

Tiek šiam kartui, kitoje dalyje ZeroMQ pagrindu įgyvendinsime Push / Pull šabloną bei išnagrinėsime ZeroMQ apkrovos paskirstymo (angl. load balancing) galimybę.

Rodyk draugams

ITishnikai #12 – dizaino ir UX svarba

Parašė Sergejus | 2012-02-22 22:05

Naujame ITishnikai epizode mes kalbame apie dizainą ir UX (User eXperience) svarbą su UX dizaineriu Edvinu Aržatskiu. Kaip visada laida prieinama mūsų Facebook puslapyje bei parsiuntimui. Labai laukiam jūsų atsiliepimų bei komentarų!

Rodyk draugams

ZeroMQ – Įvadas (1 dalis)

Parašė Sergejus | 2012-02-19 18:46

Šiandien pradedu straipsnių ciklą apie neįtikėtiną biblioteką ZeroMQ (ØMQ), kuri leidžia ženkliai supaprastinti paskirstytų programų kūrimą. Pradėsiu nuo to, kas nėra ZeroMQ. Nepaisant MQ santrumpos pavadinime, tai nėra eilių (angl. Message Queue) sprendimas kaip RabbitMQ, ActiveMQ ar MSMQ. Taipogi, tai nėra WCF ar Thrift RPC atitikmuo. Aš apibrėžčiau ZeroMQ kaip ypatingai greitą ir labai paprastą panaudojime buferizuotą soketų komunikavimo biblioteką.

Kam teko programuoti soketus (nesvarbu kokia programavimo kalba), tikriausiai pritars, kad tai nėra labai paprastas užsiėmimas reikalaujantis pakankamai gilių tinklo žinių. Reikia galvoti apie prisijungimus, atsijungimus, ryšio palaikymą, buferizavimą, tinklo problemų aptikimą, siuntimo pakartojimą ir dar daug kitų dalykų. ZeroMQ – tai labai patogi abstrakcija virš soketų. Ši biblioteka leidžia pamiršti apie visas su žinučių perdavimu susijusias problemas išlaikant soketų greitaveiką.

ZeroMQ galimybių apžvalga

ZeroMQ leidžia nesukti galvos dėl prisijungimo eiliškumo – klientai ir serveriai gali būti paleidžiami bet kokia eilės tvarka. Jeigu klientas pasileis pirmas ir reikalingo serverio nebus – visos žinutės bus kaupiamos kliento pusėje ir išsiųstos kai tik serveris taps prieinamas.

Dėl bibliotekos paprastumo (leidžiama siųsti ir priimti tik baitų masyvus), nereikia prisirišti prie konkretaus komunikavimo protokolo ir galima naudoti bet kurį duomenų formatą: JSON, BSON, Protocol Buffers (ProtoBuf) ir t.t.

Kadangi ZeroMQ yra žemo lygio abstrakcija virš soketų parašyta su C ir viduje veikia pilnai asinchroniškai, ji pasižymi ypatinga greitaveika. Lokaliame kompiuteryje man pavyko pasiekti 30 tūkstančių žinučių per sekundę perdavimo greitį, įskaitant duomenų serializavimą į ir iš ProtoBuf.

Kita nuostabi bibliotekos savybė – ji palaiko visus pagrindinius komunikavimo šablonus:

Papildomai, ZeroMQ palaiko tokius transporto protokolus kaip in-process, IPC, multicast ir TCP. Norimas protokolas nurodomas tiesiai prisijungimo eilutėje, tad jo keitimas yra trivialus konfigūracijos atnaujinimas.

Ir pabaigai, kas labiausiai mane sužavėjo – ZeroMQ automatiškai palaiko žinučių balansavimą (round-robin principu) bei turi lokalius buferius (eiles). Visos įeinamos ir išeinamos žinutės pirma dedamos į eiles, iš kurių žinutė po žinutės yra išimamos ir apdorojamos.

ZeroMQ apribojimai

Apart visų aukščiau išvardintų privalumų, manau būtina žinoti ir tam tikrus bibliotekos apribojimus. Skirtingai negu pilnaverčiai eilių sprendimai, ZeroMQ neturi centrinio brokerio, kas gali būti tiek privalumas, tiek ir trūkumas:

  • Brokerio nebuvimas leidžia pasiekti žymiai geresnių greitaveikos rezultatų negu bet koks kitas eilių sprendimas.
  • Brokeris eilių sprendimuose yra labai svarbus ir jam nulūžus – visos eilės sustoja. ZeroMQ tokios problemos neturi, nes centrinio komunikavimo taško nėra.
  • Architektūriškai, ZeroMQ negarantuoja žinučių eiliškumo išlaikymo, tad vėliau siųsta žinutė gali būti apdorota pirmiau už anksčiau siųstą.
  • Kadangi žinučių eilės saugomos atmintyje, nulūžus programai pradings ir visos neapdorotos / neišsiųstos žinutės.

Kitoje dalyje

Tiek šiam kartui, tikiuosi pavyko jus sudominti ZeroMQ galimybėmis. Kitoje dalyje sukursime kliento-serverio programas, kurios komunikuos Request / Reply principu su automatiniu žinučių balansavimu.

Rodyk draugams

UrlBuilder – paprasta klasė skirta URL formavimui

Parašė Sergejus | 2012-02-08 23:15

Atnaujinta: Atviras kodas daro stebuklus, su Giedriaus pagalba turime atnaujintą klasės variantą!

Darbas su HTTP API dažnai iš programuotojų reikalauja URL formavimo. Keista, bet .NET Framework iki šiol neturi standartinės klasės šiai užduočiai spręsti. Egzistuoja artima pagal paskirtį UriBuilder klasė, bet ji nėra optimizuota darbui su URL. Bekuriant DotNetGroup 3.0 gimė labai paprasta URL formavimui skirta klasė UrlBuilder:

public class UrlBuilder
{
    private readonly Uri baseUrl;
    private readonly IList<string> relativeUrlParts;
    private readonly IList<string> queryStringParameters;

    public UrlBuilder(string baseUrl)
    {
        if (baseUrl == null)
        {
            throw new ArgumentNullException("baseUrl");
        }

        if (!Uri.IsWellFormedUriString(baseUrl, UriKind.Absolute))
        {
            throw new ArgumentException("Base URL format is not valid", "baseUrl");
        }

        this.baseUrl = new Uri(baseUrl);
        this.relativeUrlParts = new List<string>();
        this.queryStringParameters = new List<string>();
    }

    public void AddPart(object value)
    {
        this.relativeUrlParts.Add(value.ToString());
    }

    public void AddParameter(string name, object value)
    {
        this.queryStringParameters.Add(name + "=" + value);
    }

    public string Build()
    {
        var relativeUrl = new Uri(string.Join("/", this.relativeUrlParts), UriKind.Relative);
        var queryString = string.Join("&", this.queryStringParameters);

        var uriBuilder = new UriBuilder(new Uri(this.baseUrl, relativeUrl))
        {
            Query = queryString
        };

        return uriBuilder.Uri.AbsoluteUri;
    }
}

Kaip matote, rezultate gavosi visai patogi pagalbinė klasė URL formavimui:

[TestFixture]
public class UrlBuilderTests
{
    private const string BaseUrl = "http://api.dotnetgroup.dev";

    [Test]
    public void Given_No_Arguments_Base_Url_With_Trailing_Slash_Is_Returned()
    {
        var expectedUrl = "http://api.dotnetgroup.dev/";

        var urlBuilder = new UrlBuilder(BaseUrl);

        var url = urlBuilder.Build();

        Assert.AreEqual(expectedUrl, url);
    }

    [Test]
    public void Given_Type_Argument_Correct_Url_Is_Generated()
    {
        var expectedUrl = "http://api.dotnetgroup.dev/?type=rss";

        var urlBuilder = new UrlBuilder(BaseUrl);
        urlBuilder.AddParameter("type", "rss");

        var url = urlBuilder.Build();

        Assert.AreEqual(expectedUrl, url);
    }

    [Test]
    public void Given_Date_From_And_Limit_Correct_Url_Is_Generated()
    {
        var expectedUrl = "http://api.dotnetgroup.dev/?from=2012-01-01%2010:00:00&limit=10";

        var urlBuilder = new UrlBuilder(BaseUrl);
        urlBuilder.AddParameter("from", "2012-01-01 10:00:00");
        urlBuilder.AddParameter("limit", 10);

        var url = urlBuilder.Build();

        Assert.AreEqual(expectedUrl, url);
    }

    [Test]
    public void Given_Get_And_Id_Parts_Correct_Url_Is_Generated()
    {
        var expectedUrl = "http://api.dotnetgroup.dev/get/1";

        var urlBuilder = new UrlBuilder(BaseUrl);
        urlBuilder.AddPart("get");
        urlBuilder.AddPart(1);

        var url = urlBuilder.Build();

        Assert.AreEqual(expectedUrl, url);
    }
}

P.S. Šios klasės išeities kodas taipogi prieinamas DotNetGroup 3.0 GitHub repozitorijoje.

Rodyk draugams

ITishnikai #11 – IT darbo interviu

Parašė Sergejus | 2012-02-05 16:09

Naujame ITishnikai epizode mes kalbame apie IT darbo interviu ir CV sudarymą su personalo vadove Agne Klasavičiene. Laida prieinama mūsų Facebook puslapyje bei parsiuntimui. Labai laukiam jūsų atsiliepimų bei komentarų!

Minėtos nuorodos:

Rodyk draugams

Jubiliejinis ITishnikai #10 epizodas

Parašė Sergejus | 2012-01-23 20:27

Jubiliejinis, jau 10-as ITishnikai epizodas prieinamas mūsų Facebook puslapyje bei parsiuntimui. Šį kartą svečiuose – Tautvydas Dagys iš Microsoft Lietuva. Labai laukiam jūsų atsiliepimų bei komentarų!

Minėtos nuorodos:

Rodyk draugams