Archive for the 'Uncategorized' Category


Update on nginx and Piwik

In my previous post I summoned some hackish magic to fix something that I didn’t really understand. That’s usually not good practice. Most experienced developers have a well-tuned b.s. detection system and will return to unnecessarily hackish code almost as a matter of necessity. That was the case here, and what I found was that the error was in my nginx conf file. For whatever reason I had nginx misconfigured and content JavaScript, CSS, and SWF files were being served up by fast-cgi instead of being handled by nginx directly. Here’s a relevant section of my updated conf file:

# Stop Image and Document Hijacking
# Also have to handle these file types for piwik before they get processed by PHP below
location ~* (\.jpg|\.png|\.css|\.gif|\.jpeg|\.js|\.swf)$ {

   if ($http_referer ~* ^(http://my.domain.com) ) {
      expires max;
      break;
   }

   return 444;

}

location / {

   root   /home/public_html/my.domain.com/public/;
   index  index.php index.html;

   # this serves static files that exist without running other rewrite tests
   if (-f $request_filename) {
      expires max;
      break;
   }

   fastcgi_pass 127.0.0.1:9000;
   fastcgi_index index.php;
   include /usr/local/nginx/conf/fastcgi_params;
   fastcgi_param SCRIPT_FILENAME /home/public_html/my.domain.com/public/$fastcgi_script_name;
   include fastcgi_params;
}

Everything got better after that. Not sure who I thought I was fooling with my first solution, but it didn’t even work on myself.

2 comments

Nginx, Piwik, and Content Type Headers

Note this Update: read update

I decided to give Piwik a try as my web analytics tool. I’ve used Mint in the past and am mostly happy with it, but I sometimes feel Shaun Inman has no sense of urgency to make improvements to catch up to the big guys. I also considered Google Analytics and GetClicky but can’t get over the idea of someone else owning my analytics data. Sure, that’s fine for my blog or other smaller sites, but for something “important”, I’d rather hold onto it myself.

Piwik installation was pretty straightforward, typical fare these days. First thing I noticed was that the site was completely broken in FireFox, but seemed to work fine in IE. Firing up Charles I saw 2 things that smelled wrong:

  1. Requests for JavaScript and CSS files had a cache-busting query parameters stuck on the end of it, e.g. /piwik/themes/default/common.css?piwik=0.4.2. The idea here is that they can set a far-futures expires header on that file and let the browser cache it forever. When they release a new version of the site, they increment the version number on the request parameter and the browser goes and fetches the new styles or scripts. I thought this was an interesting technique, but possibly confusing nginx because….
  2. The “Content-Type” header was coming back as “text/html” for both JavaScript and CSS files.

IE doesn’t seem to mind that the content type was set incorrectly but Firefox refused to apply the styles because of it. So I started tinkering to see what I could do. Worst case scenario I would just have to use piwik only in IE, but that seemed kind of defeatist. Strangely, no one else on the interwebs seemed to be having the same issue, which lead me to think it was something specific to my environment.

The first thing I tried was to remove the cache busting request parameter by commenting out this line of code in the piwik source code:

$this->smarty->load_filter(‘output’, ‘cachebuster’);

I found that line in the file core/View.php on line 54 in version 0.4.2. That got rid of the cache busting query parameter, but didn’t fix the content type issue, so I ended up putting that line back in. I tried dropping one of the CSS files I was testing on another server and requesting that to see the headers. They turned out to be fine, at which point I decided it had to be an nginx issue. A couple of hacky attempts later I came up with the idea of just adding another header to JavaScript or CSS files as such:

   if ( $request_filename ~* (\.css) ){
      add_header Content-Type "text/css; charset=UTF-8";
      break;
   }

   if ( $request_filename ~* (\.js) ){
      add_header Content-Type "application/x-javascript; charset=UTF-8";
      break;
   }

That seems to work. Not entirely thrilled about it since I still don’t fully understand why it’s happening. Two Content-Type headers are getting set, but Firefox is ok with that for now. Oh well.

Note this Update: read update

3 comments

CodeIgniter and Minify Redux

My previous article about CodeIgniter and Minify was a relative hit (relative only to my other posts that is), but some thinking since the original version mixed with some of the great comments on that post have prompted me to update the integration points a little to improve the flexibility and maintainability. Requiring a new method inside the MY_Includes.php file for each controller got to be a bit of a bear. Also, the wacky mapping that I did in the init method was overkill. Lastly, the code from the original post broke when CodeIgniter 1.7.1 was release because of the new support for name aliasing of library classes, so it needed an update anyway.

What I decided to do was to export the mapping to a config file. See an example config file here. This file goes into the application/config directory. You probably also want to update application/config/autoload.php to autoload that config file:

$autoload[‘config’] = array(‘minify_config’);

It is assumed that all JavaScript files are in the same location on disk and all CSS files are all in the same location on disk. It also assumes that all JavaScript files end with js and all CSS files end with css. The rest (mostly paths) can all be configured. I don’t show it but I have the absolute paths to the JavaScript/CSS files in the standard CodeIgniter config file.

The minify_config.php config file sets up a hash where the key is the controller name and the value is an array of JavaScript or CSS filenames. For simplicity’s sake the file name array is only one-dimensional, so you’ll notice the use of array_merge in some spots.

The MY_Includes class itself is greatly simplified now, but at its core performs the same task as the previous version, building a list of files to be included and passing them off to Minify for processing. The includetag.php controller is unchanged.

So the new and improved steps for integration are:

  1. Download MY_Includes.php (here) and put it in your /system/applications/libraries directory
  2. Download minify_config.php (here) and put it in your application/config directory
  3. Edit the init method inside of MY_Includes.php to include the correct path to your Minify installation
  4. (Optional) Edit the compileTags method inside of MY_Includes.php to include any special rules. Out of the box it will include a config item named global on every request, then check to see if there are any controller-specific files to include.
  5. Download includetag.php (here) and put it in the /system/applications/controllers directory
  6. Add the two code fragments commented with the text “for globally included header file” below to the appropriate file in your application
  7. Fire it up
//for globally included header file (e.g. header.php)
//so know which CSS or JS files to include
$pageName = $this->uri->segment(1, 0);
$pageName .= “/” . $this->uri->segment(2, “index”);
$this->CI->load->library(“MY_Includes”, $pageName);
<!– for globally included header file (e.g.header.php) –>
<link rel=”stylesheet” href=”<?= $this->CI->my_includes->cssTag(); ?>” type=”text/css” media=”screen” />
<script src=”<?= $this->CI->my_includes->jsTag(); ?>” type=”text/javascript” charset=”utf-8″></script>

Feel free to post a comment if you have troubles and I’ll walk you through it or edit the post to fix any errors as needed.

6 comments

Say it Ain’t So Memcache

I will never claim that application profiling and stress testing are my strongpoints, but I’m having a really difficult time understanding the results of some tests I’ve been performing on my application.

Here’s the setup. My application is on 2 256 slices, 1 running nginx and PHP through fast cgi. The other is running MySQL. Outside of things like monit and munin, there is nothing else running on these slices. Perfect time to do some stress testing. The application is fairly database heavy, so I long ago decided to integrate memcache with an eye towards boosting peformance. Or so I thought (notice ominous foreshadowing).

My strategery with memcache is to never assume that it is either running, working, or contains the data I need. So my app will use it if it’s there but will carry on unaffected if it’s not. I left hooks in the app to be able to shut off memcache through config changes for cases where I’m testing via XAMPP and don’t have memcache running locally. This turned out to be very useful.

I have a third slice (which runs this blog and a couple of other smaller sites) that I installed http_load on. I used this box to drive the load tests.

One thing about http_load is that it doesn’t understand cookies. You provide it a URL or list of URLs and it just whacks on them until the server breaks. That poses a problem for apps like mine where being logged in is essential to the experience. So I had to make a few changes to the application to support a load testing mode. Once I change to this mode it will take the session identifier out of my config file instead of the cookie. No muss, no fuss, no meaningful change to the app’s behavior while in test mode, which is essential to ensure I’m comparing apples to apples.

OK, enough setup. Here’s one of my test scripts:

http_load -parallel 5 -seconds 30 test.url > test.out

So, run 5 threads for 30 seconds. While that’s going on I’m checking top on my nginx and MySQL slices. First thing I notice – MySQL is pretty much sleeping through the test. Good news. Load on that slice barely breaks above .2. But the fast-cgi processes on the nginx box launch to the top and hog up CPU and memory at an alarming rate. Before the 30 seconds is over load on the nginx box is over 3. Not good. End result was about 27 requests per second. Not horrible, but there’s no way the box could maintain that kind of load long term. I ran this test:

http_load -rate 20 -seconds 30 test.url > test.out

Which simulates 20 requests a second. So what I’m trying to do there is find a reasonable amount of traffic that will stress the server but not kill it. That seemed to be about the breaking point. The server handled 20 requests a second with some negative effects but it seemed it could be stable at that level.

So, had to do some thinking. In an effort to cheer myself up, I figured I’d disable memcache and see how bad it would be without its help. If I got between 20 and 30 with memcache surely I’d only get between 15 and 20 without it.

Well, guess what, nerd. Not so much. To my amazement, the result came in around 36 requests per second without memcache. Not only that, CPU consumption by the fast-cgi threads was reduced and their memory consumption was totally normal. Beyond that, load on the database server didn’t budge.

It’s almost like memcache is penalizing me. Things got a little weirder when I commented out the code to pull some objects out of memcache but left others in. The results got down to 10 per second, which is nearly unbearable. I wish I had a conclusive summary to give but right now my thinking is that the overhead of connecting to memcache and hydrating objects is slower than just getting the data from the database. Or maybe I’m just overusing memcache – storing and retrieving too many small objects for example.

So for the meantime I’m running without memcache, despite the hours and hours of work I put in to integrate it, and all the hopes and dreams of the children.

4 comments

Year 2009 Alert

Note to LAMP interviewees. It’s now 2009. Boasting that you wrote your own PHP framework is ridiculous and unimpressive. I’m sure you’re very clever but no, I will never agree to letting my project use 10K lines of unproven code that’s running your blog. Yea, we all can (and have) written a database interface class. Still not interested. Sorry.

Also, it might be a good idea to have some understanding of what the term “unit testing” means.

0 comments

CodeIgniter Autoloading and Performance

Got some interesting results tonight from my adventures with xdebug and CodeIgniter, specifically with the autoloading feature.

I had run xdebug to collect stats on my app’s landing page, the page where all users will be redirected after login. I’d naturally expect this to be one of the most heavily visited pages, therefore has to be as optimized as possible. After running the results of xdebug’s profiler (“xdebug.profiler_enable=On” in php.ini) through WinCacheGrind I found something like 300+ calls being made to the method CodeIgniter uses to load a library file/class. I had long suspected that liberal use of $CI->load->library(‘MY_Blah’) wasn’t necessarily good practice, but I didn’t suspect it could have been that bad.

So I decided to put my most-frequently loaded libraries into the autoload.php and remove any calls to load them in my libraries, controller, and views. The difference was noticeable, and a second pass through xdebug and WinCacheGrind proved the improvement was real. I tried not to go overboard by loading too many classes, and it seems like I was able to strike the right balance by autoloading less than ten of my dozens of classes.

Another interesting result was integrating memcache to save some of the objects that are frequently loaded on the landing page. These objects are for the most part shared across all users on the site. For some reason after I integrated memcache the memory usage for the controller (according to CodeIgniter) went up to around 8MB from 2MB. Very weird results that I’m going to have to think about. Database load on the page is near nothing, which is good news. I’m assuming the problem is in copying the objects out of memcache and creating PHP objects out of them.

Guess I’ll be doing some more profiling.

0 comments

Scary Moments in Administering nginx

So I was trying to install xdebug on my Slicehost slice and I couldn’t get the damn module to load.

I was following these instructions – installed via PECL, added the line to php.ini, restarted the web server, etc. Nothing. Wasn’t showing up in either “php -m” or the output of phpinfo().

So then I decided to compile from source, using instructions on the same page. Now it actually got worse. I was getting a 502 error and this in the logs:

2009/06/04 16:50:46 [error] 4461#0: *1 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: XXX.XXX.XXX, server: myserver.com, request: “GET /index.php HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “myserver.com”

Begin freakout.

Nothing was working. Bounce web server. Nothing. Bounce slice. Nothing.

Continue freakout.

Don’t totally know why I decided to restart fastcgi, but sweet mother that worked. And not only that, xdebug was loading as expected.

sudo /etc/init.d/php-fastcgi restart

End freakout.

(To be more precise, I restarted nginx first and then restarted fastcgi.) Hope that helps someone out there. Certainly scared the tuna salad out of me for a good half hour. Oh the joys of system administration for developers.

0 comments

Virgin Servers and Nerd Pr0n

As weird as it sounds, for legal reasons I had to move my side project onto a server I have root access to. This posed some serious problems for me. I’ve developed tons of sites, and I’m no stranger to a command prompt, but a sysadmin I am not. Postfix? iptables? munin? monit? The extent of my exposure to the intricacies of system administration was whatever was available from within cPanel plus whatever I could change from my shell account. Admittedly, this was limited, if not comfortable.

After hemming and hawing and researching I settled on a VPS setup on Slicehost, which was recently purchased by Rackspace. I expected a painful transition to a self-managed server, and honestly it wasn’t all shits and giggles, but the experience was (and is)….Amazing. Liberating. Invigorating. Confidence building.

I got plenty of help. The Slicehost tutorial articles were an incredible resource. I could have barely done it without them. I also got some key help from A. DeRose an ex-coworker who had recently worked through moving the Tripology site to Slicehost. Even still, I learned an incredible amount about how to configure and run a server. It’s an experience I wish all developers could have at least once.

Almost on a whim I decided to use nginx as my web server instead of Apache. Nginx is stupid fast. I don’t really have anything against Apache, but I can appreciate how simple nginx is to install and configure. For basic web sites, it makes Apache seem like a big fat mouth-breathing mooch that won’t leave your apartment. I haven’t regretted that decision yet, and I don’t expect that I ever will.

I also heartily recommend Monit, Munin, and apticron. Between those three I feel that if something happens to the server that I need to know about I’ll be the first to know. Lastly, I can recommend Pingdom as a external 3rd Party service to make sure the server is responding.

The most exciting part of all of this is that after all these years of nerdom there’s still something to learn. It’s what geeks like us live for.

Update: Don’t know how I managed to forget this article for setting up Ubuntu on Slicehost. This article was pretty much my bible for 2 days. Whoever wrote that deserves a special place in nerd heaven as far as I’m concerned. Great stuff.

0 comments