zaterdag 14 september 2013

Distributed Cache Service

Commerciële websites moeten razensnel zijn. Een eindgebruiker heeft nu eenmaal geen zin om lang te wachten. Bovendien komt het de ranking in search engines niet ten goede als de website traag reageert. Je kunt er zelfs strafpunten voor krijgen. Er is dus veel aan gelegen dat de reactietijd snel blijft. Er zijn een aantal strategieën die je hiervoor kunt inzetten:
  1. Zorg ervoor dat je niet teveel html naar de client stuurt. Browsers moeten dat allemaal interpreteren en renderen. Kost dus tijd.
  2. Zorg voor voldoende machinecapaciteit. De pagina's worden vaak op de server gegenereerd. Dat kost processorkracht en geheugen. Je kunt natuurlijk een supercomputer aanschaffen, maar dat kost handenvol geld en op een gegeven moment zit je toch aan het hardwareplafond. Ga dus voor een schaalbare oplossing. Veel computers tesamen zijn altijd krachtiger dan de snelste machine. Clouddiensten voorzien in deze behoefte en bieden de mogelijkheid om snel op en af te schalen. Azure kan dit zelfs automatisch op basis van processorgebruik. 
  3. Zorg ervoor dat eenmaal gegenereerde pagina's in het geheugen van de computer bewaard worden (caching), zodat de volgende bezoeker uit de cache kan tappen.
Caching is in ieder geval een handige truc om de website snel te houden. Van belang is wel wat je gaat cachen. Ga je de hele pagina cachen, ga je alleen data cachen of een hybride vorm? Welke strategie je ook kiest, in een gedistribueerde omgeving als Windows Azure is dit niet zo eenvoudig omdat jouw website op meerdere machines draait. Je krijgt dus te maken met duplicate caches. Hoewel geheugen vrij goedkoop is, blijft het natuurlijk wel zonde. Afgezien nog van de tijdsverschillen die ontstaan tussen de verschillende gecachte objecten.

In Windows Azure zijn op dit moment een tweetal mogelijkheden voorhanden (zie blog Caching in Windows Azure):
  1. Shared Cache. Met deze optie staat iedere machine zo'n 30% van zijn geheugen af voor de totale cache. Nadeel is wel dat dit ten koste gaat van de kostbare werkgeheugen van de website. Bovendien werkt het niet echt goed. Met name de eerste keren wil het nog wel eens misgaan. Bovendien wordt deze dienst over een jaar stop gezet.
  2. Dedicated Cache. Hierbij maak je een extra cloud service aan die louter en alleen dienst doet als leverancier van geheugen. Voor zo'n 2,5GB geheugen (een aanzienlijk deel gaat op aan het OS) kost deze oplossing toch al gauw €120,- per maand. 
Sinds een week is er een nieuwe oplossing: Distributed Cache Service. Deze is nog in de preview en zal de huidige cache-oplossingen vervangen. Reden genoeg om deze nieuwe functionaliteit in Windows Azure nader te onderzoeken.

Omdat de Distributed Cache Service geld kost, moet de creditcardhouder eerst een aanvraag doen om deze service te kunnen gebruiken. Daarna kunnen de co-administrators ermee aan de slag. Vanuit de Windows Azure Portal kan nu de cache aangemaakt worden via een nieuw menu-item "Cache" in het linker menu (afbeelding 1).


Afbeelding 1. Het menu-item "Cache" dat zichtbaar wordt wanneer de cachedients geactiveerd is. Van hieruit verloopt alles hetzelfde als bij de andere services: Klink de grote "+" links onderin beeld.
Vervolgens klik je weer op de grote "+" links onderin beeld waardoor je in het configuratiescherm van afbeelding 2 komt. In dit scherm geef je een unieke endpoint naam op. Dit endpoint is het aanspreekpunt van de cache. Hiermee communiceer je met de cache. Daarnaast geef je op in welke regio de cache komt te draaien. Selecteer een cache dicht in de buurt van jouw website. Daarna geef je op welke abonnement je wilt. Je kunt kiezen uit drie vormen:
  1. Basic. De goedkoopste. Hier begin je met 128MB en schaal je in stappen van 128MB op tot 1GB. Je krijgt een default cache aangeleverd en daarmee moet je het maar doen.
  2. Standard. Deze loopt vanaf 1GB geheugen en schaalt in stappen van 1GB op tot een maximum van 10GB. Bij deze optie kun je maximaal tien cachepotten (named caches) aanmaken. Daarnaast kun je inhaken op bepaalde cachegebeurtenissen.
  3. Premium. De duurste vorm en start met 5GB en loopt in stappen van 5GB op tot 150GB. Ook hier kun je maximaal tien cachepotten aanmaken. Hierbij krijg je ook cache replicatie waarmee de beschikbaarheid enorm toeneemt.
Tenslotte geef je op hoeveel fracties van 1GB je als cache wilt gebruiken. Let op dat iedere fractie geld kost.


Afbeelding 2. Configuratie van de cache.
Nadat de cache en het endpoint zijn aangemaakt, kun je het cachegedrag vastleggen. Dit doe je door op het zojuist aangemaakte endpoint te klikken en dan de "Configure" tab te selecteren (afbeelding 3). Vanaf de Standard en Premium abonnementen kun je cachepotten (named caches) aanmaken. De default krijg je standaard aangeleverd waarin je alleen het cachegedrag kunt wijzigen:
  • Name. De naam van de cachepot. Hiernaar zul je in de code verwijzen als je deze cache wilt aanspreken.
  • Expiry Policy. Hier heb je de keuze uit sliding en absolute. Kies sliding als je de cache met een bepaalde duur (Time) wilt verlengen telkens als hij wordt geraadpleegd. Wanneer de cache na een bepaalde tijd hoe dan ook moet vervallen kies je Absolute.
  • Time. Hierbij geef je op hoe lang de levensduur van de cache is.
  • Notifications. Wanneer er zaken gebeuren op de cache, kun je daarvoor een notificatie ontvangen.
  • Eviction. Hierbij geef je op of deze cache opgeruimd mag worden wanneer er een tekort aan geheugen dreigt te ontstaan.
Afbeelding 3. Named Cache configureren.

Natuurlijk is ook de handige scale optie aanwezig waarmee je snel kunnen opschalen wanneer het drukker wordt en een Monitor functie (Afbeelding 4) waarmee we de cache in de gaten kunnen houden. Hierbij is in eerste instantie de "Cache Miss %" interessant om in de gaten te houden. Deze counter geeft aan hoe vaak een cacheaanvraag niet slaagt. Die moet dus zo laag mogelijk blijven.

Afbeelding 4. De monitor functionaliteit in Windows Azure Cache.
In de Azure Portal zijn we nu wel klaar. Tijd om in de code te duiken. Allereest haal je via NuGet de laatste versie van Windows Azure Cache op (versie 2.1.0.0 op het moment van dit schrijven). Vervolgens configureer je de cache in de web.config zodat deze gebruikt maakt van de zojuist aangemaakte cache. Hiervoor specificeer je het adres van het endpoint en geef je de key (te vinden in de Azure Portal bij de cache (Manage Keys)). In het configuratie fragment zie je hoe dat eruit ziet. Bij "identifier" geef je het endpoint adres op en bij "authorizationinfo" de access key.

<dataCacheClients>
  <dataCacheClient name="default">
    <autoDiscover isEnabled="true" identifier="pastest.cache.windows.net" />
    <securityProperties mode="Message" sslEnabled="false">
      <messageSecurity authorizationInfo="YWNzOmh0dHBzOi8vcGFzdGVzdDQ1NzUtY2FjaGUuYWNjZXNzY29ud==" />
    </securityProperties>
  </dataCacheClient>
</dataCacheClients>

Om nu de output cache in te stellen, activeer je het volgende fragment in de web.config


<caching>
   <outputCache defaultProvider="AFCacheOutputCacheProvider">
       <providers>
          <add name="AFCacheOutputCacheProvider" type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, Microsoft.Web.DistributedCache" cacheName="default" dataCacheClientName="default" applicationName="AFCacheOutputCache" />
       </providers>
   </outputCache>
</caching>

De rest is precies zoals je gewend bent te doen: Decoreer controller classen of actions met het OutputCacheAttribute.

In sommige situaties wil je niet de hele pagina cachen maar alleen de data die de pagina gebruikt. Denk hierbij aan een in-memory dataset waarin productdata wordt opgeslagen zodat er snel en eenvoudig gefilterd kan worden op bijvoorbeeld productspecificaties. Hiervoor kun je de DataCache class uit het Windows Azure Cache package gebruiken. In het codefragment hieronder zie je hoe dat gaat.

public class HomeController : Controller
{
    private DataCache cache = new DataCache("test");

    public ActionResult Index()
    {
        object co = cache.Get("time");
        if (co == null)
        {
            co = DateTime.Now;
            cache.Put("time", co);
        }
        ViewBag.TheDate = co;
        ViewBag.RoleID = RoleEnvironment.CurrentRoleInstance.Id;
        return View();
    }

    private void OnDataCacheNotificationCallback(
        string cacheName,
        string regionName,
        string key,
        DataCacheItemVersion version,
        DataCacheOperations cacheOperation,
        DataCacheNotificationDescriptor nd)
    {
        ViewBag.Name = cacheName;
        ViewBag.Region = regionName;
        ViewBag.Key = key;
        ViewBag.Version = version;
        ViewBag.Operation = cacheOperation;
    }

    public HomeController()
    {
        DataCacheNotificationDescriptor desc = cache.AddCacheLevelCallback(
            DataCacheOperations.AddItem | DataCacheOperations.RemoveItem,
            OnDataCacheNotificationCallback);
    }
}

In de action "Index" zie je hoe je data aan de cache kunt toevoegen en weer uitlezen. Vooralsnog is er geen rekening gehouden met concurrency, maar aan het locking mechanisme is verder niets veranderd (zie blog Caching in Windows Azure).
De rest van de code laat zien hoe je gebruik maakt van het notificatie mechanisme in Windows Azure Cache (Wel eerst aanzetten in de Azure Portal (afbeelding 3)).

Het gaat allemaal erg snel met Windows Azure. De ene nieuwe functionaliteit volgt de andere rap op. Distributed Cache in Windows Azure is wederom een mooie aanwinst. Eindelijk zijn we af van die brakke gedistribueerde oplossingen waarbij we een deel van het werkgeheugen van de site moesten afstaan aan de cache of een complete omgeving op moesten zetten voor het geheugen.

Geen opmerkingen:

Een reactie posten