Performance Tuning your Joomla website

Torbjorn Zetterlund ThunderBear
0

The majority of performance complaints are the result of underpowered and improperly configured servers. Our  opinion is that this is the same situation with Joomla sites.  While hosted virtual servers allow little tuning, there is no reason why a dedicated server cannot be properly tuned for high performance.

Apache

The single biggest hardware issue affecting webserver performance is RAM. A webserver should never ever have to swap, as swapping increases the latency of each request beyond a point that users consider “fast enough”. You can, and should, control the  MaxClients  setting so that your server does not spawn so many children it starts swapping. This procedure for doing this is simple: determine the size of your average Apache process, by looking at your process list via a tool such as  top, and divide this into your total available memory, leaving some room for other processes.

Beyond that the rest is mundane: get a fast enough CPU, a fast enough network card, and fast enough disks, where “fast enough” is something that needs to be determined by experimentation.

Operating system choice is largely a matter of local concerns. But some guidelines that have proven generally useful are:

  • Run the latest stable release and patchlevel of the operating system that you choose. Many OS suppliers have introduced significant performance improvements to their TCP stacks and thread libraries in recent years.
  • If your OS supports a  sendfile(2)  system call, make sure you install the release and/or patches needed to enable it. (With Linux, for example, this means using Linux 2.4 or later. On systems where it is available,  sendfile  enables Apache 2 to deliver static content faster and with lower CPU utilization.
Apache is configured using the httpd.conf file. The following parameters are particularly important in configuring child processes
  • MaxClients –  256 – The maximum number of child processes to create. The default means that up to 256 HTTP requests can be handled concurrently. Any further connection requests are queued.
  • StartServers – 5 –  The number of child processes to create on startup.
  • MinSpareServers –  5 -The number of idle child processes that should be created. If the number of idle child processes falls to less than this number, 1 child is created initially, then 2 after another second, then 4 after another second, and so forth till 32 children are created per second.
  • MaxSpareServers –  10 –  If more than this number of child processes are alive, then these extra processes will be terminated.
  • MaxRequestsPerChild –  0 –  Sets the number of HTTP requests a child can handle before terminating. Setting to 0 means never terminate. Set this to a value to between 100 to 10000 if you suspect memory leaks are occurring, or to free under-utilized resources.
For large sites, values close to the following might be better:
 
MinSpareServers 32
MaxSpareServers 64
 
Other useful performance parameters you can change include:
 
SendBufferSize –  Set to OS default –  Determines the size of the output buffer (in bytes) used in TCP/IP connections. This is primarily useful for congested or slow networks when packets need to be buffered; you then set this parameter close to the size of the largest file normally downloaded. One TCP/IP buffer will be created per client connection.
 
KeepAlive [on|off] –  On –  In the original HTTP specification, every HTTP request had to establish a separate connection to the server. To reduce the overhead of frequent connects, the keep-alive header was developed. Keep-alives tells the server to reuse the same socket connection for multiple HTTP requests.  If a separate dedicated web server serves all images, you can disable this option. This technique can substantially improve resource utilization.
 
KeepAliveTimeout –  15 –  The number of seconds to keep the socket connection alive. This time includes the generation of content by the server and acknowledgements by the client. If the client does not respond in time, it must make a new connection.  This value should be kept low as the socket will be idle for extended periods otherwise.
 
MaxKeepAliveRequests –  100 –  Socket connections will be terminated when the number of requests set by MaxKeepAliveRequests is reached. Keep this to a high value below MaxClients or ThreadsPerChild.
 
TimeOut –  300 –  Disconnect when idle time exceeds this value. You can set this value lower if your clients have low latencies.
 
LimitRequestBody –  0 –  Maximum size of a PUT or POST. O means there is no limit.
 
 
If you do not require DNS lookups and you are not using the htaccess file to configure Apache settings for individual directories you can set:
 
# disable DNS lookups: PHP scripts only get the IP address
 
HostnameLookups off
 
# disable htaccess checks
 
<Directory />
 
AllowOverride none
 
</Directory>
 
If you are not worried about the directory security when accessing symbolic links, turn on FollowSymLinks and turn off SymLinksIfOwnerMatch to prevent additional lstat() system calls from being made:
 
Options FollowSymLinks
 
#Options SymLinksIfOwnerMatch
 
You can find more details about apache tuning on the apache website.  http://httpd.apache.org/docs/2.0/misc/perf-tuning.html

MySQL

One of the main performance bottlenecks for any Joomla or content management system is the database server.  The majority of Joomla performance complaints are the result of underpowered and improperly configured MySQL server.  While hosted virtual servers allow little tuning, there is no reason why a dedicated server cannot be properly tuned for high performance.

On a dedicated server you would need to play around with your my.cnf file located at /etc/my.cnf on a Red Hat installation.  

One of the most tricky parts is to estimate memory consumption by MySQL Server for Joomla is to understand the different components, modules and plugins that you would be using. How database heavy are these Joomla  add ons, how many database  quires  are used, how many tables are required etc. To figure out what  formula that could be used, is a big question. It is  important  to get this right,  If you configure MySQL Server so it uses too small amount of memory it will likey perform suboptimally. If you however configure it so it consumes too much memory it may be crashing , failing to execute queries or make operation to swap seriously slowing down. On now legacy 32bit platforms you could also run out of address space so that had to be watched as well.  
 
To find the  optimal  fomula to compute your possible memory usage is very complex nowadays and what is even more important “theoretically possible” maximum it provides have nothing to do with real memory consumptions. In fact typical server with 8GB of memory will often run with maximum theoretical memory usage of 100GB or more. Furthermore there is no easy “overcommit factor” you can use – it really depends on application and configuration. Some applications will drive server to 10% of theoretical memory consumptions others only to 1%.  
 
First take a look at global buffers which are allocated at start and always where – these are key_buffer_size, innodb_buffer_pool_size, innodb_additional_memory_pool_size, innodb_log_buffer_size, query_cache_size. If you’re using MyISAM seriously you can also add the size of Operation System cache you would like MySQL to use for your table. Take this number add to it number of memory Operation System and other applications need, add might be 32MB more for MySQL Server code and various small static buffers. This is memory which you can consider used when you just start MySQL Server. The rest of memory is available for connections. For exampe with 8GB server you might have everything listed adding up to 6GB, so you have 2GB left for your threads.
 
Each thread connecting to MySQL server will needs its own buffers. About 256K is allocated at once even if thread is idle – they are used by default thread stack, net buffer etc. If transaction is started some more space can add up. Running small queries might only barely increase memory consumption for given thread, however if table will perform complex operations such as full table scans, sorts, or need temporary tables as much as  read_buffer_size, sort_buffer_size, read_rnd_buffer_size, tmp_table_size  of memory might be allocated. But they are only allocated upon the need and freed once given stage of query is done. Some of them are allocated as single chunk at once others, for example  tmp_table_size  is rather maximum amount of memory MySQL will allocate for this operation. Note it is more complicated than once may think – multiple buffers of the same type might be allocated for exampe to handle subqueries. For some special queries memory usage might be even larger – bulk inserts may allocate  bulk_insert_buffer_sizebytes of memory if done to MyISAM tables.  myisam_sort_buffer_size  used for  ALTER TABLE, OPTIMIZE TABLE, REPAIR TABLE commands.
 
style=”color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; “>Another approach you may take is to come up with amount of memory you want MySQL Server to consume at peak. This can be easily computed by memory needed for OS, File Cache and for Joomla. For 32bit envinronment you also should keep 32bit limits into account and probably limit “mysqld” size to about 2.5GB (exact number depens on a lot of factors). Now you can use “ps aux” to see VSZ – Virtual Memory allocated by MySQL process. You can also look at “Resident Memory” but I find it less helpful as it may down because of swapping – not what you would like to see. Monitor how the value changes so you know memory requirements with current settings and increase/decrease values appropriately.

 

List of rarely considered MySQL Server Memory Requirements

 

  • Thread buffers can be allocated more than once for each thread. Consider for example subqueries – each layer may need its own read_buffer,sort_buffer, tmp_table_size etc
  • Many variabes can be set per connection. So you can’t relay on global values if developers may use their local values to run some queries.
  • There can be mutiple key caches.  Multiple key caches can be created to accomodate query executions
  • Query Parsing and optimization needs memory.  This is usually small to be ignored but certain queries can have very large memory requrement for this step, especially specially crafted ones.
  • Stored Procedures.  Compex stored procedures may require a lot of memory
  • Innodb Table Cache.  Innodb has its own table cache in which meta data about each table accessed from the start is stored. It is never purged and may be large if you have a lot of tables. It also means user having  CREATE TABLE  privilege should be able to run MySQL server out of memory
  • MyISAM buffers.  MyISAM may allocate buffer which is large enough to contain largest record in the given table which is held until table is closed.
  • Federated Storage Engine.  This may have unbound memory requirements retriving result sets from remove queries.
  • Blobs may require 3x time of memory.  This is important if you’re deaing with large Blobs (your  max_allowed_packet  is large) Processing of 256MB of blob may require 768MB of memory.
  • Storage Engines.  In general storage engines may have their own per thread or global memory allocations which are not tuned as buffers. Watch for these especially now with many storage engines being released for MySQL by various parties.

The main point is – there are a lot of memory consumers out where and trying to find peak possible usage for each is impractical – so measure what you get in practice and how memory consumption reacts to changing various variables. For example you may find out increasing  sort_buffer_size  from 1MB to 4MB and 1000  max_connections  increases peak memory consumption just 30MB not 3000MB as you might have counte I want to add about InnoDB memory. InnoDB allocates additional memory for internal needs (adaptive hash index, etc) which you should take into account. My investigations show it is about  innodb_buffer_pool_size / 20 + ~20MB d.

Here is an example – You could have such server running with max_connections=1000 and myisam_sort_buffer_size=256M.  If it happens so all connections will start to repair tables at the same time it will need 1000*256MB = 256GB of memory.  In practice however you would not have more than 2-3 connections doing it at the same time so you happen to be fine.

Here is our my.cnf for the findmore.ca website that uses Joomla. Our server is a 1GB dual  AuthenticAMD, AMD Athlon(tm) X2 Dual Core Processor BE-2350.  When we got our dedicated  server, the my.cnf only contain two lines. We have since tried different configuration and this is what we using today and it seems to work fine for know, have not had any crashes in the last while.

/etc/my.cnf

 

 

 

[mysqld]

set-variable=local-infile=0

datadir=/var/lib/mysql

socket=/var/lib/mysql/mysql.sock

user=mysql

#skip-locking

#skip-innodb

query_cache_limit=1M

query_cache_size=32M

query_cache_type=1

max_connections = 200

max_user_connections = 10000

max_connect_errors = 99999999

interactive_timeout=300

wait_timeout=60

connect_timeout=10

# * Fine Tuning

max_allowed_packet = 16M

thread_stack = 200K

thread_cache_size = 8

join_buffer_size = 2M

read_buffer_size = 4M

read_rnd_buffer_size = 16M

sort_buffer_size = 2M

myisam_sort_buffer_size = 128M

key_buffer = 150M

table_cache=512

join_buffer=1M

log_slow_queries = /var/log/mysql/mysql-slow.log

long_query_time = 2

log-queries-not-using-indexes

#log-bin

server-id=1

# Default to using old password format for compatibility with mysql 3.x

# clients (those using the mysqlclient10 compatibility package).

old_passwords=1

[mysqld_safe]

log-error=/var/log/mysqld.log

pid-file=/var/run/mysqld/mysqld.pid

 


Query caching was added as of MySQL version 4, the following three directives will greatly enhance mysql server performance.

query_cache_limit=1M
query_cache_size=32M
query_cache_type=1

Query caching is a server wide variable, so set these generous. We have found the above levels are generally best if you server has at least 512 ram. If you run a server just for DBs with a lot of ram, you can up these quite a bit, like 2m limit and a 64+M cache size.

The key buffer is a variable that is shared amongst all MySQL clients on the server. A large setting is recomended, particularly helpful with tables that have unique keys.

key_buffer=150M

The next set of buffers are at a per client level. It is important to play around with these and get them just right for your machine. With the setting below, every active mysql client will have close to 3 MB’s in buffers. So 100 clients = almost 300 MB. Giving too much to these buffers will be worse than giving too little. Nothing kills a server quite like memory swapping will.

sort_buffer_size=1M
read_buffer_size=1M
read_rnd_buffer_size=768K

The following directive should be set to 2X the number of processors in your machine for best performance.

thread_concurrency=2

Heres a few example configurations for servers running MySQL and web for common memory sizes. These are not perfect, but good starting points.

Server with 512MB RAM:

thread_cache_size=50
key_buffer=40M
table_cache=384
sort_buffer_size=768K
read_buffer_size=512K
read_rnd_buffer_size=512K
thread_concurrency=2

For servers with 1 GB ram:

thread_cache_size=80
key_buffer=150M
table_cache=512
sort_buffer_size=1M
read_buffer_size=1M
read_rnd_buffer_size=768K
thread_concurrency=2

 

PHP.ini

[MySQL]

mysql.allow_persistent = On ; allow or prevent persistent link
mysql.max_persistent = -1 ; maximum number of persistent links. -1 means no limit
mysql.max_links = -1 ; maximum number of links (persistent+non persistent). -1 means no limit
mysql.default_port = ; default port number for mysql_connect(). If unset,
; mysql_connect() will use the $MYSQL_TCP_PORT, or the mysql-tcp
; entry in /etc/services, or the compile-time defined MYSQL_PORT
; (in that order). Win32 will only look at MYSQL_PORT.
mysql.default_socket = ; default socket name for local MySQL connects. If empty, uses the built-in
; MySQL defaults
mysql.default_host = ; default host for mysql_connect() (doesn’t apply in safe mode)
mysql.default_user = ; default user for mysql_connect() (doesn’t apply in safe mode)
mysql.default_password = ; default password for mysql_connect() (doesn’t apply in safe mode)
; Note that this is generally a *bad* idea to store passwords
; in this file. *Any* user with PHP access can run
; ‘echo cfg_get_var(“mysql.default_password”)’ and reveal that
; password! And of course, any users with read access to this
; file will be able to reveal the password as well.

PHP

PHP is a very fast programming language, but there is more to optimizing PHP than just speed of code execution.Optimizing PHP involves many factors which are not code related, and why tuning PHP requires an understanding of how PHP performs in relation to all the other subsystems on your server.
 
The article  A HOWTO on Optimizing PHP  provides an insight to how to tune PHP to run faster.

Joomla

The are a number of things you can do with Joomla to tweak the performance.

Use Server Side Compression –  Joomla! support the server side compression protocol GZIP. If your server supports GZIP, enable this option in the Global Configuration Manager as it can result in some significant performance improvements. The GZIP Page Compression options are located on the Server tab in the Global Configuration Manager.

If You Don’t Use It, Disable It –  Disable all Components, Modules and Plugins that you are not using. Even if you are not displaying the output on the page, the system is likely doing at least some of the processing associated with the feature.

Minify Your CSS And JavaScript –  Minification is the process of reducing the size of CSS selectors and JavaScript by reducing unnecessary spaces and characters. While minifying a single selector saves only a small amount, it all adds up and minifying the entire CSS can result in a meaningful savings. This is a tedious manual process, so if you want to employ this technique I suggest you use one of the many tools designed to make this easier. Run a Google search for “minify CSS” and “minify JavaScript” for lists of options. TheJoomla! Extensions Directory also lists several Extensions that can compress your CSS and JavaScript.

Be Careful With Google Analytics –  Google Analytics, though a wonderful and useful service, can slow down your site. Every page that includes the Analytics code increases your load time as the Analytics script causes the system to wait while it contacts the Google servers. The impact of this varies greatly depending on the time of day, the traffic on your site and the location of your servers.

Be Selective About Your Template –  Your Template developer can have a significant impact on your site performance. Many of the lovely Templates I see in circulation rely heavily upon images to achieve their look and feel. The size of the Templates and the number of HTTP requests they generate are not optimal. Select carefully your Template. Look at the file size, and the quality of the code. You want to select Templates that use CSS, not tables, and those that prefer system text to image usage. Be particularly careful of Templates that use images for the menus, rather than system text and CSS. Not only do these Templates have a negative impact on site performance, but they also tend to be less than optimal from the perspective of both SEO and accessibility.

Be selective about  compression  –  CSS and javascript aggregation can decrease the http requests dramatically for those sites built with a lot of modules(Usually a lot of css and javascript files.)    GZip can compress css and javascript files a lot. The plugin only need to compress the css and javascript files once, so this can save a lot of CPU times, and give a repeat response.  example

Be Selective About Extensions –  Some third party Extensions are incredibly resource-intensive. When you are comparing Components, Modules or Plugins, use YSlow to compare the impact on your page performance and check resource usage on your server. Don’t forget that small differences in performance can balloon into big differences when the site experiences spikes in traffic.

Skip Live Stat Reporting –  Components or Modules that produce live real-time statistics on your site can be significant drains on site performance. If you don’t have a compelling need for real-time statistics, skip them.

Disable SEF URLs –  Though this may not be an option for many of you, if your goal is performance above all else, disable the SEF URLs option. The conversion of your native URLs into Aliases causes a performance hit.

Optimize Your Database –  One of the main performance bottlenecks for any content management system is the database server. To improve performance, you should periodically optimize the database tables. Optimization is performed from within phpMyAdmin.  

Optimising Mootools.js – On mootools.net you can download a customised mootools containing only the modules you need and it’s compressed using the YUI algortihm. As it turns out I didn’t need much more than the core and my Mootools size decresed from ~100k to less than 10k – more than a 90% size reduction!

Google Ajax Library –  one  great way to save bandwidth is to take advantage of Google’s AJAX Libraries API to serve your favorite open-source JavaScript libraries.  For a Joomla user, Joomla import mootools.js automatically.  Mootools.js is more than 70KB, How much bandwidth it will takes?

Plugin Google Ajax Library can host Mootools(70K),Prototype,JQuery,YUI libraries, which can save bandwidth and speed up your site’s response.Tips:This plugin is suitable for all joomla site. The Plugin Google Ajax Library will automatically replace your local ajax libraries with Google’s AJAX libraries. It will replace  /media/system/js/mootools.js  </span></span></strong></p>
<p><strong><span class=""Apple-style-span"”>with

http://ajax.googleapis.com/ajax/libs/mootools/1.11/mootools-yui-compressed.js</span></span></span></strong></p>
<p><strong><span class=""Apple-style-span"”>or

http://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js  </span></span></span></strong></p>
<p><strong><span class=""Apple-style-span"”>It depends the version you  have set. The mootools version must have hosting on Google’s Ajax libraries.

There are a few other things that you can do, to tweak the  Joomla performance.  How fast Joomla is depends on how many content items you have and how many (and which ones) extensions you run.  If you happend to have thousands of pages full of content, your site will be slow. Or if you have to have that nifty autolinker mambot, but it makes so much overhead.

Turn Off Stats and Error reporting –  You might not want all the stats Joomla gathers. If your site is not really busy (averaging over hit per second) you most propably won’t notice any change, but you will save couple of database queries every time a page gets loaded.

Both settings can be altered at the admin in the site -> global configuration

Caching –  Joomla supports native caching mechanism. To turn it on go to the Joomla admin page and choose global configuration from the site menu. Go to cache tab and make sure your cache directory exists and is writable by the webserver user.  Caching can be turned on at the site level and extension level.  Go to site modules and click on each module to see if caching can be turned on. All native modules support caching.

Propably the best option I was able to find is to use third party extension. I tried a couple of them and recommend PageCache and JAccelerate.

They both support database and file caching. This gives you the advantage to chose between cpu usage (database) and disk usage (file) depending upon your scenario. PageCache is more complex,  but performance wise gave me worse results than JAccelerate.

JAccelerate is very straightforward. Only a few simple settings and off it goes. It changed my load times from 12-17 seconds per request to 2-3 seconds. The pages are generated in less then a second.  

PageCache offers more stats, caching exceptions, neat clear cache admin button (if you use PageCache, you will understand how often you use this feature), but the load times decreased to 6-9 seconds, which might not be enough for more impatient users.

Joomla Modules

If you go to the Joomla Module directory, you will always see the PHP and XML file. The XML file stores the definition and parameters about that particular module. And in our  opinion most of these modules usually don’t go through proper design and implementation. Maybe the developer just thought of a cool idea to support some component and created a Joomla module in a flash.

Param Cache

What is param cache? This is a very special parameter in Joomla Module. And in most module this is missing. This tells Joomla to cache the module when it is enabled. What does exactly happens when Joomla cache the module? For example, the module displays the latest 10 ads in an ads components. If the developer is good, the module might have 1 query, if he’s not it might have 10.

So when Joomla cache this module, it means the module will only execute the query once when it initially loads the page that displays the module. So when a second visitor visits that page, all it’s doing is reading the cache (it’s a file from your cache directory) from your server. There are no query calls and thus improves your website performance. It will only execute the query again when the cache expires. You set this expiration time on the Site Global Configuration.

Adding Param Cache

You need to do 2 things: add the cache param on the XML file and enable caching on the module from the Administrator. If you follow these 2 steps, the query calls could be reduce with as much as 50%. That is a big performance boost.

1.Editing the modules XML file.

XML file is a specially formatted file. So you need to be careful where you add the param cache. You need to add this inside the <params> field.

<params>

     <param name=”cache” type=”radio” default=”0″ label=”Enable Cache” description=”Select whether to cache the content of this module”>

     <option value=”0″>No</option>

     <option value=”1″>Yes</option>

     </param>

     .

     .

     .

</params>

2.Enabling module caching from Administrator.

Leave a Reply