Monday, February 27, 2012

Really Speeding up Joomla

This article is a free translation of the Russian blog post from here: http://alexandr.sysoev.ru/node/168

How to Speed up Joomla at the Core

Typical measures to speed up Joomla: turn on cash, install PHP accelerator, you will optimize and and maybe get 20 requests per second.

But then what, change the CMS? In my experience users who swtich often ask to come back to Joomla.

Just to mention, this article does not discuss the choice of CMS, the speed of the various CMS solutions or architectural flaws of Joomla.

These recommendations will be helpful if it is not enough for you to get 20 requests per second, you need 2000-3000.

Joomla runs on PHP, so even if you use caching at the level of modules, Joomla still uses PHP and is rendering the page each time. This means that the rate of 2000 requests per second would be unattainable. So what we are going to do is to to make Joomla keep a copy of the generated pages to disk, and Apache to read the copy directly, bypassing the PHP for all subsequent users. This is a good old approach, which incidentally can be applied to other CMS, but only for static content. For Joomla we are using Article, which is just a page with static content.

So lets create a new plugin for Joomla, just two files:

HERE IS THE CODE:


defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.plugin.plugin' );
class plgSystemHtmlcache extends JPlugin
{
function plgSystemHtmlcache(& $subject, $config)
{
parent::__construct($subject, $config);
}

function onAfterRender()
{
global $mainframe;
if($mainframe->isAdmin()) { return; } //do not cache admin pages

$document =& JFactory::getDocument();
$doctype = $document->getType();
$user =& JFactory::getUser();
if($user->get('guest') != 1) { return; } //Only cache for non logged in users
if ( $doctype != 'html' ) { return; } // Only render for HTML output
$html_cache_dir=$this->param('html_cache_dir');
if($html_cache_dir=='') { return; } //Exit if no html_cache_dir specified
if(!file_exists($html_cache_dir)) { mkdir($html_cache_dir); } //try to create folder if it does not exist
// Only render for provided views
if ((JRequest :: getVar('view')) != $this->param('cache_view_1') &&
(JRequest :: getVar('view')) != $this->param('cache_view_2') &&
(JRequest :: getVar('view')) != $this->param('cache_view_3') &&
(JRequest :: getVar('view')) != $this->param('cache_view_4')) { return; }
$relativePath=$this->request_uri();
if (strpos($relativePath, '.')) { return; } //exit if found DOT in the request_uri, we do not want to cache anything other than SEO
$relativePath=str_replace('/',DS,$relativePath);
//$body = Minify_HTML::minify(JResponse::getBody());
$body =JResponse::getBody();
$fullPath=$html_cache_dir.$relativePath;
$parts=explode(DS,$relativePath);
$currentPath=$html_cache_dir.DS;

foreach( $parts as $p){
if($p==''){
continue;
}
$currentPath.=$p;
if((!file_exists($currentPath))&&(!is_file($currentPath))){
mkdir($currentPath);
}
$currentPath.=DS;
}//end for each
$indexFile=$currentPath.DS.'index.html';
if(!file_exists($indexFile)){ $this->writeToFile($indexFile,$body); }
}

function writeToFile($fileName,$content){
$handle=fopen($fileName,'w');
fwrite($handle,$content);
fclose($handle);
}

function request_uri(){
if (isset($_SERVER['REQUEST_URI'])){
$uri = $_SERVER['REQUEST_URI'];
}else{
if (isset($_SERVER['argv'])){
$uri = $_SERVER['PHP_SELF'] .'?'. $_SERVER['argv'][];
}else{
$uri = $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
}
}
return $uri;
}

function param($name){
static $plugin,$pluginParams;
if (!isset( $plugin )){
$plugin =& JPluginHelper::getPlugin('system', 'htmlcache');
$pluginParams = new JParameter( $plugin->params );
}
return $pluginParams->get($name);
}
}
Now lets create an event handler onAfterRender. The main task of the task handler to intercept only articles of the "Article" type, to create the directory structure of folders html_cache_dir in accordance with the structure of the website and to place/save page's content in there.


In addition, before saving, you can run the page via the HTML optimizer (for example, this Minify_HTML (http://code.google.com/p/minify/source/browse/trunk/min/lib/Minify/HTML.php)), which optimizes the size of the page by removing unnecessary comments and spaces, thereby increasing the efficiency of the website.


As a separate remark, we note that this code works for websites with SEO enabled and does not cache the pages with any extensions such as php or html. Those that will be cashed are URLs of the type:
/ about
/ software / catalog


The code will have to be tweaked if you are not using SEO.


htmlcache.php - directly to the code.


Both files can be uploaded to the / plugins / system or put in htmlcache.zip and installed via the administrative interface of Joomla. After installation, set this: html_cache_dir = / opt / www / html / cache / content in the plugin settings and turn on the plugin (Enabled: Yes).
When first accessing the page in the directory / opt / www / html / cache / you should see that content is available in those folders and files - this means that the plugin is working fine and that all write permissions are fine.


What is left to do is to force Apache to give these files without contacting the PHP code. In. Htaccess, right after the RewriteEngine on to add:
RewriteCond% {REQUEST_URI} (/ | / [^.] *) $ [NC]
RewriteCond% {DOCUMENT_ROOT} / cache / content /% {REQUEST_URI} / index.html-f
RewriteRule (. *) / Cache / html / $ 1/index.html [L]


Restart apache and test the browser. In order to verify the performance run (under Linux):
ab-n 10000-c 50-k www.azati.com/
...
Concurrency Level: 50
Time taken for tests: 4.294054 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 10000
Total transferred: 71155755 bytes
HTML transferred: 67695750 bytes
Requests per second: 2328.80 [#/sec] (mean)
Time per request: 21.470 [ms] (mean)
Time per request: 0.429 [ms] (mean, across all concurrent requests)
Transfer rate: 16182.38 [Kbytes/sec] received
...
It is better to run the test a few times to ensure the "warm-up" for Apache. Can be run on the different for each.


Replace "www.azati.com" with the address of your server, www.azati.com can be tested for comparison. Do not fear, the site does not crush and Google statistics are not coreupted.

Unfortunately, the speed does not come for free:
  1. We lose the ability to edit articles (Articles) through the Joomla front-end with the help of special plugins, we can do so only through the administrative interface (i.e. the standard Joomla ability).
  2. After editing the article, you must clear the cache via the administrative interface Tools -> Clean cache.
Weigh all factors and decide whether this approach is justified for your website.


P.S. If you have dynamic content, you can arrange a periodic cleaning of the cache (e.g. every hour), and hence get a fast site that is also frequently updated.


SOURCE: http://habrahabr.ru/blogs/personal/92783/  



The key is, if you change the cotent on your website, you must clear Joomla cache. Otherwise, the new content will not be displayed. If you're going to use this method, this must be made clear to the customer.

To order a website from us, go to our web design Ottawa site, this year we focus on website design Ottawa for medium businesses and non-profit organizations.

No comments:

Post a Comment