Professional Freelance Web Developer
CodeIgniter Activist, Caffeine Junkie

Elliot Haughin

Building Web Applications That Scale

25th February 2009

During my time as a web developer I’ve had the opportunity to work on some application that needed serious scalability. But scaling isn’t something we always think of when we set off to build an application.

So, here’s a few tips I’ve picked up on the way that can help you build applications that are ready to scale immediately.

1. Benchmark all of your code

When you write new sections of code, make sure you add benchmark points to it, so that when you start to scale up, you can immediately find any bottlenecks in your code without having to go back through your application and add the points.

In CodeIgniter, there’s a built-in benchmarking library that is loaded by default, so it’s very simple to use.

$this->benchmark->mark('POST_XML_START');
$this->post_model->get(10, 'xml');
$this->benchmark->mark('POST_XML_END');

If your application already has benchmark points in from the start, scaling will go much smoother.

2. DON’T cache everything

Contrary to other advice, I’d say that the best way to cache is bit by bit. One section of functionality at a time.
Scaling and caching is always a balance between data being up-to-date, and data being fast to retrieve.

When you build your application, make sure that your code is ‘ready’ to cache things, but it’s not actually doing it yet.
Here’s an example of what I mean.

function get_posts($num = 10)
{
     $cached = $this->cache->get('post_model.get_posts.'.$num)

     if ( $cached !== FALSE )
     {
          return $cached;
     }

     // OTHERWISE... we get the posts, and cache them
}

In our cache library, it would look for a configuration value for how long to cache posts_mode.get_posts – by default we would set this to FALSE, or not to cache.
When our application scales, we can choose specific methods within our models to cache as and when we need.

3. Abstract Your Cache Methods

Don’t assume that when you DO start caching data you’ll know what caching extension you will be using, so build a caching library that is abstract and can handle a configuration value to select the caching extension.

So, you may ‘think’ that you will use memcache, but to start with, you may want to use APC, then later migrate to memcache. If you’ve written memcache->set throughout your application, you’re going to have a hard time migrating.

But if all you have to do is change is:

$this->cache_type = 'memcache'

To:

$this->cache_type = 'apc'

You’re going to find it much easier to switch.

4. Avoid disk usage

In any area of computing, one of the slowest (‘expensive’) tasks is reading from and writing to disk. Due the the basics mechanics of a disk, it’s inherently slow.

If you have any methods that traverse directories, read/write contents to disk, try to get rid of them… think of any other way to do it possible.

5. Write ‘cloud’ applications

Whenever you’re writing functionality within an application, bear in mind that this might not be the only instance of the application running at a given time. When your application scales, you may wish to setup several instances of the application running simultaneously. This can cause some problems when writing to a database, working with sessions, and very ‘live’ data.

It’s not something that you should spend days discussing and having meetings about in the very early days of your application, but it is something that you should keep in mind. Try to avoid any code that will ONLY work in a standalone environment.

6. Optimize queries as you write them

Many people write queries (that’s database queries) then just throw them right into their application. This might seem like a perfectly acceptable way of using your database but beware!

I have a simple way of writing my queries to give them the best chance of scaling.

  1. Write what you ‘think’ the query should be.
  2. Run an ‘EXPLAIN’ (or similar) on the query to find any flaws.
  3. Add indexes where needed
  4. Now we can put it in our application

This process only takes a few minutes to do, and it could save you a great deal of performance headaches at a later date. However, there will be a point within your scaling where queries will need to be re-written, and possibly database structure changed to accommodate greater load.
But, if you do a few simple checks on your queries, they should last a bit longer before you have to rewrite them!

And Finally…

Whenever I write code, I always have a vague ‘idea’ of how I will write it. Then, I solidify the idea, and just ‘write’ it. Once it’s done, I check it works, make sure it’s quick, and get on with the next bit of code.

This process is fine if you’re already up-to-speed (excuse the pun) on best coding practices for scaling. But, I’d always recommend getting second opinion about the way you’ve written your code.

Make friends with clever people, and ask them questions about what you’ve done and how to improve it.

In any area of web development there are several ways to do the same thing, so have an open ear for other people’s ideas. After-all, they might be better, and this will help you learn!

Related posts:

  1. Building Web 2.0 Ready Applications with XML-RPC
  2. Optimizing and Scaling your CodeIgniter Application – with Benchmarks!
  3. CodeIgniter Multicache Library 0.1
  4. Building UTF8 Compatible CodeIgniter Applications

  • "I’d say that the best way to cache is bit by bit" -Do you know of any CI Caching Library that does so ?
  • Tommy
    Very interesting post! I'm curious; won't having "tons" of benchmark calls slow down the app as well?
  • Great tips! Thanks so much for sharing. Just about to dig into a project where scalability (in CI) is very important. This was great.

    -Garrett
  • Elliot,

    I like the way you set posts out and I enjoyed this post as much as the last. It's always good to see what other CI users are doing in their applications.

    Thanks,
    Adam
  • Great post Elliot.
    I will add something about SQL queries: avoid " select * " whenever it's possible. I have seen lot of bottlenecks because of that in php applications whis uses select * always instead of a well designed sql query.

    Regards,
    Jose
  • Nice post Elliot.
    It is always important to predict a higher level of traffic to an application that first expected.

    We recently developed a t-shirt website which was not developed using CodeIgniter, which I usually develop with, due to the other developers on the team.
    Now, is now causing a high amount of performance issues which is effecting other sites on the server.

    It may be nice to add a little bit about pconnect v's connect.
  • Great post! I'm in the process of building a large scale app that will, no doubt, have to scale at some point. These are good things to keep in mind... thanks!
blog comments powered by Disqus

Boring Stuff

Design © copyright Elliot Haughin 2009

Content published here are copyright their respective owners.

You cannot copy content from this site, either in English or translated to another language.

Keep Subscribed

Theres lots of ways for you to keep up with me on the web.

Please Note

Information given out on this blog should only be used as a guideline. I hold no liability for any code I write.

Always consult a professional before acting on this guidance.