3

Just a bit of background first. I currently have a site hosted with Windows Azure, with multiple instances and also AppFabric as my sole caching provider.

Everything was going great until my traffic spiked earlier this morning. After the instances became overloaded and stopped responding everything came good again once the new instances started.

However I started getting messages from AppFabric saying that I was being throttled because there were too many requests in a given hour. Which is fair enough, it certainly was giving it hell.

In order to avoid these messages in the future I was planning on implementing an InProc cache for very short lifespan. So it checks InProc first, if not goes to AppFabric, if not goes to DB.

 ObjectCache cache = MemoryCache.Default;

 CacheItemPolicy policy = new CacheItemPolicy();
 policy.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(5);

The questions I have are

  • Is this the best way to handle the situation?
  • Is this going to interfere with AppFabric Caching?
  • Any issues I am overlooking?

Update I just wanted to say I chose the above method and it works well. I was using it only for general data storage and not session state. MemoryCache with session state would not work too well on Azure due to no server affinity (as mentioned by David below).

Update 16-03-2012 After realizing the obvious I also disabled SessionState on most pages. Most of my pages don't need it and hence this rapidly decreases my calls to cache under heavy load. I also disabled ViewState for most pages as well, just for that slightly quicker page load time.

Adam
  • 16,089
  • 6
  • 66
  • 109
  • I've found that you shouldnt use InProc with Azure, especially on a role with multiple instances. You are not guaranteed to have that context that of accessing the same process on the same instance across requests. – Glenn Ferrie Mar 08 '12 at 05:08
  • Hi Glenn. Thanks for responding. I am aware that InProc won't be the same across any instance, however I was talking more about using InProc as a temporary cache on each instance, that expires after a few minutes, just to take some pressure off AppFabric. I also thought it would be far faster under heavy loads to get from InProc, even if it is wiped every 5 minutes. – Adam Mar 08 '12 at 05:15
  • Have you considered monitoring requests and programmatically spinning up new instances at peak times? – Glenn Ferrie Mar 08 '12 at 05:16
  • http://stackoverflow.com/questions/6713721/change-the-value-of-instances-count-programmatically-in-azure – Glenn Ferrie Mar 08 '12 at 05:17
  • I think you should distinguish between local cache and Appfabric Cache. please check this article http://www.infoq.com/news/2011/04/Azure-AppFabric-Caching – normalian Mar 08 '12 at 05:17
  • @GlennFerrieLive - The instances are not the issue, its the number of requests to the AppFabric Cache. I use AzureWatch to spin up or down. – Adam Mar 08 '12 at 05:22
  • @normalian - I know the difference, that isn't the question though. – Adam Mar 08 '12 at 05:23
  • gotcha... I see where you're going with this... – Glenn Ferrie Mar 08 '12 at 05:25
  • May be of interest: http://msdn.microsoft.com/en-us/magazine/hh708748.aspx – RichBower Mar 08 '12 at 11:17
  • Thanks @RichBower - post it as an answer and I will accept it :) – Adam Mar 08 '12 at 11:28

5 Answers5

2

Are you using cache to provide SessionState storage, or general data storage by your application, or both? It's not totally clear, because InProc usually refers to SessionState, but your sample code does not look like SessionState.

Assuming that you're storing data which can be safely cached locally, then I would recommend looking into AppFabric Local Caching. It does basically what you want, and doesn't require writing any separate code (I think...).

Otherwise, using MemoryCache as you outlined is a workable scheme. I've done this in my apps, you just need to be careful to avoid cache incoherence issues.

Depending on your application, you may also want to implement a per-request cache by storing data in the HttpContext.Items collection. This is helpful when different parts of your code might request the same data during a single request.

Brian Reischl
  • 7,216
  • 2
  • 35
  • 46
  • 1
    Using local cache requires no changes to the way you access the cache, just how you initialise it. If you're reading from your config, it's just a setting (http://msdn.microsoft.com/en-us/library/ee790816.aspx) or it's part of the DataCacheFactoryConfiguration if you're doing it in code (http://msdn.microsoft.com/en-us/library/microsoft.applicationserver.caching.datacachefactoryconfiguration.localcacheproperties(v=ws.10).aspx) – knightpfhor Mar 08 '12 at 20:18
  • Thanks for the response @breischl, you are correct in that I am using SessionState and general data storage for my application. I am only trying to do the local cache for general data storage at the moment. It was quite easy to implement as I had all my caching going through 1 class, I did this after the effort I went through upgrading my local cache to AppFabric the first time :) – Adam Mar 09 '12 at 07:04
  • thanks for the comment @knightpfhor, I chose to do MemoryCache anyway as I didn't want to mess around with all the cache which deals with Sessionstate as well. I don't want session state being stored InProc. Thanks for the links, certainly worth knowing. – Adam Mar 09 '12 at 07:07
1

One thing I have done is use HttpContext.Items. This is only a per request cache but depending on the nature of your system can be useful.

Craig
  • 36,306
  • 34
  • 114
  • 197
  • Thanks Craig. I have quite a few items that are cached for all users, not so much individual sessions. – Adam Mar 08 '12 at 05:56
1

Try this: http://msdn.microsoft.com/en-us/magazine/hh708748.aspx

RichBower
  • 204
  • 1
  • 2
  • 7
  • Thanks @RichBower this just confirmed that I could use InProc caching with AppFabric. And it is working out quite well. It does reduce hits to AppFabric under heavy load. – Adam Mar 09 '12 at 06:59
1

I wouldn't suggest inproc, due to the fact there's no server affinity.

One option, with With Windows Azure Cache, to avoid the hourly quota throttling is to bump up cache size. Fortunately the price doesn't scale linearly. For instance: $45 for 128MB, $55 for 256MB. So one option is to bump up your Cache to the next size. You'll need to monitor Compute performance though, via perf counters, as there's no way to monitor cache usage realtime.

Another option is to move session state to SQL Azure, which is now an officially-supported session state provider as of Azure 1.4 (Aug. 2011 - see this article for more info). With the latest SQL Azure pricing updates, if the db stays below 100MB, it's a $4.99 monthly rate instead of the original $9.99 baseline. It's amortized daily, so even if you have transient spikes and go into 1+GB range, you still have quite an affordable cache repository.

David Makogon
  • 69,407
  • 21
  • 141
  • 189
  • Thanks David. I am mainly using cache for items from the DB and not session state (though of course I do use some for session state as well). I have kept the session state on AppFabric yet done MemoryCache (inproc) for cached DB items. Which does rapidly reduce the hits to AppFabric under heavy load. I will however have to take your suggestion to upgrade to the next level once traffic further increases. – Adam Mar 09 '12 at 06:58
1

Another possible solution would be to use Sticky Sessions like this example:

http://dunnry.com/blog/2010/10/14/StickyHTTPSessionRoutingInWindowsAzure.aspx

Tom
  • 1,611
  • 10
  • 11