Tracking peak users online with Redis

This probably isn’t the best way to track things, but it’s the best I came up
with. Tracking the total number of users that log in per day or month is trivial
as I have discussed in a previous post. To track the peak users online at
a given time requires a bit more thought.

The major issue for me is that I don’t necessarily want to be slamming Redis on
every page view, so I end up throttling the writes to every couple of minutes.
Delay aside, I have come up with two ways to track the peak number of users. One
method results in more data being stored while the other ends up with a small
bit of computation. YMMV and you should utilize a method that makes the most
sense for your current scale.

The first method is to write to a sorted set periodically with the number of
users online. You can then pull the peak number of users by grabbing the member
with the largest score:

ZADD :key :score: :member

:key is your key (I’d name it something like ns:users:online:peak:20151224).
:score is how many users were online at that moment and :member would be the
current timestamp (CCYYMMDDHHMMSS).

To grab the highest value for the day (or whatever period you’re using) you
would run:

ZREVRANGE :key 0 0 WITHSCORES

Which would return the :member and :score for the member with the highest
score. You could break this up by hour, day, week, year, whatever. Could even
write to multiple keys at once to create something a bit more like a time
series.

The next method, and the method I am currently using on one of my sites is to
keep a value, sanity checking if the new value is larger and if so, overwriting
it. The reason I took this approach is because I wanted to store the values in a
hash to avoid key bloat.

As mentioned, this method requires a bit more logic as you have to retrieve the
stored value, compare it to the current value and if the current value is
greater, go ahead and store that. I’m sure this additional logic adds a small
bit of margin of error, but like I said, it reduces some of the key bloat and in
my opinion, makes it a ton easier to pull multiple day’s peak values without
pipelining.

First, you need to get the stored value:

HGET :key :period

As before, :period can be whatever period you want it to be, I tend to use the
current date as I like having peak user data broken out by day. The :key can
be something like ns:users:online:peak.

Once you have this value, you’ll need to compare it to the current value (this
is a code agnostic post, I trust that you know how to compare variables ;). If
the current value is larger than the value we retrieved, you will need to write
the current value back out:

HSET :key :period: :users

Where :users is the current number of users online.

That’s pretty much it, both methods allow you to track the peak number of users
per day. If so desired, you could run this on every single page load, but I find
that both methods would introduce quite a bit of unnecessary overhead.

Assuming you don’t prune the keys for the first method, you could end up with a
better picture of your site’s daily usage whereas the second method only shows
you the peak.

As mentioned, you have to choose the method that best fits your use case. If
you’ve come up with a better method of tracking, I’d love to hear about it, hit
me up in the comments below!

Oh! and by the way, Merry Christmas 🙂

Josh Sherman - The Man, The Myth, The Avatar

About Josh

Husband. Father. Pug dad. Musician. Founder of Holiday API, Head of Engineering and Emoji Specialist at Mailshake, and author of the best damn Lorem Ipsum Library for PHP.


If you found this article helpful, please consider buying me a coffee.