Use Write Caching to Optimize High Volume Data Driven Applications
page 6 of 11
by Steven Smith
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 63353/ 86

Storing Update Data in Memory

Actually, my next step was to set up two Hashtable collections, one for clicks and one for impressions, each holding an integer value keyed off of a date plus an advertisement ID key.  This would have worked, but since both sets of data are destined for the same database table, it would have required me to reconcile the two sets of counters prior to persisting to the database, or else required a lot of duplicate database calls.

So then, finally, I created an Activity class to hold the ID, date, impressions, and clicks, and then I created a 1400-line strongly-typed ActivityCollection class, which was basically a Hashtable with a strongly-typed String key and a strongly-typed Activity value.  At that point, whenever I needed to log an impression or click, it was just a matter of adding a new item to this collection (if I didn’t already have one) or incrementing the existing item’s counter. 

Incidentally, I’m not going to list the code for the collection, but I will tell you that I created it automatically using a built-in CodeSmith template (CodeSmith is free, so if you don’t have it already, get with the program and go download it now).

However, since this is meant to perform properly in a high-volume, multi-user environment, I had to consider multi-threaded access.  Specifically, I had to implement a locking system that ensured that two requests did not try to increment the exact same item at the same time (a simple example of what happens without locking can be found here). 

Now, we could take the naïve approach and simply lock the entire collection, but I know, I just know, that that will result in contention for that resource.  (I could do yet another test to show it, but at some point I have to actually implement this code and finish this article.)  I figured there had to be a way to do ‘row level’ locking of a Hashtable, and Google quickly spit one out.

Thanks to Ambrose Little and Brian Button for the final locking code shown in Figure 4.  For more on how to implement locks check out the MSDN documentation: C# Spec: The lock statement.

Figure 4: LogActivity – Showing Smart Hashtable locking

private static void LogActivity(int featuredItemId, ActivityType activityType)
{
 string index = featuredItemId + "-" + DateTime.Today.ToShortDateString();
 AspAlliance.Framework.Common.FeaturedItemActivity item = 
activityCollection[index];

if(item==null)
 {
  // only if it is not there do we lock, and then only the 
// syncroot, so that other threads can still access the Hashtable
  // to read/update other items.  Doing this will only block 
// threads wanting to add new items to the collection
  lock(activityCollection.SyncRoot)
  { 
   // once we get our lock, check again to ensure another thread 
// didn't get here first and add it while we were blocking
   item=activityCollection[index];
   if(item==null)
   {
    // still null, so we're definitely the first to try 
// to add it; create the item and add it.
    item = new 
AspAlliance.Framework.Common.FeaturedItemActivity(
featuredItemId, DateTime.Today, 0, 0);
    activityCollection.Add(index, item);
   }
  }
 }
 // now we can just lock the item and do our update 
// with only item-level locking.
 switch(activityType)
 {
  case ActivityType.Click : 
   lock (item) item.Clicks++;
   break;
  case ActivityType.Impression : 
   lock (item) item.Impressions++;
   break;
 }
}

Now that we have a reliable way to store the data on the web server in a high-performing manner, the second step is to figure out a way to write the data to the database.


View Entire Article

User Comments

Title: Modern SQL XML Support   
Name: Steve Smith
Date: 2008-08-08 2:33:41 PM
Comment:
Jason Follas posted recently on how to do the SQL XML work more efficiently in SQL 2005+:
http://jasonfollas.com/blog/archive/2008/06/19/coding-in-sql-server-an-evolution.aspx
Title: MSMQ   
Name: Derek
Date: 2008-01-14 9:37:07 AM
Comment:
Thanks for the article. Having some experience with MSMQ I can tell you it will probably perform well, but we've had a lot of issues with using it in a clustered environment. This is a well-known shortcoming of MSMQ.

We've gone to some 3rd party pub-sub solutions that work much more efficiently and work well in a clustered environment.
Title: Using a synchronized HashTable   
Name: Tim
Date: 2005-08-22 1:41:25 PM
Comment:
Also, how would this be affected by using Hashtable.Synchronized(...) to create the hashtable. It appears that automatically protects the hashtable's Add method and the indexing property Set accessor with a lock, which would protect you during writes.
Title: What about the code for updating the item in Cache?   
Name: Tim
Date: 2005-08-22 12:08:14 PM
Comment:
Can you show sample code for updating the item in Cache? For example, if item is added to cache with certain expiration, etc., when you update it, do you have to add it back with the same parameters, or do you just reference it like Cache[myitem] = updatedValue, and it will retain all previously set values...

Thanks
Title: Programmer   
Name: Microfolx
Date: 2005-05-21 10:33:19 AM
Comment:
This is a very nice site. Keep it up.
Title: Re: Consistency   
Name: Brett
Date: 2005-05-20 5:15:54 PM
Comment:
Nice article... I might consider trying normal XML writers rather than StringBuilder. Or even XML serialization. Probably slightly slower, but reduces errors.

On the point regarding charging for page views. I have two suggestions. One is to periodically reload the current click count from the database and not worry about being exact. Hey if they get 1 million or 1,005,000, does it really matter? This isn't the space shuttle. The second would be to switch to a non-caching code path when you get close to whatever your maximum value is. So when you hit, say 990,000 views (based on your hit rate, etc.) then switch to the non-caching version for that customer.
Title: Consistency   
Name: Brian
Date: 2005-05-20 2:03:29 PM
Comment:
I had to accomplish this exact same scenario. The problem I ran into was the caching. Lets say that one of your advertisers pays you to show their ad 1 million times. How can you insure that it doesn’t go over? If you are holding the most current counters in cache, won’t each process be looking at their own cache, not to mention each server in the web farm and all it’s processes be looking at their own cache.

Another general Cache question. When I write something to cache, isn’t it only available for that particular process? So if you setup your application to have 5 worker processes, won’t that have 5 separate cache entries?
Title: web farm   
Name: parker
Date: 2005-04-24 3:19:08 AM
Comment:
How do you account for disperate sessions in a web farm scenario? Is the cache shared amoung the servers?
Title: Too Good   
Name: Zulfiqar Damani
Date: 2005-04-18 12:46:36 AM
Comment:
It presented very well, also it was interesting too.
Title: Thanks   
Name: Happel
Date: 2005-04-14 8:23:23 AM
Comment:
Thanks for sharing this article, very interesting.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 12:59:10 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search