Introduction
You can use a leaderboard to rank players in gamified systems. It's an essential part of building an application where several participants are competing for a specific goal. Leaderboards are widely used in computer games to show peers how they rank compared to other players.
Today, you can use leaderboards in a variety of applications to rank performances. For instance, you might use it to rank salespersons depending on the total sales they've made within a given period. Similarly, you can implement a leaderboard in a fitness tracker application, and anyone connected to your software can compete in fitness leagues and online challenges. In the financial industry, you can use leaderboards to monitor and detect suspicious transactions and mitigate fraud.
The best thing about leaderboards is creating a sense of motivation; they encourage participants to work hard and achieve their goals. In addition, in some sense, leaderboards build cohesion since participants are grouped with like-minded peers depending on the criteria of each competition.
While leaderboards are great, consuming and processing data from thousands or even millions of users connected to your application to provide real-time analytics may not work well with traditional SQL databases since they save data to disk. For this task, you require an in-memory database that can read, write, slice, and sort data at a massive scale without any disk IO overhead. This is where the Redis Server comes in.
Redis is highly suitable for fast data ingest and can handle complex mathematical computations (for instance, sorted sets and attributes that you require to analyze and rank data to create a leaderboard. It can also handle simultaneous clients performing thousands of requests per second. To put this in a better perspective, Redis can effectively process step counts data from thousands of fitness devices at a lightning speed.
In this guide, you'll create a PHP logic that uses the php-redis
library to accept data and create a leaderboard on an Ubuntu 20.04 server.
Prerequisites
Before you proceed, make sure you have the following:
- An Ubuntu 20.04 server. Since Redis uses your computer memory for storage, spin up a server with several vCPUs and a fair amount of RAM.
- A sudo user.
- A Lamp Stack. For this guide, you might skip Step 2 (Install a Database Server) since you don't need a MySQL/MariaDB server.
- A Redis Server
1. Install the Redis Extension For PHP
In this step, you'll install a PHP extension that allows PHP scripts to talk to the Redis Server via an Application Programming Interface (API). This is a fast, flexible, fully functional, and user-friendly Redis library.
To install the library, SSH to your server and update the package information index.
$ sudo apt update
Next, run the following command to install the php-redis
extension.
$ sudo apt install -y php-redis
Restart the Apache webserver to load the new extension by executing the following command.
$ sudo systemctl restart apache2
You now have a working PHP extension for interacting with Redis. Next, you'll create a PHP script that accepts data for ranking purposes.
2. Create a PHP Script To Accept User Scores
Before you start ranking your data in either ascending or descending order, you should use the Redis ZADD
command to add members with their respective scores to a sorted set ZSET
. If you have already included a member in a set, you can update their respective score at any time by calling the ZADD
command against the existing member's data. Behind the scenes, the Redis server will update the score and position of the member. The ZADD
command is suitable in situations where you have tons of updates since it is extremely fast.
To add a member's score via the redis-server
command-line interface, you should use the syntax below.
$ redis-cli
127.0.0.1:6379> ZADD NAME_OF_THE_SORTED_SET SCORE_VALUE MEMBER_NAME
127.0.0.1:6379> quit
For example, to add a score of 1768 to a member named Fred
, use the syntax below.
$ redis-cli
127.0.0.1:6379> ZADD players 1768 Fred
127.0.0.1:6379> quit
In this guide, you'll create a PHP script that automates the whole process using the Redis zadd
function. Use the nano
text editor to open a new zadd.php
file in the root directory of your web server by executing the following command.
$ sudo nano /var/www/html/zadd.php
Then, enter the information below into the file.
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$seller = $_POST['seller'];
$total_sales = $_POST['total_sales'];
$redis->zadd('sales_persons', $total_sales, $seller);
echo "You've successfully added the seller's sales into the Redis server.\n";
Save and close the file when you're through with editing. In the above file, you're connecting to the Redis server. Then you're listening for two HTTP POST variables from the client's applications. The variable $_POST['seller']
holds the member's name that you wish to add into the sorted set. Then, you're retrieving the current sales amount of a salesperson (score) from the $_POST['total_sales']
variable.
In this script, you're simply accepting salesperson data depending on the sales an employee has made. Then, you're adding the data of each participating employee into the sorted set named sales_persons
.
Next, you'll simulate some sales records using the Linux curl
command. You might find it easier to feed sales data from your invoicing software through an API in a production environment instead of adding it manually, especially if you have many salespeople, such as a web hosting referral system.
For now, execute the following 7 commands against the zadd.php
script to add the salespersons' data to the Redis server.
$ curl --data "seller=JOHN DOE&total_sales=9749" http://localhost/zadd.php
$ curl --data "seller=MARTHA SMITH&total_sales=1822" http://localhost/zadd.php
$ curl --data "seller=PETER JACOB&total_sales=4437" http://localhost/zadd.php
$ curl --data "seller=ESTHER ERIC&total_sales=6849" http://localhost/zadd.php
$ curl --data "seller=JANE ERIC&total_sales=2256" http://localhost/zadd.php
$ curl --data "seller=MARY PATRICK&total_sales=7894" http://localhost/zadd.php
$ curl --data "seller=PETER MARTIN&total_sales=3526" http://localhost/zadd.php
Ensure you receive the following output after running each command to make sure the data is in place.
...
You've successfully added the seller's sales into the Redis server.
You now have a working Redis sorted set, which you've populated with some records. Next, you'll use a Redis ZREVRANGE
function to rank the data.
3. Create and Test a PHP Leaderboard Script
You should order the sales amount from the highest to the lowest value to rank your sales data. That is, in descending order. You can accomplish this task in a command-line interface by executing a ZREVRANGE
against your sorted set using the following syntax.
$ redis-cli
127.0.0.1:6379> ZREVRANGE NAME_OF_THE_SORTED_SET START END WITHSCORES
For instance, to get a list of all salespersons arranged in ascending order together with their associated sales amount between $0 and $200000, run the following commands.
$ redis-cli
127.0.0.1:6379> ZREVRANGE sales_persons 0 200000 WITHSCORES
You should get the following output.
1) "JOHN DOE"
2) "9749"
3) "MARY PATRICK"
4) "7894"
5) "ESTHER ERIC"
6) "6849"
7) "PETER JACOB"
8) "4437"
9) "PETER MARTIN"
10) "3526"
11) "JANE ERIC"
12) "2256"
13) "MARTHA SMITH"
14) "1822"
Exit from the Redis server command-line interface.
127.0.0.1:6379> quit
You'll accomplish the same result above by using the zRevRange
function inside a PHP script. This time around, you will structure the leaderboard in a more human-readable format using some PHP functions.
To do this, use nano
to open a blank /var/www/html/leaderboard.php
file.
$ sudo nano /var/www/html/leaderboard.php
Next, enter the information below into the /var/www/html/leaderboard.php
file.
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$result = $redis->zRevRange('sales_persons', 0, 200000, true);
echo "\n" . str_repeat("-", 40);
echo "\nSALES RANK BY HIGHEST SELLER\n";
echo str_repeat("-", 40) . "\n";
echo "\nRANK NAME SCORE \n";
echo str_repeat("=", 40) . "\n";
$i = 1;
foreach($result as $key => $value) {
echo str_pad($i, 6, " ") . str_pad($key, 17, " ") . str_pad($value, 17, " ", STR_PAD_LEFT) . "\n";
$i++;
}
Save and close the file. In the above file, you're initializing a new Redis instance. Then, you're invoking the $redis->zRevRange
function to retrieve the sales data made by sellers between $0 and $200000 from the sales_persons
sorted set using the statement $result = $redis->zRevRange('sales_persons', 0, 200000, true);
.
The statement $redis->zRevRange
returns the sales data as an array, and you're using the PHP foreach(...)
statement to echo
out the name of the salespersons and their associated sales amount. Then, you're using the PHP str_repeat
and str_pad
functions to format the array into a human-readable report.
To test the leaderboard.php
script, execute the leaderboard.php
script using the Linux curl
command.
$ curl http://localhost/leaderboard.php
You should now get the following output. As you can see, JOHN DOE leads in sales followed by MARY PATRICK.
----------------------------------------
SALES RANK BY HIGHEST SELLER
----------------------------------------
RANK NAME SCORE
========================================
1 JOHN DOE 9749
2 MARY PATRICK 7894
3 ESTHER ERIC 6849
4 PETER JACOB 4437
5 PETER MARTIN 3526
6 JANE ERIC 2256
7 MARTHA SMITH 1822
To test whether the leaderboard is able to handle real-time data as it changes, execute the following curl
commands to add 2 more sales records.
$ curl --data "seller=MARTHA KATE&total_sales=3940" http://localhost/zadd.php
$ curl --data "seller=ZABRON JAMES&total_sales=12400" http://localhost/zadd.php
Output.
...
You've successfully added the seller's sales into the Redis server.
Execute the leaderboard.php
script again to check whether the Redis server has updated the rankings.
$ curl http://localhost/leaderboard.php
As you can see from the output below JOHN DOE has been overtaken by ZABRON JAMES.
----------------------------------------
SALES RANK BY HIGHEST SELLER
----------------------------------------
RANK NAME SCORE
========================================
1 ZABRON JAMES 12400
2 JOHN DOE 9749
3 MARY PATRICK 7894
4 ESTHER ERIC 6849
5 PETER JACOB 4437
6 MARTHA KATE 3940
7 PETER MARTIN 3526
8 JANE ERIC 2256
9 MARTHA SMITH 1822
The above output confirms that indeed, the Redis server is well optimized and suitable to handle leaderboards. In a production environment, you should poll the leaderboard.php
script and display the result in a client application after every few seconds to get updated ranks for the salespersons. This would encourage healthy competition as the employees struggle to appear on top of the list.
In this guide, you're using a Redis leaderboard to check and probably reward hardworking salespersons. This logic is very useful in other different scenarios. For instance, if you have a subscription service where you're accepting credit cards, you can use a leaderboard to check the highest-ranking orders originating from a single customer to detect fraud. Similarly, in a multi-author blog, you can use a scoreboard to watch the highest performing bloggers in real-time based on the unique page views or hits originating from their blog posts.
Conclusion
In this guide, you've built a real-time leaderboard script with PHP on a Redis server running on Ubuntu 20.04. Since relational database management systems like MySQL perform sub-optimally for leaderboards, you should use the Redis server since it's optimized to handle thousands of writes per second. Redis in-memory processing was designed with speed in mind and is the most suitable platform for handling thousands of simultaneous users with a near-instant speed.