Efficient graph generation using the built-in cache subsystem

The full explanation of how to use the JpGraph cache system is deferred to Chapter 9. Using the JpGraph cache system so this early section is just to explain the principles and why you probably want to read through the full chapter later on.

The core problem is that generating images can require a lot of CPU time. If we combine this with the interpreted nature of PHP we can get a potential lethal performance mixture. For example, if a web page uses one dynamically generated graph and at its peak the site has 50 hits per second this means that the PHP graph script also has to be called 50 times a second. On a high end server a typical graph takes in the range of 0.02s up to 0.2s (and some complex graph, for example an anti-aliased Contour-plot, can take up to 1s) to generate using a plain non-accelerated installation (see more on supported PHP Accelerators in Chapter 11. NuSphere PHP accelerator).

If we furthermore makes the realistic assumption that the site needs to run some database services and generate other content as well the graph script itself might not be allowed to use more than 50% of the available CPU bandwidth. It is now easy to see that we are in trouble.

Continuing with the example. Assuming our graph is medium complex and takes a whole 0.04s to generate. This means that if the server does not do anything more than just creating images then we can crank out 1/0.04 or 25 graphs per second per core at maximum. If we then take the 50% load into account it means that we could only be allowed to generate ~12 graphs per second per core and remember that this was on a high end server. If we now have more than 12 hits per second or have a more average server with a less powerful CPU we are heading directly for a seriously under dimensioned server.

If we assume we are running our server on a dual-core CPU this gives us an upper practical limit of 24 graphs per second per server.

There are a couple of ways to counteract this problem but none is a 100% solution.

  1. Introduce load balancing among several servers. This is a common way to dynamically adjust to varying loads but without some serious investments into a server farm it is still possible to overload the system.

  2. Reduce the complexity of the graphs. However there is still a limit, even very simple and basic graphs takes in the order of 0.02s on a high end server due partly to the cost PHP parsing of all the library files. This means that the upper limit is still valid.

  3. Make use of a PHP accelerator. If you are running a professional server this is a must. We would go so far as to say that running a professional PHP server without using any of the available PHP accelerators borders on gross misconduct on the behalf of the information architect that did the logical server design. Using a PHP accelerator we can normally expect to get an almost 100% improvement. Taking the previous example as a case we can probably expect an upper limit of ~24 graphs per second per core instead of the normal ~12.

  4. Make use of the built in cache system in JpGraph. This system if set up correctly will avoid the problem by not having to generate the same (or almost the same) image over and over again. The core idea of the system is the observation that the majority of the data presented on a WEB page is changing only very slowly compared with the hits a server gets.

    For example, if a server has a graphical overview of defects by showing inflow/outflow there is probably a good case to state that the data change sufficiently slowly that it is probably not necessary to re-generate the graph more than 6 times per day (or perhaps even just once per day).

    The JpGraph cache system allows you to do just that. What you do is specify a timeout. When the server calls the graph script the script first checks if a previous image has been generated. If that is the case it then checks how old the image is and if it is newer than the timeout limit then the existing image is sent back. It is just in the case that there isn't already any image (the script has never been run) or that the existing image is too old (older than the specified timeout limit) that the image gets generated again.

    You could of course do all of this manually but the library has built in support for this that will allow you to use the system without changing a single line in your existing scripts. It is all taken care of in the background.

For a production server the recommended setup is to use a combination of load balancing, a suitable PHP accelerator and enabling the JpGraph cache system.