NoSQL is all the rage for Web developers who are tired of building complex SQL. Redis, a NoSQL database server much like Cassandra or MongoDB, provides a powerful and speedy alternative to relational database servers for PHP developers. Redis is similar to Memcached in terms of speed, but the data isn't volatile. That means that when your server reboots, your Redis data will still be there. You can back it up too.
A raging debate in the Web development community is whether NoSQL databases like Redis will replace traditional relational databases. But if you've been a programmer for more than a few years, you know that rarely does a technology come along and completely wipe another off the technology landscape. What's likely to happen is that NoSQL databases will work alongside traditional relational database servers.
Key-value NoSQL databases are very appealing though, particularly because of their speed, flexibility and scalability. Because Redis is a key-value database not a relational one, you don't have to spend an inordinate amount of time building a SQL schema and worrying about relational stuff such as foreign keys and primary keys. Of course, you still need to design your database, but you don't have to think about whether to use second normal form or third normal form.

Installing Redis

Installing Redis is really easy. If you're running Debian, you can install the redis-server package. It's in the testing aptitude source. Installing from the current source is really a no-brainer. You just have to download and extract it, run make, and then type ./redis-server. That's it. You can customize the server by editing the redis.conf and starting the server with ./redis-server redis.conf.

Redis Types

What makes Redis different than other key-value databases is that every value has a type. Redis supports strings, lists, sets and sorted sets. Each type has a unique set of commands that you can call to access and manipulate that type.
Strings are simply a single key with one value. For example, the key yourfirstname could have the value Boomer. Redis strings are binary safe. You can store images, serialized objects or whatever you want, as long as the data is less than 1GB in length. The single elements of lists, sets and sorted sets are strings.
A Redis list is like an array in PHP. You just push elements onto the head or onto the tail, depending on how you want the elements ordered in the list's stack. A list is indexed starting with 0 then 1, 2, 3 and so on -- an array. The command LPUSH inserts the element on the head, and RPUSH on the tail. To determine the length of the list, you call the LLEN command.
You can think of a Redis set as an associative array (or in Perl-speak, a hash). Redis sets are unordered hashes and can contain more than 4 billion elements. The current version of Redis resizes the set synchronously whenever elements are added or removed. This is a blocking operation, so you should be careful when performing mass importing or deleting of set elements.
Redis sorted sets are similar to sets, but every element can have an associated score that is used to set the ordering of the elements in the hash. As with sets, take care if you perform a mass import or deletion (millions of records), because resizing the hash is a blocking operation.

PHP Clients

There are several PHP client interfaces available for Redis. You should check out Rediska, but for this tutorial you'll use a modified version of the Redis client that comes with the Retwis application. Retwis is a Twitter-like application written in PHP to demonstrate how to build applications with Redis. For this tutorial, you should use the redis.php version because the one included with Retwis doesn't support sorted sets for some reason.

Getting to Know Redis

Download the PHP source code for this tutorial and extract it in a Web server document directory. In the redis-tutorial directory you will find two files. One is the PHP client script called redis.php, which you'll use to interact with the Redis server. The other file is called index.php, which performs basic Redis operations to demonstrate how easy it is to work with Redis.
The application you're building for the purpose of this tutorial is a favorite movie Web application. It's a really simple application, but it serves the purpose of showing how to interact with Redis using PHP.
Let's start writing some code. Connecting to Redis is a snap.
require 'redis.php'; $r = new Redis(); $r->connect();
That's all there is to it -- it doesn't get much easier than that.


A Redis string is analogous to a PHP variable. In PHP you might write:
$firstname = 'Keith';
With Redis you would write:
$r->set('firstname', 'Keith');
In the movie application you write:
$r->set('firstname', $_GET['firstname']);
Strings have a one-to-one relationship with their values. If you need to store a list of things, you could use a Redis list data type. Lists in Redis are like PHP arrays. They're indexed numerically starting with zero.
To create a Redis list, or add new data to an existing one, you use either LPUSH or RPUSH. With LPUSH, the new element is pushed onto the head of the array. If you use RPUSH, the element is added to the tail of the array.
With our Redis PHP abstraction layer, the method is simply called "push." You can specify whether you want to append the element to the head or the tail of the Redis list with a method attribute. In the movie application, you're going to store the genres in a list by simply issuing this method call:
$r->push('genres', $_GET['genre']);
What's nice about lists is that they're really fast in terms of adding elements. So while a list isn't necessarily the best data type choice for storing movie genres, lists are great for handling message queues, which can contain hundreds of thousands of records. But if you need to search through the list for a specific element, that can be laborious and slow.
The other downside of lists is that the data elements can contain duplicates. Well, it's not necessarily a downside, but that's how arrays work. For instance, if you enter "Horror" in the form as a genre twice, it will be added to the list twice.
That brings us to Redis sets. A set is similar to a PHP hash, but with Redis the data is the key and the value is always true. If you look at the movie application sample, you're going to create a dataset of actors using a Redis set. Unlike with lists, you can't enter duplicates. Entering "George Clooney" more than once will not result in a duplicate "George Clooney" element in your Redis Set.
To add data to a set, you use the command sadd like this:
$r->sadd('actors', $_GET['actor']);
What's great about sets is that you can check if a given element exists. You can perform intersections and unions, as well as check for differences between sets.
The last Redis type is the most complex: the sorted set. With sorted sets you can specify a "score" for each element and than sort your list based on that score. Just like a Redis set, a sorted set is similar to a PHP hash, but the values aren't always set to true. Rather, the value is a number that represents the element's score.
To add a new element to a sorted set, you use the command zadd.
$r->zadd('movies', $r->zscore('movies', array_pop($r->zrange('movies', -1, -1)))+1, $movieid);
There's a lot going on here, so let's break it down. The zadd command takes three arguments: key, score and value. In our example, the key is movies. You're storing your favorite movies in a sorted set so you can rank them from most favorite to least favorite. However, you don't want to store the movie name (for instance, "The Big Lebowski") in the sorted set. You want to generate a movie ID and use that instead.
Redis provides a handy command call cincr, it increments a Redis string data point. In our example application, the key is called "movieids." It's actually not a string but rather an integer, but like PHP, Redis figures all that out for you.
So what you need to do is generate a movie ID using the incr command, save the movie title and associate it with the movie ID, and then add the movie ID to the sorted set with the score or rank.
$movieid = $r->incr('movieids'); $r->set('movie:' . $movieid, $_GET['movie']); $r->zadd('movies', $r->zscore('movies', array_pop($r->zrange('movies', -1, -1)))+1, $movieid);
Notice that second line, which is storing the movie title from the GET variable. What you're doing here is just saving the movie title in a Redis string that is named movie:$movieid, where $movieid is the unique identifier for the current movie generated with the incr command. That means that when you're looping through your sorted set of movie IDs, to get the movie title you just have to query Redis for the string that contains the title.
In our example, when rendering the movie titles to the Web browser, you're going to loop the movie IDs and call the get command to pull the movie's title.
$r->get('movie:' . $movie);


While it's certainly acceptable to just run one instance of your Redis database, you might need your application to scale. If you decide to build a massive social networking application with Redis and your server starts to bog down, adding Redis slave servers to balance the load across any number of Redis servers is simple. For more information on Redis replication, check out the Replication How-to.


As you can see, building a Web application using PHP and Redis is really simple. Comb through the sample code provided with this tutorial and hack away at it to see what you can do. You should also check out the Retwis Twitter-clone application. It will give you an even deeper understanding of what you can do with Redis and PHP.
Redis also includes a handy command-line shell client. It's helpful when analyzing data and performing database administration functions. For example, if you want to clean out your database and start over, run ./redis-cli in the directory where you installed Redis and issue the flushall command.
About the Author
Keith Vance is a software engineer and a journalist. He's been developing web applications professionally since 1997, and he received his journalism degree from the University of Washington in 2008. to e-mail him.