Redis - Reliably Deploying Rails Applications: Hassle free provisioning, reliable deployment (2014)

Reliably Deploying Rails Applications: Hassle free provisioning, reliable deployment (2014)

11.4 - Redis

Overview

Redis is, in general, extremely simple to install and manage for small to medium sized projects. Here we’ll cover the basics of installing it using chef as well as key aspects of security and a common gotcha with dataset sizes.

Installation

Simply include the role redis-server which includes the redis-tlq cookbook and an appropriate Monit config from monit_configs-tlq.

Redis-tlq installs redis from a ppa rather than the default from the Ubuntu package manager, you can see more about the ppa along with the current version it has built here: https://launchpad.net/~chris-lea/+archive/redis-server

This repository is generally up to date and always more up to date than the standard Ubuntu repository.

The recipe only has one attribute to be set:

1 "redis": {

2 "dont_bind" : false

3 }

If this is set to true then Redis will accept connections from all hosts (assuming they are allowed through the firewall) rather than the default which limits connections to just those from localhost.

Security

Redis does not include any sort of authentication. By default it binds to 127.0.0.1 which means that only connections originating from the machine it is installed on can access it. If we’ve disabled this binding then any incoming connection which is allowed through the firewall will be allowed complete access to anything store in Redis.

It’s therefore extremely important that if local binding is disabled, for example when Redis is being run on a server of its own, that the Firewall is carefully configured to only allow connections through from trusted servers.

Managing Size

The redis-tlq recipe assumes that Redis is being used primarily as a cache store. Because of this it has the following none-standard configuration at the bottom of redis.conf:

1 # prevent redis from ever using 400MB of memory

2 maxmemory 419430400

3

4 # when max memory is reached, go through all keys and delete the

5 # "least recently used" ones. NOTE: this doesn't do quite what it

6 # sounds like, in practice Redis takes a random sample of keys

7 # (see below) and of the sample it takes, deletes the one which was

8 # least recently used.

9 maxmemory-policy allkeys-lru

10

11 # when looking for a key to expire on maxmem, randomly pick 10

12 # and delete the one with the highest idle time (least recently

13 # accessed)

14 maxmemory-samples 10

This configuration prevents Redis from ever using more than 400mb of memory. If 400Mb is reached and a new key is inserted, Redis will pick a random sample of 10 (maxmemory-samples) and delete the one which has been least recently accessed.

With this option set, Redis behaves a lot like memcached. However it means that no data is safe from deletion. Therefore if you are planning to use Redis as a permanent data store, you should modify the configuration accordingly.

The simple redis-tlq recipe is setup in this way because in my experience the vast majority of Rails applications which use Redis are in fact using it as a cache. Without this behavior configured, it’s surprisingly easy for for the in memory data set to grow hugely in size.

Take for example a common use case; caching geocoder results. If the results are not set to expire automatically (which many of the popular geocoding gems don’t do) then the cache will grow indefinitely whenever a new unique query is performed. If the precision of queries is not limited (a good idea for ‘search in this area’ type queries) this can be a huge volume of new entries every day.

On a single box configuration such as our simple one, where the web server, database server and Redis server all run on the same instance, this can cause significant problems as the Redis set will be kept in memory, gradually causing the system to start swapping and eventually to run out of memory completely.

Monit

monit_configs-tlq::redis-server creates the following simple monit definition for watching the redis process:

1 #Monitoring redis

2 check process redis with pidfile /var/run/redis/redis-server.pid

3 group database

4 start program = "/etc/init.d/redis-server start"

5 stop program = "/etc/init.d/redis-server stop"

6 if 15 restarts within 15 cycles then timeout