Hi there. The homepage of one of our sites has roughly 60 images, all of which call ImageGen passing in Width/Height params. Unfortunately this results in a split second CPU spike of roughly 20% (on our dev server) for the IIS worker process running ImageGen (it's running in its own worker process, so it's definately ImageGen causing the load).
The images are mostly static, i.e. they've been generated in ImageGen previously and 'cached' but this spike still occurs.
Is there potentially something I'm missing that could be causing this? Is ImageGen not designed to be used for this many images?
ImageGen should work perfectly in this situation and there are sites with vastly more images being processed. I wonder, do you have the &nocache=true parameter set? You shouldn't except perhaps for some testing.
What happens is the 60 images on your homepage will make 60 requests to imagegen.ashx. ImageGen will resize each according to your height/width and other parameters. Those resized images will be saved to the server's drive, the index.xml file(s) will be updated, and the resized images will be sent to the website visitor. Resizing can be a cpu and memory intensive task, especially if the original images are very large. But it only happens once for each unique set of height/width and other parameters.
Once ImageGen's cache is primed, any future requests will find the cached file, update the associated index.xml file, and send the already-cached image to the website visitor. This is less cpu-intensive but like all website activity opening 60 http requests and sending the data down the pipe may be a load on the server for a moment, depending on the server's robustness. ImageGen is adding very little to this overhead than if you'd requested the images from the filesystem directly, but 60 nearly simultaneous requests for each website visitor can add up even for static resources.
Or, if the website visitor has already downloaded the images from a previous visit to the site, ImageGen will respond with a 304 Not Modified response to the requests and bandwidth will be reduced to nearly zero for each request. Apart from the momentary burst of 60 requests and 60 304 responses.
Finally, if you are using ImageGen Professional, you can set a CachingTimeSpan value for a class of images and the visitor's browser won't even request the image again from your server for that time period, totally eliminating the 60 requests and 304 responses once the visitor gets the images initially. No activity on the server means zero load on the server. You can always try the ImageGen Professional features by running on localhost or any *.local domain before purchasing a key for your live domain.
I hope this explanation helps, and do be sure you're not using the &nocache=true parameter as that will force ImageGen to recreate the image (ignoring any previously-cached images) with every request.
Definately don't have a &nocache=true parameter set
I changed the URL paths from ImageGen.ashx to the direct generated cache image and there was no CPU movement so it wasn't the server / bandwidth.
After a little more investigation a handful of URL's had the image path and Contrain=True and nothing else. After looking into the index.xml file all the cached images had height/width values so I assume it wasn't caching those images (with just Constain=True) but still serving them. Adding heights/widths to those calls dropped the CPU hit by about half, down to roughly 10% with 40 images. Still this seems high.
FYI, it's ImageGenPro version 2.5.7.27945
Also, if I add MaxHeight and MaxWidth to the request they don't seem to be stored in the index.xml. In fact, adding MaxHeight or MaxWidth doesn't seem to do anything. I know ImageGenPro is working because if I add Class=X it renders the class settings. Is it not valid to simply have MaxHeight and/or MaxWidth ?
(I've been very sick and out of the office for many days, sorry for the slow response)
Thanks for the info, that's helpful.
The index.xml file will always have every key parameter in it, not only those you specify. That way, if you request a different set of parameters but the result would be the same image ImageGen doesn't need to re-create an already-existing image. Constrain and maxWidth and maxHeight aren't part of the index.xml since they don't define the resulting image (an image with maxWidth=50 will produce an image with a width of 50, and the resulting width is saved in the index.xml... but you could get the same result by requesting the image with width=50, for instance, amongst other potential combinations of parameters).
An image that doesn't need any process is sent to the visitor directly and isn't resized or cached.
I wonder if there's some poorly performing code in some of these routines to determine the resulting parameters, or possibly in opening files if they aren't being resized and therefore aren't cached. It's worth a look.
One thought I had was looking up the cached image path myself (parsing index.xml) and caching that path in my application, saving it from hitting ImageGen for each image request. Is there any API within ImageGen that'll allow this? If I use ImageGen.ImageGenQueryStringParser.ImageGen ?
I'm seeing similar load problems, although not yet worked out if there's a similar cause - we've just sent an email marketing campaign out, and the affected site is now serving ~20-40 concurrent ImageGen requests, and melting down with >95% CPU load.
We are using ImageGen Pro in our ASP.Net appllication hosted in our server with 16GB memory and 2 Quadcore Xeon processors at 2.5GHz. Our site has to render between 60 - 80 images per minute. Average size of the images is 110KB. We are using the bellow classes, and still we get high usage of the resources. Sometimes it goes as far as 100% of the CPU. Is there a way to improve this situation please.
I ended up wrting a very basic method (well, few methods) that would look at the ImageGen XML files and cache the physical image paths of the generated ImageGen images so image requests aren't constantly hitting ImageGen.ashx. They're customised for our needs but you can probably modify them for yours. Essentially, every image request calls RenderImageGenUrl and from there it calls another method (GetDirectImageUrl) to check the cache and then (if neccesary) another method to lookup the XML file (RetrieveGeneratedImageUrl).
if (String.IsNullOrEmpty(imageGenUrl)) throw new NullReferenceException("AppSettings missing setting 'ImageGenUrl'"); if (!imageGenUrl.Contains("?")) imageGenUrl = String.Concat(imageGenUrl, "?");
if (String.IsNullOrEmpty(settings.ImageUrl)) { return String.Empty; }
// add the image relativeImageUrl = settings.ImageUrl.Replace( String.Concat("http://", new Uri(imageGenUrl).Host), String.Empty ); imageGenUrl = String.Concat( imageGenUrl, "Image=", System.Web.HttpUtility.UrlEncode(relativeImageUrl) );
public string RetrieveGeneratedImageUrl(ImageGenSettingsEntity imageGenSettings, string relativeImageUrl) { _logger.Debug("RetrieveGeneratedImageUrl");
if (String.IsNullOrEmpty(relativeImageUrl)) return null;
decimal ratio; int resizedHeight, resizedWidth;
var isExternalUrl = (relativeImageUrl.StartsWith("http://") || relativeImageUrl.StartsWith("https://")); var requestedUri = OperationContext.Current.Channel.LocalAddress.Uri; var uri = isExternalUrl ? new Uri(relativeImageUrl) : requestedUri; var dns = String.Concat( requestedUri.Scheme, "://", requestedUri.Host );
if (requestedUri.Port > 0 && requestedUri.Port > 80) { dns = String.Concat(dns, ":", requestedUri.Port); }
if (!isExternalUrl) // an image residing within the asset service directory structure { if (!relativeImageUrl.StartsWith("~/") && !relativeImageUrl.StartsWith("/")) { relativeImageUrl = String.Concat("~/", relativeImageUrl); } else if (!relativeImageUrl.StartsWith("~/")) { relativeImageUrl = String.Concat("~", relativeImageUrl); } }
// not in cache, attempt to retrieve from the ImageGen XML cache file var filename = isExternalUrl ? relativeImageUrl : Path.GetFileName(relativeImageUrl); var xmlCacheFile = isExternalUrl ? HostingEnvironment.MapPath(String.Format("~/data/Cached/{0}/index.xml", uri.Host)) : String.Concat( Path.GetDirectoryName(HostingEnvironment.MapPath(relativeImageUrl)), "\\Cached\\index.xml" );
_logger.Debug("Looking for XML file at '{0}'", xmlCacheFile);
if (!File.Exists(xmlCacheFile)) return null;
_logger.Debug("Found the XML file");
var xmlSerializer = new XmlSerializer(typeof(ImageGenCacheIndexEntity));
using (var reader = new StreamReader(xmlCacheFile)) { // deserialize the XML into an object var imageGenCachedIndex = (ImageGenCacheIndexEntity)xmlSerializer.Deserialize(reader);
if (imageGenCachedIndex != null) { // find an image which matches the criteria var originalImage = isExternalUrl ? imageGenCachedIndex.Images .FirstOrDefault(i => i.ImageUrl == filename) : imageGenCachedIndex.Images .FirstOrDefault(i => i.OriginalFileName == filename);
Thank you John for the code. But then there is an issue with ImageGen, I have checked the index.xml about the cahche images being accessed, the information looks correct most of the times, but when I check the file system monitor the file never gets accessed or read from the hard disk. I think the caching is not working properly as the cached images are not being retireved properly. I hope the developer looks into this.
CPU Load
Hi there. The homepage of one of our sites has roughly 60 images, all of which call ImageGen passing in Width/Height params. Unfortunately this results in a split second CPU spike of roughly 20% (on our dev server) for the IIS worker process running ImageGen (it's running in its own worker process, so it's definately ImageGen causing the load).
The images are mostly static, i.e. they've been generated in ImageGen previously and 'cached' but this spike still occurs.
Is there potentially something I'm missing that could be causing this? Is ImageGen not designed to be used for this many images?
Cheers
Hi, John,
ImageGen should work perfectly in this situation and there are sites with vastly more images being processed. I wonder, do you have the &nocache=true parameter set? You shouldn't except perhaps for some testing.
What happens is the 60 images on your homepage will make 60 requests to imagegen.ashx. ImageGen will resize each according to your height/width and other parameters. Those resized images will be saved to the server's drive, the index.xml file(s) will be updated, and the resized images will be sent to the website visitor. Resizing can be a cpu and memory intensive task, especially if the original images are very large. But it only happens once for each unique set of height/width and other parameters.
Once ImageGen's cache is primed, any future requests will find the cached file, update the associated index.xml file, and send the already-cached image to the website visitor. This is less cpu-intensive but like all website activity opening 60 http requests and sending the data down the pipe may be a load on the server for a moment, depending on the server's robustness. ImageGen is adding very little to this overhead than if you'd requested the images from the filesystem directly, but 60 nearly simultaneous requests for each website visitor can add up even for static resources.
Or, if the website visitor has already downloaded the images from a previous visit to the site, ImageGen will respond with a 304 Not Modified response to the requests and bandwidth will be reduced to nearly zero for each request. Apart from the momentary burst of 60 requests and 60 304 responses.
Finally, if you are using ImageGen Professional, you can set a CachingTimeSpan value for a class of images and the visitor's browser won't even request the image again from your server for that time period, totally eliminating the 60 requests and 304 responses once the visitor gets the images initially. No activity on the server means zero load on the server. You can always try the ImageGen Professional features by running on localhost or any *.local domain before purchasing a key for your live domain.
I hope this explanation helps, and do be sure you're not using the &nocache=true parameter as that will force ImageGen to recreate the image (ignoring any previously-cached images) with every request.
cheers,
doug.
Hi Doug,
Definately don't have a &nocache=true parameter set
I changed the URL paths from ImageGen.ashx to the direct generated cache image and there was no CPU movement so it wasn't the server / bandwidth.
After a little more investigation a handful of URL's had the image path and Contrain=True and nothing else. After looking into the index.xml file all the cached images had height/width values so I assume it wasn't caching those images (with just Constain=True) but still serving them. Adding heights/widths to those calls dropped the CPU hit by about half, down to roughly 10% with 40 images. Still this seems high.
FYI, it's ImageGenPro version 2.5.7.27945
Also, if I add MaxHeight and MaxWidth to the request they don't seem to be stored in the index.xml. In fact, adding MaxHeight or MaxWidth doesn't seem to do anything. I know ImageGenPro is working because if I add Class=X it renders the class settings. Is it not valid to simply have MaxHeight and/or MaxWidth ?
Hi, John,
(I've been very sick and out of the office for many days, sorry for the slow response)
Thanks for the info, that's helpful.
The index.xml file will always have every key parameter in it, not only those you specify. That way, if you request a different set of parameters but the result would be the same image ImageGen doesn't need to re-create an already-existing image. Constrain and maxWidth and maxHeight aren't part of the index.xml since they don't define the resulting image (an image with maxWidth=50 will produce an image with a width of 50, and the resulting width is saved in the index.xml... but you could get the same result by requesting the image with width=50, for instance, amongst other potential combinations of parameters).
An image that doesn't need any process is sent to the visitor directly and isn't resized or cached.
I wonder if there's some poorly performing code in some of these routines to determine the resulting parameters, or possibly in opening files if they aren't being resized and therefore aren't cached. It's worth a look.
cheers,
doug.
No problem Doug, understandable.
One thought I had was looking up the cached image path myself (parsing index.xml) and caching that path in my application, saving it from hitting ImageGen for each image request. Is there any API within ImageGen that'll allow this? If I use ImageGen.ImageGenQueryStringParser.ImageGen ?
Cheers, feel better.
I'm seeing similar load problems, although not yet worked out if there's a similar cause - we've just sent an email marketing campaign out, and the affected site is now serving ~20-40 concurrent ImageGen requests, and melting down with >95% CPU load.
We are using ImageGen Pro in our ASP.Net appllication hosted in our server with 16GB memory and 2 Quadcore Xeon processors at 2.5GHz. Our site has to render between 60 - 80 images per minute. Average size of the images is 110KB. We are using the bellow classes, and still we get high usage of the resources. Sometimes it goes as far as 100% of the CPU. Is there a way to improve this situation please.
Hi Byron,
I ended up wrting a very basic method (well, few methods) that would look at the ImageGen XML files and cache the physical image paths of the generated ImageGen images so image requests aren't constantly hitting ImageGen.ashx. They're customised for our needs but you can probably modify them for yours. Essentially, every image request calls RenderImageGenUrl and from there it calls another method (GetDirectImageUrl) to check the cache and then (if neccesary) another method to lookup the XML file (RetrieveGeneratedImageUrl).
Thank you John for the code. But then there is an issue with ImageGen, I have checked the index.xml about the cahche images being accessed, the information looks correct most of the times, but when I check the file system monitor the file never gets accessed or read from the hard disk. I think the caching is not working properly as the cached images are not being retireved properly. I hope the developer looks into this.
We ended up setting up a reverse proxy of our own (Squid) to cache the ImageGen output
is working on a reply...