CodeIgniter Output Caching

This week I had the privilege of doing load testing on an aws setup. The goal of the test was to support 25k concurrent users and was designed to ramp up over a period of a few minutes. The first round of testing failed pretty quick and I only had a select number of large queries cached. So the db spiked and was the bottle neck. During that test we was only able to reach 10k concurrents.

For the second round of testing I decided to just setup output caching before I even loaded the db in a MY_Controller. I set the number of minutes to something relatively high and was ready to commence the load test. Unfortunately this test maxed out the db again and I was honestly scratching my head on just why that would be the case.

Since this didn’t make any sense to me I decided I better figure just what is going on. I got my local system setup the exact same way, enabled mysql query log, and then proceded to test and see what was going on. Queries was being ran even after the cache file was written. At this point it was way late so I decided I better sleep on it and try and think about what I was missing.

The next morning I got to work ran the same tests and got the same results. Starting researching and then realized it was just my ajax calls that was generating the queries. This had me puzzled because the ajax controller extended the MY_Controller so it should be cached as well. Turns out I was wrong and missed the most important note in the user guide:

Warning: Because of the way CodeIgniter stores content for output, caching will only work if you are generating display for your controller with a view.

The more I thought about it the more sense that makes since the Loader ties into the output library but I wasn’t thinking clearly at 3am. Looked at my ajax controller and sure enough I was just returning a json string.

return json_encode($vars);

The quick fix was to change the return to the following:

return $this->output->set_output(json_encode($vars));

My hope is this will help others if they ever run into the same situation. Unfortunately the load testing was only scheduled for two rounds but I feel confident by fixing that it would have passed with flying colors.

So the moral of the story. READ THE MANUAL 🙂

New Year, New Job, New Framework

I am happy to announce that starting January 9th I will be working full time for Userscape. If you are not familiar with them they are the company behind the awesome HelpSpot help desk software.

Laravel

Not only will I be a part of a great company but they have also hired the creator of the Laravel framework, Taylor Otwell. I have been watching that framework closely the past few months and I am very impressed with what he has done with it. Laravel’s motto is:

Laravel is a clean and classy framework for PHP web development. Freeing you from spaghetti code, Laravel helps you create wonderful applications using simple, expressive syntax. Development should be a creative experience that you enjoy, not something that is painful. Enjoy the fresh air.

The simplicity of framework is what drew me in originally. But now it will just keep getting better and better because it will be the framework of choice for Userscape. The reason I feel this way is that HelpSpot can be purchased as either a downloaded application or hosted with their partner Engine Hosting, so Laravel will be tested in a wide range of different hosting environments.

CodeIgniter

Even though my day job will be with Laravel I still love CodeIgniter and I am still on the CodeIgniter Reactor team. CodeIgniter is and has always been near and dear to me and I really enjoy using it. Plus I will be doing contract and freelance work for companies that are heavily invested into it. I am very excited with where CodeIgniter v3 is heading and I think it is a big step in the right direction that we have all been wanting.

My Top Mac Apps of 2011

I always like reading lists of apps that developers use on a daily basis and I love finding ones that I have never heard of or never gave a chance. As 2011 comes to a close I wanted to share my favorite apps that I use on an almost daily basis.

CodeIgniter

Not a mac app but still the framework I use every single day and write posts about all the time. 🙂

Alfred App

This is a must for every computer that I own. I love the quick application launching, calculator, and custom commands you can use.

Sparrow

Previously I was using just the standard mail app but when 10.7 came out I really disliked it. So I found Sparrow and have been happy ever since. It is nice and light and does just enough for what I do.

Git-Tower

I don’t always use a git gui, but when I do I choose Tower. I like the quick visual diffs and the clean layout. Another great git gui is gitbox which I use as well.

Mamp Pro

I use Mamp Pro just because it is easy. I like the fact that I can setup vhosts through a gui and not have to worry about installing apache, php, and mysql. Another benefit is that I work with a bunch of designers and with us all using Mamp I know what I build will run on their systems with out me having to do anything.

Sublime Text 2

This is my code editor of choice right now. It is awesome and you should try it if you haven’t. More Sublime Text Posts

Fake App

I found this a few months ago and it is really great for browser testing and inspired by Automator. So it is really simple to setup and use.

nvalt

I use this every day to create notes, ideas, and write out features before starting coding. I have this setup to sync with dropbox so my notes are always available. More Tips

Sequel Pro

I have to connect to several dbs throughout my day and this app makes managing mysql a breeze.

CoRD

CoRD is a Mac OS X remote desktop client for Microsoft Windows computers using the RDP protocol. At work we have a lot of old legacy sites that are running on windows hosting and I really like this app because of its speed compared to others I have tried.

Common Ones

For other common day to day applications I use Chrome as my browser, iChat, Textual IRC, dropbox, and Feedly for my rss feeds.

CodeIgniter Slug Library

I am happy to announce a simple CodeIgniter library to help you generate slugs for your urls. This is something I use on almost every project and it has been invaluable to me. Hopefully you will find it useful as well.

For those that are not familiar with the term slug WordPress defines it as:

A slug is a few words that describe a post or a page. Slugs are usually a URL friendly version of the title.

Description

What this library does is allow you to pass a string such as a titile and then generate a url friendly string from it. Also and most importantly it checks against fields in your db so that you will not have any duplicates. For example:

"This is my title"

Would become:

"this-is-my-title"

If a duplicate is found then it appends a number. Example:

"this-is-my-title-1"

Example

First load the library with an array of config items:

$config = array(
    'table' => 'mytable,
    'id' => 'id',
    'field' => 'uri',
    'title' => 'title',
    'replacement' => 'dash' // Either dash or underscore
);
$this->load->library('slug', $config);

When creating a uri for a new record in your db you can do it like this:

$data = array(
    'title' => 'My Test',
);
$data['uri'] = $this->slug->create_uri($data);
$this->db->insert('mytable, $data);

Then for when you are editing an existing record: (Notice the create_uri uses the second param to compare against other fields).

$data = array(
    'title' => 'My Test',
);
$data['uri'] = $this->slug->create_uri($data, $id);
$this->db->where('id', $id);
$this->db->update('mytable', $data);

Download

You can clone the repo by running the code below:

$ git clone git://github.com/ericbarnes/CodeIgniter-Slug-Library

Or visit the GitHub Repo.

CodeIgniter Optimizations

I am currently building a pretty large CMS system on top of CodeIgniter and I wanted to share some of the best performance optimizations I have found. Although CodeIgniter is optimized out of the box, when you start building large scale applications with large controllers, it is easy to miss things that can add up to your overall performance.

Do Not Save Queries

$this->db->save_queries = FALSE;

By default CodeIgniter keeps an array of all the queries1 ran so that they can be used in the profiler for debugging. This is great during development but in most production cases that is not needed and just wasted memory. I recommend disabling this in production mode and can be conditionally setup with a simple if statement:

if (ENVIRONMENT == 'production')
{
    $this->db->save_queries = FALSE;
}

Output Cache

CodeIgniter supports several levels of caching and the most extreme is caching is the entire output. That is designed to cache the entire parsed page then just display it the html for the amount of minutes you designate.

By default CodeIgniter writes this cache to files which increases your i/o and it might suit you better to use apc2 (example) or memcache for the storage.

The downside to this is if you are needing some form of dynamic data like user information. Then it will not work. If that is a requirement for you then consider caching queries or other areas where your site is slow. Or you can do like getsparks and use ajax calls to dynamically populate the user information.

Consider Nginx + php-fpm + apc

I know everybody uses Apache and it has tons of tutorials and an all around good server. But in my tests straight out of the box Nginx out performs Apache and I am not the only one

I had a standard AWS medium instance running about 25 sites that was averaging 30% CPU usage during the day with Apache + APC. After just switching to Nginx and php-fpm it is now averaging around 10%. That is a huge difference!

Autoloading Can Be Dangerous

CodeIgniter comes with an “Auto-load” feature that permits libraries, helpers, and models to be initialized automatically every time the system runs.

Lets face it autoloading is awesome, but does come with some drawbacks. The biggest is that everything autoloaded is loaded on every request. This means for every page and every ajax call all those items are being loaded. So unless you are, in fact, going to need it for everything then I wouldn’t recommend auto loading. Instead consider base controllers or loading only when needed.

Only Load What You Need

Touching on autoloading is another common issue I have seen. Loading when you don’t need too. Ideally you do not want to load anything unless you are going to use it in the code that is running.

class Welcome extends CI_Controller {
    public function __construct()
    {
        $this->load->library('email');
        $this->load->library('ftp');
    }
    public function index()
    {
        $this->load->view('home_page');
    }
}

As you can see in the example above we are loading two libraries that will never be used when viewing the home page so by including them you are just wasting resources.


  1. This feature has been around since v1.6.0 but is not documented very well. 

  2. This idea came from getsparks.org and I linked to a gist in case getsparks code changes. 

CodeIgniter Nginx Virtual Host

Currently I am in the process of switching a server from Apache to Nginx and here is a quick tip for those using CodeIgniter or who want to host a bunch of very similar domains. For each server line I do this: 

server {
    server_name .mysite.com;
    root /sites/mysite/www;
    include /sites/nginx/ci_vhost;
}
server {
    server_name .mysecondsite.com;
    root /sites/secondpath/www;
    include /sites/nginx/ci_vhost;
}

Then the ci_vhost includes the common settings: 

index index.html index.php index.htm;

# set expiration of assets to MAX for caching
location ~* .(ico|css|js|gif|jpe?g|png)(?[0-9]+)?$ {
    expires max;
    log_not_found off;
}

location / {
    # Check if a file exists, or route it to index.php.
    try_files $uri $uri/ /index.php;
}

location ~* .php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+.php)(.*)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

This allows you to have all the shared settings in one location and will make future changes much easier. Also this works perfectly for me with CodeIgniter’s default setup. Removing index.php and leaving uri_protocol to AUTO.