Redis Durability Test

5 Dec 2015

I'm using a custom-compiled Redis as detailed here.

Wow. Redis inserts are crazy fast. Of course, with those crazy fast inserts, obviously a lot of buffering is going on, though.

As with all the previous durability tests, let's turn on our consumer SSD's write-through feature (see the first post on the page for details):

# ./set-write-through.sh 

In root's home dir, here is a script to kill redis, kill-redis.sh.

#!/bin/bash

set -e
set -o pipefail
set -u

PGPID=$(cat /usr/local/redis-3.0.5/var/redis_6379.pid)

kill -9 ${PGPID}

In your regular user's home directory, here is a script to get the integers successfully written to Redis, get-last-written.sh.

#!/bin/bash

set -u
set -e
set -o pipefail

# Interesting. The max integer is at the lowest offset
echo "max integer"
/usr/local/redis-3.0.5/bin/redis-cli lindex test_ints 0

# ...and the min integer is at the highest offset
MX=$(/usr/local/redis-3.0.5/bin/redis-cli llen test_ints)
MX=$(( MX - 1 ))
echo "min integer"
/usr/local/redis-3.0.5/bin/redis-cli lindex test_ints ${MX}

echo "number of integers"
/usr/local/redis-3.0.5/bin/redis-cli llen test_ints

In your regular user's go/src directory, (such as ${HOME}/go/src/github.com/foo/redis-durability/insert-ints), create this main.go file:

package main

import (
	"fmt"
	"os"

	"github.com/mediocregopher/radix.v2/redis"
)

func main() {
	client, err := redis.Dial("tcp", "localhost:6379")
	defer closeClient(client)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not connect to  redis: %v\n", err)
		os.Exit(1)
	}
	err = client.Cmd("del", "test_ints").Err
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not delete test_ints array: %v\n", err)
		os.Exit(1)
	}
	i := 0
	for {
		i++
		err = client.Cmd("lpush", "test_ints", i).Err
		if err != nil {
			fmt.Fprintf(os.Stderr, "Did not insert %d\n", i)
			os.Exit(1)
		}
		fmt.Printf("inserted %d\n", i)
	}
}

func closeClient(client *redis.Client) {
	if client != nil {
		client.Close()
	}
}

Build the above go file.

$ cd go/src/github.com/manniwood/redis-durability/insert-ints
$ go get github.com/mediocregopher/radix.v2
$ go build

Now you've got everything you need.

In a root terminal, set your consumer hard drive to not cache writes, but to write them to permantent storage immediately. (With most consumer hard drives, this setting will be forgotten after a reboot, so don't worry about wearing out your hard drive fater.):

# ./set-write-through.sh

Next, be sure Redis is running. Also run this command in a root terminal:

# systemctl start redis-6379

Let's run our go command to insert ints into Redis in a loop. This can be run in a regular user's terminal:

$ ./insert-ints

Now let's return to our root terminal and kill Redis while it is running:

# ./kill-redis.sh
# systemctl status redis-6379

The second command, above, should show us that PostgreSQL was killed.

Also, back in your regular user's terminal, you should see that the go program exited like this:

...
inserted 31876
inserted 31877
inserted 31878
inserted 31879
Did not insert 31880

Now let's prove to ourselves that Redis saved all of our writes to disc... or not!

# systemctl start redis-6379
# ./get-last-written.sh
max integer
"659"
min integer
"1"
number of integers
(integer) 659

With default durability settings, Redis works as advertised. A lot of buffering happens with writes, and a small percentage of our writes made it into Redis.