RSS

CEK.io

Chris EK, on life as a continually learning software engineer.

An Introduction to Redis

Redis, which got its name as a remote dictionary server, is a key-value data store that can be useful for temporary caching or as a NoSQL (‘not only SQL’) data store.

I recommend getting started with this post about Redis. It’s a little old, but covers some key use cases for Redis. In this post, I will provide an overview to get started with Redis.

Installation

Install Redis using Homebrew by running brew install redis from the command line. Alternatively, complete download instructions can be found here.

Once installed, starting a Redis server is as simple as running redis-server. You’ll know you have it working if you see some ASCII art like what’s depicted on the right.

Code example

You can view a full code example in this Github repo. It’s not really necessary to focus on the controller logic in sinatra_app.rb (it’s there to provide a user interface). This example can be viewed in the browser by running ruby redis_models.rb, starting a Redis server (redis-server), and visiting port 4567.

That said, we can look at the code without serving the example app. The snippet below gives a sense of some basics of Redis, which I’ll walk through line-by-line.

We start with the RedisClient class. This class enables us to create a new instance of the Redis client, connected to localhost:6379, which is the default for Redis servers. (Notice when you run redis-server from the console that we read “of the Redis client, connected to localhost:6379”). Instantiating a Redis client is necessary to work with the Redis server, thus we need the class on lines 6-11.

Side note: what’s happening in line 7 with include Singleton isn’t terribly important at this point. Suffice it to say that the Singleton class is needed when it is necessary to have only one instance of the class. In this case, we need one and only one instance of Redis. The super keyword uses the Redis superclass’ initialize method, which is written into the Redis gem.

So how is Redis being used? Notice some of the main keywords that are unique to Redis: lpush, sadd, and—two of the most fundamental ones—set and get, which we’ll see in more detail. I give an overview of the others at the end of this post.

(redis_book.rb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
require 'redis'
require 'singleton'

BOOK_STRING_ATTRS = %w(title isbn description price pages)

class RedisClient < Redis
  include Singleton
  def initialize
    super
  end
end

class Book
  attr_reader :id
  attr_accessor :title, :isbn, :description, :price, :pages, :authors, :topics

  def initialize(options = {})
    @hub = RedisClient.instance
    # ...
  end

  def self.get(id)
    hub = RedisClient.instance

    if hub.get("book:#{id}:title")
      book = Book.new(:id => id)
    else
      return nil
    end

    book
  end

  def self.get_all
    # ...
  end

  def save
    @hub.lpush('topic:list', @id)
    @hub.set("topic:#{@id}:name", @name)
    @hub.set("topic:#{@id}:description", @description)
    @books.each do |book|
      @hub.sadd("topic:#{id}:books", book)
    end
  end

  def self.remove(id)
    # ...
  end

  def self.get_books_range(start, stop)
    # ...
  end
end

Interacting in IRB

Before we get too bogged down in the code, let’s try this from the command line. Everything I’ve covered up to this point can be done in IRB.

  1. In IRB:
    require redis
    redis = Redis.new(:host => 'localhost', :port => 6379)
  2. In a separate terminal window:
    redis-server
  3. Below we see some of Redis’ magic in setting (Redis SET, aliased by the gem as set) and getting (Redis GET, aliased as get) key-value pairs. We first set a new key-value pair (key of “hello”, value of “world”), then get it by getting that value (with key “hello”). Back in IRB:
    redis.set("hello", "world")
    redis.get("hello") #=> "world"
  4. But what other data types can Redis use? Here we see a hash:
    redis.set(:and_a_hash?, {a:1,b:2,c:3})
    redis.get(:and_a_hash?) #=> "{a:1,b:2,c:3}"
    Note: this returns a string, but can be evaluated: eval("{a:1,b:2,c:3}") #=> {a:1,b:2,c:3}.
  5. Lists, sets, other data types? (http://redis.io/topics/data-types)

Redis data types and commands

There are a number key Redis commands. Below, I define each (Redis.io has more information about data types and commands). Ruby syntax is each Redis command downcase.

Strings: Strings are the most basic kind of Redis value. Redis Strings are binary safe, this means that a Redis string can contain any kind of data, for instance a JPEG image or a serialized Ruby object.
Redis Command      Command Definition
SET      Set the string value of a key
GET      Get the value of a key
INCR      Increment the integer value of a key by one
DECR      Decrement the integer value of a key by one
INCRBY      Increment the integer value of a key by the given amount
APPEND      Append a value to a key
GETRANGE      Get a substring of the string stored at a key
SETRANGE      Overwrite part of a string at key starting at the specified offset
GETBIT      Returns the bit value at offset in the string value stored at key
SETBIT      Sets or clears the bit at offset in the string value stored at key

Lists: Redis Lists are simply lists of strings, sorted by insertion order. It is possible to add elements to a Redis List pushing new elements on the head (on the left) or on the tail (on the right) of the list.
Redis      Command
LPUSH      Prepend one or multiple values to a list
RPUSH      Append one or multiple values to a list

Sets (“S”…): Redis Sets are an unordered collection of Strings. It is possible to add, remove, and test for existence of members in O(1) (constant time regardless of the number of elements contained inside the Set).
Redis      Command
SADD      Add one or more members to a set
SINTER      Intersect multiple sets
SPOP      Remove and return a random member from a set
SRANDMEMBER      Get one or multiple random members from a set

Sorted Sets (“Z”…): Redis Sorted Sets are, similarly to Redis Sets, non repeating collections of Strings. The difference is that every member of a Sorted Set is associated with score, that is used in order to take the sorted set ordered, from the smallest to the greatest score. While members are unique, scores may be repeated.
Redis      Command
ZADD      Add one or more members to a sorted set, or update its score if it already exists
ZRANGE      Return a range of members in a sorted set, by index
ZRANK      Determine the index of a member in a sorted set
ZRANGEBYSCORE      Return a range of members in a sorted set, by score

Wrapping up

That’s a quick intro to Redis. You can try Redis using Redis’ own “Try Redis” command line tutorial, but I prefer setting it up in an application or IRB environment myself.