2011. szeptember 25., vasárnap

Gyorsan válaszoló Azure Web Role Application

Sokak számára okoz fejfájást a IIS recycling. Kis idő után az alkalmazásunk leáll, majd egy új user request éleszti. Ez kisebb forgalmú web alkalmazásoknál egész kellemetlen lehet. Egy kis cache töltögetés, vagy hasonló tevékenység őrületbe kergeti a kedves felhasználót a túloldalon. Engem is…

Érdekes, hogy mennyire jól konfigurálható, hogy az alkalmazásunk milyen szabályok teljesülése esetén legyen leállítva. Ezzel szemben nincs semmilyen normális infrastruktúra arra, hogy az alkalmazás újra el is induljon. Pontosabban a IIS 7.5-ig nem volt.

Ez az IIS verzió a Windows Server 2008 R2-ben debütált, így ha használni akarjuk a WebRole-unkban az új lehetőséget, akkor mindenképpen R2 operációs rendszert kell hozzárendelnünk a Role-hoz.

A fent említett szolgáltatás az “Auto-Start” elnevezésre hallgat, ami máris segít, hogy elkeveredjünk és esetleg összetévesszük az application pool AutoStart beállításával. Nagyon jó a megoldás, mert nem úgy dolgozik, hogy a recycling lenyomja az appunkat, hanem előbb meghívja a warm-upot egy új worker processben, majd ha az véget ér, akkor állítja le a korábbi workert. ScottGu rövid bemutató cikkét elolvasva arra jutottam, hogy ezt pedig én beállítom az Azure alkalmazásomra is.

Az IIS beállításainak módosítására több út is van. Ezek közül csak a programozott eljárást mutatom be.

A cikket elolvasva látható, hogy nem bonyolult a funkció életre keltése, egyszerűen csak editáljuk az applicationHost.config fájlt, implementáljuk a WarmUp kódot és minden príma… Na igen, de azért az Azure-ban ilyeneket nem csinálunk...

Az alábbi kód egy komplett megoldás arra, hogy a WebRole egyik Site-ját Auto-Start-ossá tegyük. De szép mondat!

Gyors lépésről lépésre áttekintés a megoldás használatához.

  1. A WebRole projekthez hozzá kell adni az alábbi referenciát:
    %WindowsDir%\System32\inetsrv\Microsoft.Web.Administration.dll. Ez az assembly tartalmazza az IIS adminisztrációhoz szükséges logikát.
  2. Be kell állítani a Microsoft.Web.Administration referencia Copy Local projekt tulajdonságát True-ra.
  3. Minden ServiceConfiguration fájlban be kell állítani a ServiceConfiguration elemben a osFamly attribútumot 2-re. Ez azt jeleni, hogy Windows Server 2008 R2 rendszeren fog futni a role.
    <ServiceConfiguration serviceName="FastAzureApp" xmlns="" 
                          osFamily="2" osVersion="*">
  4. Ugyanebben a konfigurációban be kell állítani a következőt, hogy legyen jogunk “állítgatni”:
    <Runtime executionContext="elevated" />
  5. Hozzá kell adni a WebRole-hoz egy osztályt, amely a warm up során lesz példányosítva és meghívva. A példában FastMvcWebRole.Helpers.WarmUp
  6. Meg kell valósítani a WarmUp osztályban a IProcessHostPreloadClient interfészt.
    public class WarmUp : IProcessHostPreloadClient
    {
        public void Preload(string[] parameters)
        {
            Trace.WriteLine("Warm up.");
     
            //Inicializáló kód jöhet ide...
     
            Trace.WriteLine("Warm up done.");
        }
    }
  7. Az alábbi metódust hozzáadva a WebRole osztályhoz, beállítható az IIS Auto-Start feature:

    /// <summary>
    /// Az site és az application pool beállításainak módosítása az IIS konfigurációkban
    /// </summary>
    /// <param name="siteName">A paraméter ServiceDefinition.csdef fájl Site name-re utal</param>
    /// <param name="keyName">A serviceAutoStart elem egyedi kulcsa (IIS szinten)</param>
    /// <param name="methodReference">A Warm Up metódus referenciája "Namespace.Metodus, Assembly" formátumban</param>
    private void SetupIIS(string siteName, string keyName, string methodReference)
    {
        using (var serverManager = new ServerManager())
        {
            var siteRealName = string.Format("{0}_{1}", RoleEnvironment.CurrentRoleInstance.Id, siteName);
     
            var site = serverManager.Sites[siteRealName];
            if (site == null)
                throw new Exception(String.Format("Site not found: {0}", siteRealName));
     
            var siteApplication = site.Applications.FirstOrDefault();
            if (siteApplication == null)
                throw new Exception(string.Format("Site Application (first) not found:{0}", siteRealName));
     
            var appPoolName = siteApplication.ApplicationPoolName;
            var appPool = serverManager.ApplicationPools[appPoolName];
     
            //Egy óra tétlenség után legyen recycle
            appPool.ProcessModel.IdleTimeout = TimeSpan.FromMinutes(60);
     
            //Periodikusan is legyen recycle
            appPool.Recycling.PeriodicRestart.Time = TimeSpan.FromHours(29);
     
            //Tegyük az Application Pool-t Always Running módba
            appPool["startMode"] = "AlwaysRunning";
     
            //Állítsuk be a site-on is az AutoStart szolgáltatás engedélyezését
            siteApplication["serviceAutoStartEnabled"] = true;
     
            //Adjuk meg az AutoStart providerünk kulcsát
            siteApplication["serviceAutoStartProvider"] = keyName;
     
            //Adjunk hozzá egy elemet (saját providerünk) az serviceAutoStartProviders kollekcióhoz
            var config = serverManager.GetApplicationHostConfiguration();
            var serviceAutoStartProvidersSection = config.GetSection("system.applicationHost/serviceAutoStartProviders");
            var serviceAutoStartProvidersCollection = serviceAutoStartProvidersSection.GetCollection();
     
            var serviceAutoStartProviderElement =
                serviceAutoStartProvidersCollection.SingleOrDefault(f => f.ElementTagName == "add" && (string)f.Attributes["name"].Value == keyName);
     
            if (serviceAutoStartProviderElement != null)
                serviceAutoStartProvidersCollection.Remove(serviceAutoStartProviderElement);
     
            serviceAutoStartProviderElement = serviceAutoStartProvidersCollection.CreateElement("add");
            serviceAutoStartProviderElement["name"] = keyName;
            serviceAutoStartProviderElement["type"] = methodReference;
            serviceAutoStartProvidersCollection.Add(serviceAutoStartProviderElement);
     
            serverManager.CommitChanges();
        }
    }
  8. Hívjuk meg a SetupIIS metódust az OnStart override-olt metódusból.
    public override bool OnStart()
    {
        SetupIIS("Web", "FastMvcWebRoleWarmUp", 
            "FastMvcWebRole.Helpers.WarmUp, FastMvcWebRole");
     
        return base.OnStart();
    }

Ennyi az egész.
A forráskód elérhető a CodePlex-en: http://martonrusko.codeplex.com címen, vagy letölthető innen:

Nincsenek megjegyzések:

Megjegyzés küldése