In Part I we covered some very basic steps to start up a Redis server and connect to it with the redis-cli tool. This is useful information for playing around in your Dev. environment, but doesn’t help us much when its time to move to production. In this post I will start tocover the steps we took to deploy Redis to production, and keep it running smoothly.
When its time to run in production there are generally two primary ways to offer high availability. The older way of doing this is using Redis Sentinel. In this setup you have a Primary (also called the master) and 2 or more Secondaries (also called slaves). All writes must go to the primary, data is then replicated to the secondaries over the network.
You also must have at least 3 more instances of Redis running in sentinel mode. These sentinels monitor the primary (also called the master). If they determine the master is unavailable a new master will be promoted from one of the available secondaries. All other secondaries will automatically be reconfigured to pull from the new master.
There is a bit more to it than this, but that is a sufficient explanation for right now.
In cluster mode we shard reads/writes across multiple instances, and these multiple instances also have Secondaries.
Reads and Writes are distributed across them Primaries by using a computed hash slot. Hash slots are pretty easy to understand if you want to review the Cluster Specification. But suffice it to say that a hash slot is computed based upon the key name, the hash slots are divided between primaries and it is up to the client to route to the correct instance.
Note, when I say Client, I dont mean your application, unless you plan to connect directly Redis and speak the Redis protocols. You’ll likely be using a client library like StackExchange.Redis though
Which One To Choose?
Generally speaking, I think you should just go ahead and choose Redis Cluster if you’re going to be setting this up in a production environment. It gives you the ability to scale horizontally when you need to, and honestly isnt much more difficult to setup than Sentinel. But I’ll cover the setup of both.
Configure Redis Sentinel
I’m going to continue using Docker here. And we’ll assume you have 3 nodes called redis1, redis2, and redis3. If you’re following along on your local machine you can use the following Vagrant file to get started:
Vagrant.configure("2") do |config| config.vm.define "redis1" do |redis1| redis1.vm.box = "bento/ubuntu-16.04" redis1.vm.box_version = "201812.27.0" redis1.vm.provision :shell, path: "bootstrap.sh", :args => "redis1" end config.vm.define "redis2" do |redis2| redis2.vm.box = "bento/ubuntu-16.04" redis2.vm.box_version = "201812.27.0" redis2.vm.provision :shell, path: "bootstrap.sh", :args => "redis2" end config.vm.define "redis3" do |redis3| redis3.vm.box = "bento/ubuntu-16.04" redis3.vm.box_version = "201812.27.0" redis3.vm.provision :shell, path: "bootstrap.sh", :args => "redis3" end end
And here is the bootstrap.sh file mentioned in the above config:
#!/usr/bin/env bash hostnamectl set-hostname $1 echo 127.0.0.1 $1 >> /etc/hosts apt-get update apt-get remove docker docker-engine docker.io containerd runc apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg2 \ software-properties-common -y curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" apt-get update sudo apt-get install docker-ce -y
Now when you run vagrant up, in a few moments you’ll have 3 machines running with docker installed. I’ll be configuring a swarm, like I have in production. So next I need to init the swarm.
vagrant ssh redis1 #wait for connect sudo docker swarm init #copy the join command that gets output by the last command, it'll look like this #sudo docker swarm join --token SWMTKN-1-2wwy0py488uvo6u0lhbpgqpvbhha1kd6w4k1t95uox9m0t4ln0-1fjjc15308hvndpdj8ui7lts9 192.168.10.114:2377
Now you’ll ssh into the other two and join the swarm with the command from the previous example
vagrant ssh redis2 sudo docker swarm join --token SWMTKN-1-2wwy0py488uvo6u0lhbpgqpvbhha1kd6w4k1t95uox9m0t4ln0-1fjjc15308hvndpdj8ui7lts9 192.168.10.114:2377
Repeat that step on 2 and 3
Now we have a running docker swarm with redis1 as our master. The next steps are to create our redis services. We’ll be pinning each redis instance to a specific node. Here are the commands to create the redis services
sudo docker service create --name redis1 --constraint node.hostname==redis1 --hostname redis1 --mode global --publish published=6379,target=6379,mode=host redis:latest sudo docker service create --name redis2 --constraint node.hostname==redis2 --hostname redis2 --mode global --publish published=6379,target=6379,mode=host redis:latest sudo docker service create --name redis3 --constraint node.hostname==redis3 --hostname redis3 --mode global --publish published=6379,target=6379,mode=host redis:latest
We are pinning each instance of Redis to a node b/c we dont want docker to schedule the primary and secondaries to ever be on the same docker host. That would remove some of the high availability we get with running multiple instance.
We now have 3 instances of redis running. You can test connecting to them using the examples from part 1 of this series.
docker run -it redis:latest redis-cli -h 192.168.10.117 #obviously update your ip address
The next step is to enlist redis2 and redis3 as slaves of redis1. To do that we’ll connect to each and run the slaveof command. First ssh into redis 2 and then connect to redis using the docker command above. Then run
slaveof 192.168.10.117 6379 #again, update your IP and port (if you changed the port)
Redis should respond with “OK”
Repeat this step on redis 3
Once this is done you should be able to again connect to the instance of redis on redis1 and run the info replication command:
redis-cli info Replication # Replication role:master connected_slaves:2 slave0:ip=192.168.10.118,port=6379,state=online,offset=322,lag=0 slave1:ip=192.168.10.121,port=6379,state=online,offset=322,lag=1 master_replid:1dcb7819abdce86eeee71021c89bdb075dab8943 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:322 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:322
Whew! Now we have 3 instances of redis running with 1 master and 2 slaves. In the next post we’ll work on getting redis-sentinel up and running to monitor them.