A while ago I updated my exchange rate sites (Dollars2Pounds et al) to use the "new" ASP.NET Chart control, after some initial testing every thing appeared to be going well and the live websites were updated with the chart control.
Shortly after deploying the servers event log filled up with messages along these lines:
Event code: 3005
Event message: An unhandled exception has occurred.
Event time: 5/19/2009 1:17:59 AM
Event time (UTC): 5/19/2009 12:17:59 AM
Exception type: ArgumentException
Exception message: The image is not found.
Request URL: http://www.yuan2dollars.com/ChartImg.axd?i=chart_6_6.png&g=e036ff271be14badb39473c8d04f8609
Request path: /ChartImg.axd
T Stack trace: at System.Web.UI.DataVisualization.Charting.ChartHttpHandler.ProcessSavedChartImage(HttpContext context)
at System.Web.UI.DataVisualization.Charting.ChartHttpHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext context)
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
I've been trying to get to the root cause for some time concerned that visitors to the websites were seeing blank images and I followed various suggestions based on image cache lifetime, temp folder permissions, phase of the moon and so on.
It wasn't until just recently when I followed Scott Hanselman's top tip of implementing elmah that the real cause of the problem became obvious.
It's Google causing all the exceptions! Well googlebot and other search engines.
Their right in front of me under the ALL_RAW heading of the server variables was the answer "Connection: Keep-alive Accept: / Accept-Encoding: gzip,deflate From: googlebot(at)googlebot.com"
I should have guessed that!
What happens is googlebot request the page, so the charting control creates the image and renders a image tag for it, caching the image for a predefined period of time. Naturally googlebot does what it does best, it saves that link to the image and tries to re-index it time and time again at a much latter date (weeks), by the time googlebot comes back for the image a second time the cache has long since been updated and naturally the image no longer exists and the naming convention of the image means that it's not going to get the replacement.
Recently I also ran some performance test with the charts in place using LoadImpact, they provide some limited and basic performance testing for free, but its more than enough for simple sites like mine to see that I had serious performance issues on my sites when more than a couple of visitors were hitting the site at the same time.
The charts on each pages were taking about one second to render (it's not surprising as I'm trying to render something like 26,000 data points for the 3 month USD/GBP chart and 7,000 for the other 3 month charts on a 2.4GHz P4). With the CPU fully pegged for a second trying to produce those charts it doesn't take long before the delay hits in if more than a couple of users access the page at the same time.
My fix for this has been fairly simple, the charts are now updated in the background by a cache expired event and are written to a static .png file with a fixed name. The charts are stored in a Charts folder and existing files are replaced with fresh images, the page is rendered with a normal img tag so when googlebot visits it can get the latest chart using the correct name and page rendering now happens in about 6ms.
Interestingly this performance fix has also seen a 10% increase in traffic.
- Watch your servers event logs.
- Implement ELMAH, it's crazy simple and very useful.
- Take advantage of the free load testing from LoadImpact, even if you only try it the once.
- If you are running IIS/Server 2k3/2k8 have Perfmon run in the background as you run the Load Impact tests and look at:
- CPU usage
- Error Events Raised
- Requests Current
- Requests Queued
- Request Execution Time
- and others that might be relevant.
- In perfmon save the setup somewhere easy to get to (i.e. the desktop) so you can just double click it to get your perfmon setup back quickly