Badge 2

WordPress 3.0 “Thelonious”. Say goodnight, Drupal.

June 25th, 2010

I recently got a chance to do some professional development with the latest WordPress 3.0 “Thelonious” release and it blew me out of the water. For a while now, I’ve been doing some work on the side in web design/development (I love to code, but I’m a designer at heart) and I use WordPress almost exclusively. I have to say, I’m very excited about the new features, menus in general, and their apparent redirection towards content management and less of a sole focus on blogging.

The menus are absolutely awesome. I’ve written and used extensions in the past to accomplish the same goal, but nothing beats out-of-the-box support with a Apple-esk UI only WordPress can provide. Multi-level support, drag/drop from content areas and built-in javascript for drop-downs all equal a vast improvement to an already great system. Best yet, the API function and the modifications to the theme to enable menus took me about 5 minutes to figure out.

For me, working with Drupal for an extended amount of time was painful. If a client wanted a complete CMS, it was hard to argue that a blog was their best solution. Often times, I’d green light Drupal just to avoid my least favorite word: Joomla (aims gun at head). Don’t get me wrong, these are fine products; it’s just that sometimes if you need to write in space, a pencil works better than a quill connected with a straw to an ink tank connected to a vacuum connected to a car battery. Is it really necessary to have a settings page with more options than there are hairs on my body?

Oh, and as someone who’s written extensions for all three of the PHP-base CMS players, you can not beat WordPress. I had my CATS JobSite page up and running in an hour — svn and release management included. Did I mention that Joomla has like 5 names for ‘plugin’? As if figuring out whether to call something a plugin, extension, addon, toolbar, module, etc. wasn’t hard enough, Joomla just grabbed the top 5… and I’m done with the complaining.

Back to point: if you need a blog, use WordPress. If you need a website your mom could add content to, use WordPress. Need more proof? I dare you to find a sexier video from an open source project.

  • Facebook
  • Twitter

Posted in HTML, News | 1 Comment »

Fixed MySQL slow queries using indexes by removing string to date conversion warnings

May 23rd, 2010

This is just a quick one for an issue I ran into today when I was tuning some MySQL indexes for better performance. Some of our older PHP code was performing a SELECT using a BETWEEN to specify a date range. After adding an index to speed up this range query, I noticed that it wasn’t taking and was still performing a table scan/file sort.

The code was using PHP’s date function with the ‘c’ format string, which inserts a date/time string like so: “2010-05-23T16:45:08-05:00″. When inserting or comparing dates, MySQL will automatically convert this to it’s internal date/time format; but, it will throw a warning.

It turns out that the warning was causing MySQL to ignore the new index for the range query even through it was listed as the used index in the EXPLAIN. My guess is that this has something to do with MySQL having to convert each string to a date on a per-row basis, causing its optimizer to use the index inefficiently.

Simply changing the PHP date function’s format string from ‘c’ to ‘Y-m-d H:i:a’ (which is a native MySQL date/time format) did the trick. The explain remained the same, but the number of rows was drastically reduced from hundreds of thousands to a few hundred (the result of the range) which took a 20 second query down to about a tenth of a second.

I haven’t tested it, but my guess is this will occur with any type of conversion that results in a warning, such as a string with text in it being converted to a number, truncated values, etc.. MySQL probably doesn’t cache those conversions up front, which leads to expensive conversions on a per-row basis which ultimately tanks any benefit an index will give you — despite what the EXPLAIN tells you!

Something to keep in mind — watch those warnings!

  • Facebook
  • Twitter

Posted in Linux, News, Uncategorized | Comments Off

Easy ICMP health checking for front-end load balanced web servers

May 13th, 2010

Over the past several years, I’ve encountered a lot of growing pains while managing a SaaS infrastructure for my company. One of our big successes in transitioning to the Lighttpd web server was almost reverted because our hardware load balancer wasn’t able to health check our front-end web servers.

Under normal operation, the load balancer will health check its child servers using a basic HTTP HEAD request. Lighttpd has some stricter requirements than Apache, and the load balancer’s HEAD request contained an invalid Content-Length header, which caused it to be rejected. Long story short, a load balancer that can’t health check its children is about as useful as a cell phone on the moon.

Being weary of continuous HEAD requests causing our log files to fill up and reserving web processes to answer them, I thought a much simpler solution would be to rely on the ICMP protocol, or more specifically, ping. If you ping a server and it comes back, that server should be online and ready to accept requests — if not, it’s dead. It’s easy to test on any terminal, DOS prompt on an aunt’s computer over Thanksgiving dinner, bash scripts, the load balancer, etc..

Next problem. Using FastCGI with Xcache in production, I’ve found a handful of ways a server can simply go zombie in my configuration which leads to the server answering pings and behaving normally but not answering (or corrupting) HTTP requests:

1) Too many connections at once overloads FastCGI available threads.
2) Xcache segfault
3) FastCGI craps out (keep PHP_FCGI_MAX_REQUESTS to 500!)
4) opcode overload (especially with stat)
5) Runaway CLI asynchronous daemon process(es) spawning off cron
6) Out of swap space (my favorite)
7) Too many open file descriptors
8) TCP network saturation
… to name a few I’ve experienced.

We rely on an external health checking service; but it can take time to get the phone call, get out of bed, restart the web server and fix the problem — the whole time your client is seeing a 500 error message or getting nothing at all. The best solution is to stop answering pings when any of the above situations happens or when the database goes down or when your app starts spewing errors. The quicker the server stops answering pings, the quicker the load balancer will redirect traffic to the next server, then the next, then eventually a nice, clean error page until we get the problem fixed.

I’ve written three scripts in bash which accomplish this on later versions of Ubuntu (I believe > version 7 or whenever the Ubuntu Firewall was introduced). The first two: block-pings and allow-pings do just what they say. The third, www-check, attempts to connect to its own web server and scans for a string of your choice. If it finds it, it executes allow-pings. If it can’t connect, or it doesn’t find the string, it calls block-pings. Here are the first two scripts, tested in Ubuntu 10.04:

block-pings:

#!/usr/bin/env bash

if [ ! $('whoami') = 'root' ]; then
    echo "This script must be run by root."
    exit 1
fi

UFW_BEFORE_RULES="/etc/ufw/before.rules"

/bin/grep "icmp-type echo-request -j ACCEPT" $UFW_BEFORE_RULES > /dev/null 2>&1
if [ $? -ne 0 ]; then
    exit 0
fi

/bin/sed -r -i "s/(icmp-type echo-request -j) ACCEPT\\s*$/\1 DROP/" $UFW_BEFORE_RULES 2>/dev/null
if [ $? -ne 0 ]; then
    echo "Failed to update $UFW_BEFORE_RULES."
    exit 1
fi

/etc/init.d/ufw restart > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "Failed to restart ufw."
    exit 1
fi

echo "ICMP ping requests are now being blocked."

exit 0

allow-pings:

#!/usr/bin/env bash

if [ ! $('whoami') = 'root' ]; then
    echo "This script must be run by root."
    exit 1
fi

UFW_BEFORE_RULES="/etc/ufw/before.rules"

/bin/grep "icmp-type echo-request -j DROP" $UFW_BEFORE_RULES > /dev/null 2>&1
if [ $? -ne 0 ]; then
    exit 0
fi

/bin/sed -r -i "s/(icmp-type echo-request -j) DROP\\s*$/\1 ACCEPT/" $UFW_BEFORE_RULES 2>/dev/null
if [ $? -ne 0 ]; then
    echo "Failed to update $UFW_BEFORE_RULES."
    exit 1
fi

/etc/init.d/ufw restart > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "Failed to restart ufw."
    exit 1
fi

echo "ICMP ping requests are now allowed."

exit 0

www-check:

#/usr/bin/env bash

TMP_FILE="/tmp/www-check.tmp"

if [ $# -ne 3 ]; then
    echo "Syntax: www-check [url] [string to check] (ping|yell|exit)"
    exit 1
fi

/bin/touch $TMP_FILE
/usr/bin/wget -T 4 -O - "$1" > $TMP_FILE 2>/dev/null
/bin/grep "$2" $TMP_FILE >/dev/null 2>&1

if [ $? -ne 0 ]; then
    case "$3" in
        ping)
            /usr/local/bin/block-pings;
            exit $?;
        ;;
        yell)
            /bin/echo "$1 is DOWN.";
            exit 1;
        ;;
        *)
            exit 1;
        ;;
    esac
else
    case "$3" in
        ping)
            /usr/local/bin/allow-pings;
            exit $?;
        ;;
        yell)
            /bin/echo "$1 is UP.';
            exit 0;
        ;;
        *)
            exit 0;
        ;;
    esac
fi

Now, either run www-check in a looping script or install it in the crontab like so:

* * * * * /usr/local/bin/www-check “http://www.mywebsite.com” “Welcome to my Site” ping

Every minute, the server will health check itself and block pings if the test string isn’t found, an HTTP connection can’t be made, or if the request times out. When the server comes back online, it answers the pings again!

  • Facebook
  • Twitter

Posted in Linux, Tips | Comments Off