This article is participating in “Java Theme Month – Java Development in Action”, see the activity link for details

Get the Redis image

The docker command pulls the image

docker pull redis

Look at mirror

docker image ls

Get and modify the Redis configuration file

Redis provides a sample configuration file that can be downloaded using the wGET tool.

Wget http://download.redis.io/redis-stable/redis.conf in the allocation of master-slave relationship need only be amended

There are some differences in the configuration files used by the master and slave roles of redis server, as described below.

First of all, configuring the master-slave relationship normally requires multiple machines, but this is often not allowed in reality. So now it’s on a machine.

Make three copies of the downloaded redis.conf file and name them redis-master.conf,redis-slave1.conf, and redis-slave2.conf respectively

cp redis.conf redis-master.conf
cp redis.conf redis-slave1.conf
cp redis.conf redis-slave2.conf
Copy the code

I put the three configuration files in /usr/local/docker-redis/

First modify the master configuration file

vim redis-master.conf

Redis can accept connections from any IP # bind127.0. 01.Daemonize yes # set the password of the master database for authentication. If the requirepass option is enabled for the master library, the corresponding password must be entered here: masterauth <master-password> # Set password (optional, if the password requirement is enabled here, this password will be added to the slave configuration. Requirepass masterPassword: redis logfile: : logfile: : redis logfile: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :"/var/log/redis/redis.log"
Copy the code

If it is a server, redis password is very important, because redis default password vulnerability, there are many people use redis vulnerability to mine your server, experience.

Second, modify the slave configuration.

vim redis-slave1.conf

Redis can accept connections from any IP # bind127.0. 01.Daemonize yes # Set password (optional) Requirepass masterPassword specifies the master database password for authentication. If the requirePass option is enabled for the master library, you must specify the password masterauth <master-password> # to set the master IP and port number. The default port number in the redis configuration file is6379In the lower version of redis, it will be slaveof, which has the same meaning. As slave is a sensitive word, the concept of slave is not used in the later version of redis. Replica # will be used instead35.236172.131.Do the master, the other two machines do the slave. IP and port number based on machine and configuration the IP addresses here look down. replicaof198.18. 02. 6379Redis logfile = logfile"/usr/local/logs/redis.log"
Copy the code

The address of the master node mentioned above is the address of the master Docker container, which can be viewed by running the following command

Docker inspect redis_master # to view the details of the containerCopy the code

Slave2 has the same configuration as above.

Start the container

First, run the master container in background mode, noting the address of the file

docker run -it --name redis-master --network=dockercompose --ip 172.19. 02. -v /data/docker_redis/redis-conf/redis-master.conf:/usr/local/redis/redis.conf -d -p 6379:6379 redis /bin/bash
Copy the code

First, run The Slave1 container in backend mode. Note the address and port number of the file. The port number of the physical machine cannot conflict

$ docker run -it --name redis-master -v /usr/local/docker-redis/redis-slave1.conf:/usr/local/redis/redis.conf -d -p 6380:6379 redis /bin/bash
Copy the code

Slave2 startup same as above

Next go into the container and start the Redis server.

Enter the container Redis-master in interactive mode

docker exec -it redis-master bash
Copy the code

Create a log file directory that is the same as the configuration file

mkdir /usr/local/logs/
touch /usr/local/logs/redis.log
Copy the code

Start the Redis server and if there is no output, it is successful

redis-server /usr/local/redis/redis.conf
Copy the code

Start a Redis client in the container

redis-cli

Enter your password for authentication

127.0. 01.:6379> auth password
Copy the code

Run the info command to check the server status

127.0. 01.:6379> info
Copy the code

If the role is master, the value of this role will be master, and if it is slave, the value of this role will be slave

For slave, also look at the master_link_status property value. If the value of this attribute on the slave is up, it indicates that the master/slave replication is OK; otherwise, there is a problem. If the status of the slave machine is not Up, check whether the ports on the host are limited, and view redis logs to find the cause

Exiting the Client

127.0. 01.:6379> quit
Copy the code

Finally exit the container

exit

Verify the master/slave replication

After the master and slave are set up successfully, you can write a key-value value on the master to check whether the synchronization is performed on the slave

redis-cli
auth password
set test hello
Copy the code

Enter the container on any slave machine and also run a redis-cli to query the value of this key. If the value can be queried and the value is the same as that on the host, the synchronization is successful. After testing, active synchronization is successful.

redis-cli
auth password
get test 
Copy the code

Add the sentry

After the master fails, failover can be performed automatically. One of the slave machines is selected and upgraded to the host, and the original host is monitored continuously. When the original host recovers, it will be used as the slave machine of the new master.

The sentry listens to the master, sends the info command to the master, gets information about the slave, and then listens to the slave. In addition, sentinels subscribe to the main __sentinel__: Hello channel. When a new sentinel joins the channel, a message is sent to the channel. This message contains the IP address and port of the sentinel, and other sentinels that have subscribed to the channel will receive this message. The sentries connect with the newcomers and sentries, and the primary vote is made through this connection. This relationship can be illustrated by the following diagram

Obtain and modify the sentinel configuration file

Run the wget command to obtain the sentinel configuration file

wget http://download.redis.io/redis-stable/sentinel.conf

Modify the following items in the configuration file

vim sentinel.conf

# daemonize yes # change the logfile path to logfile"/var/log/redis/sentinel.log"# Modify the main Redis server monitored # last one2Sentinel Monitor MyMaster indicates that after the two machines are determined to be active or passive, a failover is performed192.18. 02. 6379 2# Master database password, need to put the configuration in sentinel Monitor Master127.0. 01. 6379 1Sentinel Auth-pass myMaster below123456789
Copy the code

Start the container

docker run -it --name sentinel -p 26379:26379 -v /usr/local/docker-redis/sentinel.conf:/usr/local/redis/sentinel.conf -d redis /bin/bash
Copy the code

Run the sentry

Into the container

docker exec -it sentinel bashdocker exec -it sentinel bash
Copy the code

Create log directories and files

mkdir /usr/local/logs
touch /usr/local/logs/sentinel.log
Copy the code

Start the sentinel

redis-sentinel /usr/local/redis/sentinel.conf
Copy the code

Check whether it takes effect.

cat /usr/local/logs/sentinel.log
Copy the code

Verify failover

To verify the automatic master/slave switchover under the Sentry mechanism, we killed the redis process on the master.

doker top reedis-master
Copy the code

Find the PID of redisServer

kill -9 PID
Copy the code

After a few seconds, there will be another machine upgraded from host to host. In the experiment, the third machine, namely Redis-3, will be upgraded to master. If you use the info command, you can see that the role of Redis-3 server becomes master. The automatic primary/secondary switchover succeeds.

How does Python use Redis

But when I use Python USES two problems, the record here: 1, redis. Exceptions. ConnectionError: Error 113 connecting to 172.19.0.3:6379 No route to host. 2, redis. Exceptions. ConnectionError: Error 99 Connecting to 192.168.7.71:6380. Cannot assign requested address.

1. Install redis

pip install redis
Copy the code

2. Implement the connection logic

from redis.sentinel import Sentinel
from redis import WatchError
SENTINEADDRESS = [('192.18.0.2'.26380), ('192.18.0.2'.26381), ('192.18.0.2'.26382)] def 
MYSETINEL = Sentinel(SENTINEADDRESS, socket_timeout=2000) # try to connect the maximum time in milliseconds,1000MASTER = mysetinel.master_for ('mymaster', socket_timeout=2000)
MASTER.set("a"."A")
result=MASTER.get("a")
print(result)
Copy the code

Error:

Redis. Exceptions. ConnectionError: Error 113 connecting to 172.19.0.3:6379 No route to host.

3. Resolve the process of external access to the container IP address

The first thing that comes to mind is that the container IP is unreachable. Two solutions come to mind:

1. After obtaining the container IP address and converting it to a public IP address, establish a connection (only one connection is normal, but frequent connection errors occur) 2. The Python container is constructed.Copy the code

1) Self-transformation (problematic)

# Method of transformation

If s = = "172.19.0.2" : Conn = redis.strictredis (host='192.18.0.2', port=6380, password=" PWD ", Decode_responses =True) return conn elif s=="172.19.0.3": Conn = redis.strictredis (host='192.18.0.2', port=6381, password=" PWD ", decode_responses=True) return conn else: Conn = redis.strictredis (host='192.18.0.2', port=6382, password=" PWD ", decode_responses=True) return conn from redis.sentinel import Sentinel from apps.utils.handler import redis_conn Sentinel = sentinel ([(' 192.18.0.2, 26380), (' 192.18.0.2, 26381), (' 192.18.0.2, 26382)]. Socket_timeout =0.5) master=sentinel. Discover_master ("mymaster") master= redis_conn(master[0]) Results = master.get("a")  print(results)Copy the code

It can be used normally. But I’m running a timed script that requires frequent writes, and that’s when a new problem arises.

Redis. Exceptions. ConnectionError: Error 99 connecting to 192.168.7.71:6380 always assign a requested address. The reason is frequent redis connections. The best way to do that is to connect the sentinels the way they did.

2. Use python containers

This is because I put the sentry inside the method. I’m worried about putting it outside the method. When failover occurs, the myMaster cannot be changed

master = sentinel.master_for('mymaster', socket_timeout=0.5, password='pwd', db=0,decode_responses=True)
Copy the code

After it is taken out, the program automatically switches to the correct node by deliberate failover (killing the master node).

And it works.