📜 ⬆️ ⬇️

Caching in Windows Azure

The problem of caching is faced by any high-loaded application. In Windows Azure, where the main algorithm for increasing productivity is adding instances of an application, the role of the cache becomes even more important, because with it, you can provide "shared memory" for all instances.

Memorycache


In general, this class is not related to Azure, but it is simply impossible not to mention it in the article about caching.

Starting with .Net 4, the new namespace System.Runtime.Caching has appeared. Engaged in MemoryCache, as the name implies, the creation of a repository of objects in memory. For me it is important because it works much faster than Cache from the System.Web.Caching space. Another nice feature is that you can create multiple caches with different settings.

For simplicity, you can immediately describe the cache parameters in the configuration and then access it through MemoryCache.Default. Other caches need to be initialized forcibly and keep references to them. Parameters can be set both in runtime and in configuration:
<configuration> <system.runtime.caching> <memoryCache> <namedCaches> <add name="default" cacheMemoryLimitMegabytes="0" physicalMemoryPercentage="0" pollingInterval="00:02:00" /> </namedCaches> </memoryCache> </system.runtime.caching> </configuration> 

')

In-role cache


As a rule, each application in the cloud has several instances: on the one hand, this provides fault tolerance (SLA Azure in principle requires at least two instances) and scalability with increasing and decreasing loads.

Regularly there is a desire to provide a single "memory" for all instances. The simplest example would be a session. To do this, Azure has an In-Role Cache mechanism that allows you to allocate part or all of the instance’s memory to the cache, and it will be available from all instances of the application.

To use it, you need to add the Windows Azure Caching package to the solution and configure the roles for working with it.

First we need to enable the cache on the instances or add the instances selected for the cache to the solution.
Warning : cache is not supported on ultra small (extra small) instances.

Pictures about turning on the cache
Enable cache on existing role


Creating a cache-allocated role




There will always be a cache named “default”. We can add caches with their own names and various settings.

Cache settings

High Availability.
Requires that the solution contains at least two instances on which the cache is located. The data entering the cache will be stored on at least two copies and the failure of one copy will not lead to data loss. Use this option carefully, because the cache begins to absorb much more resources.

Notifications
Enable / disable the alert mechanism for the cache. They literally just appeared and there are no real scenarios for them, I have not yet invented.

Eviction policy
How the cache will be cleared in case of overflow. For inclusion, only one option is currently available - LRU (Least recent use). Those. which object was least accessed - it will be deleted.

Obsolescence (Expiration Type) and Time to Live (TTL, Time To Live)
Two interrelated parameters indicate how and for how long (in minutes) they will become obsolete in the cache and disappear from it. Those. if the cleanup option is more abnormal (cache overflow does not usually lead to anything good), then obsolescence allows us to describe how objects should disappear from the cache during normal operation.
None. Objects will be stored in the cache forever (until the reboot). Requires the lifetime to be set to zero.
Absolute. The object is stored in the cache for some time after it got there.
Sliding window. My favorite option. The object will disappear from the cache after a specified time after the last access. Those. objects accessed will constantly live in the cache.

Setting client cache


In general, everything is quite simple: in the configuration file we describe what caches we have and where we are located. Paste the following lines into the configuration file in the configuration section (their template should have already created NuGet when installing the caching package).
 <dataCacheClients> <dataCacheClient name="default"> <autoDiscover isEnabled="true" identifier="CacheWorkerRole" /> <localCache isEnabled="true" sync="TimeoutBased" objectCount="100000" ttlValue="300" /> </dataCacheClient> <dataCacheClient name="MyNamedCache"></dataCacheClients> 

As an identifier you need to specify the name of the role containing the cache in the project. In our case, CacheWorkerRole. And not the name of the access point in Azure, such as mycoolapp.cloudapp.net.

The explanations are probably required only by the localCache tag, which indicates that the instance can store objects locally and the principle of storage. objectCount determines how many objects we will store locally, upon reaching the specified number, the cache will remove from the local copy 20% of the objects that have not been accessed for the longest.

Time synchronization (TimeBased) indicates that the objects will be stored in the local cache the number of seconds specified in ttlValue. NotificationBased requires that the alert mechanism be enabled in the cache. In this case, the ttlValue parameter indicates the frequency with which the local cache will check for changes in the cache.

Basic settings completed. Now, for example, let's connect the sessions of our web role to the cache. In IIS, this is done very simply by replacing the standard InProc session provider with a provider that uses the cache.
 <sessionState mode="Custom" customProvider="AFCacheSessionStateProvider"> <providers> <add name="AFCacheSessionStateProvider" type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, Microsoft.Web.DistributedCache" cacheName="default" dataCacheClientName="default" applicationName="AFCacheSessionState"/> </providers> </sessionState> 

The session is a great example of where the cache can be used. But you should not be limited only to her. For example, you can cache pages, then other instances will not have to spend time building them. And by itself, in the cache can and should add our own data.

Before proceeding to the examples of working with the cache from the code, we will focus on a completely new kind of cache.

Cache service


While the cache as a service is available in preview mode (preview). It may be in demand in scenarios where different solutions must have access to the same data. In-Role cache is available only within the solution to which it is attached. The cash service is deprived of this.

Configuring the cache service one-on-one is the same as setting the In-Role cache, but you need to do it not in the studio, but in the Azure management portal. A cache access key will be added to the role configuration.


Another advantages of the cache service include:
- a slightly lower price;
- no headache during deployment updates (they will not affect the cache);
- protocol support memcached, which allows you to connect to it not only PaaS solutions, but also any type of virtualok.

A few more words on the setting


Creating a cache is to know how many objects, how much will be stored in it and with what frequency they will be read and written. When these values ​​are known, the data must be driven into one of the exel plates (for service or roles ) and get recommendations on how much and what you need in terms of chargeable units.

Objects are stored in the cache in a serialized form, therefore, to determine the volume of an object, you need to get the size after serializing the object itself and its key.

The size of the object in the cache after serialization is limited to 8 megabytes. If you go beyond the limit, you can enable compression for the cache, then objects will be compressed before entering the cache. In general, compression can have a positive effect on the work of the cache, if the cost of packing-unpacking is less than the cost of a network transfer. Unfortunately, this can only be found out experimentally.

To increase the bandwidth of the cache, you can increase the number of connections to it with the maxConnectionsToServer parameter. By default, only one cache connection is created.

Work with cache from code


Everything you need to work with the cache lives in Microsoft.ApplicationServer.Caching.

To begin, create a cache object and use the Add, Put, Get, and Remove commands to start working with data.
 DataCache dc = new DataCache("default"); dc.Add("test", DateTime.Now); //    dc.Put("test", DateTime.Now); //   DateTime dt=(DateTime)dc.Get("test"); // dc.Remove("test"); // 


Race

To prevent a race, use GetAndLock, PutAndUnlock, and Unlock. The operator GetAndLock does not block the normal Get and does not interfere with "dirty" reading.
 try { DataCacheLockHandle lockHndl; object value = dc.GetAndLock("test", new TimeSpan(0, 0, 5), out lockHndl); //  dc.PutAndUnlock("test", value, lockHndl); // dc.Unlock("test", lockHndl)     } catch (DataCacheException de) { if (de.ErrorCode == DataCacheErrorCode.KeyDoesNotExist) { //  } } 

Reading updates

It is easy to imagine a scenario in which you need to take some action when changing an object in the cache. You can get an object and compare it with the current value, but you can reduce the cache load using the GetIfNewer method.
 object val = DateTime.Now; DataCacheItemVersion version = dc.Put("test", val); while (true) { val = dc.GetIfNewer("test", ref version); if (val != null) { //  } Thread.Sleep(1000); } 

If the object appears in the cache, somewhere else, you can get its version from the DataCacheItem object.

 DataCacheItem dci = dc.GetCacheItem("test"); DataCacheItemVersion version = dci.Version; object val = dci.Value; 

Regions

To group objects, you can use regions. In each of the methods listed above, the second argument can be passed the name of the region (after creating it) in which to create an object. And after that, it is easy to iterate over objects in the cache.
 if (dc.CreateRegion("region")) { //  ,   } dc.Put("test", DateTime.Now, "region"); foreach (KeyValuePair<string, object> kvp in dc.GetObjectsInRegion("region")) { //  } 

The regions have a couple of features that should be considered when working with them.

It is not necessary to sort objects in the region directly as in the code above. If another thread adds or removes an object in it, we will run into an exception: “the collection has changed.”

The second feature: the region lives within the limits of one copy. Those. if the distribution of objects across regions is uneven, then a situation may arise when one of the instances idle, and the other is boiling under load.

What is worth remembering when working with cache


- The size of the object in the cache is limited to 8 megabytes.
- If regions are used, they should be filled evenly
- Cache objects locally whenever possible.
- Include high availability only where it is needed.
- Use locks (GetAndLock) only where necessary
- Do not read objects if they are not updated (use GetIfNewer)

I hope this article will help others go through fewer rakes than I collected. Successes in development, let your applications be fast.

Google Plus

Source: https://habr.com/ru/post/200744/


All Articles