一文入门Redis主从复制(保姆级别教程)

283 阅读8分钟

1. 引言

抽空学了一下Redis的基本操作。Redis的数据直接存在内存中。相对于磁盘I/O,对内存的存取速度是比较快的。其次,Redis内部运行是单线程的,没有多线程里各种锁来锁去的东西。也就是说,Redis服务端就只有一个线程,而客户端有许多线程,Redis采用了I/O多路复用的技术来处理客户端的请求。总的来说,Redis由于这些优势,使得它读写数据的速度都比较快。因此,在现实应用中常被作为缓存,存储一些经常访问的热数据,比如实时排名等。

Redis的语法很简单,在Java中直接用Jedis操作也可以。但是,关于Redis的一些细节,比如持久化和主从复制等内容比较多。虽然现在还能记得,但是过段时间可能就忘记了。因此打算在这里记录一下关于主从复制的一些相关知识。可能会有表达上或者认知上的错误,望指出,望海涵。

2. 为什么需要主从复制

首先,我们假设就只有一台服务器,我们读数据和写数据都在这台服务器上发生。假如是实验环境,这应该是没啥问题的。但是,在生产环境下,一秒钟的请求数量高达几百几千万请求的时候,这时候我们还是只用一台服务器提供服务,这会给服务器带来很大的压力,同时用户那边也可能会有请求超时的问题。为了解决这个问题,于是有了主从复制这样的设计需求。Redis的主从复制,也可以称之为读写分离。主服务器(Master)主要用于写数据,而从服务器(Slave)主要用于读数据。只有一台主服务器,可以有多台从服务器。酱紫,对于查询请求比较多的生产环境来说,这种一主多从的数据架构是非常合适的。

image.png

3. 一主二仆

在这一节中,我们搭建一个主服务器,两个从服务器的数据架构。由于我只有一台机器,所以在这里我使用三个docker容器来模拟多服务器的主从复制搭建。首先,我们用docker拉取redis镜像,

docker pull redis

然后,我们使用以下命令,查看redis镜像的版本号,

docker image inspect redis:latest|grep -i version

结果显示如下,redis版本为6.2.6。接着,我们下载redis6.2版本的配置文件( wget https://raw.githubusercontent.com/redis/redis/6.2/redis.conf),并将配置文件写进/usr/local/redis路径下的redis6379.conf,redis6380.conf和redis6381.conf中。我们之后启动的docker容器的配置文件将挂载在这个地方。

image.png

在Redis主从复制中,当有一台服务器申请成为从服务器时,会给Master服务器发送一个同步信号。Master收到命令后,会启动后台的存盘进程,该进程对数据进行RDB持久化操作。接着,Master将RDB文件发送给从服务器。从服务器收到RDB文件后,将其存盘并加载至内存,完成一次完全同步。这个过程也称为全量复制。因此,在redis.conf配置文件中,AOF持久化功能可以关闭。并且,我们可以配置RDB文件的存储目录和名字。具体地,我们只需要修改redis.conf中的几个地方,如下,

image.png

image.png

image.png

为了好区分,我们将本地端口6379,6380和6381分别映射至容器redis-6379的6379端口,redis-6380的6380端口和redis-6381的6381端口,如下图。其中,容器redis-*在*端口提供redis服务。

image.png

接着,我们启动三个容器。启动redis-6379容器的命令如下,

docker run -p 6379:6379 --name redis-6379 -v /usr/local/redis/redis6379.conf:/etc/redis/redis.conf -v /usr/local/redis/data6379:/data -d redis redis-server /etc/redis/redis.conf

意思是,将本机的6379端口映射为容器redis-6379的6379端口,容器redis-6379的6379端口提供redis服务。并且将redis配置文件和rdb等数据保存路径挂载在本机的/usr/local/docker/redis6379.conf和/usr/local/docker/data6379中。

使用docker ps查看容器是否成功运行,如下图,说明容器已经开始运行了。

image.png

接着,我们尝试将redis-6379作为Master,redis-6380和redis-6381作为Slave。我们使用docker exec -it redis-6379 redis-cli -p 6379docker exec -it redis-6380 redis-cli -p 6380docker exec -it redis-6381 redis-cli -p 6381登录三个容器的客户端。我们首先通docker inspect redis-6379查看容器redis-6379的IP为172.17.0.2,接着,通过slaveof命令,将redis-6380和redis-6381设置为redis-6379的从服务器,如下图。可见,redis-6379为master,其它两个容器为其slave。

image.png

image.png

我们使用info replication查看各个容器的主从状态,如下,

image.png

image.png

image.png

我们接着做一些尝试。

(1)使用slave服务器写数据会报错

image.png

(2)从服务器redis-6380挂掉后重启,还是redis-6379的从服务器吗?

首先,先shutdown一下redis-6380。接着,使用docker start redis-6380重启。我们使用info replication查看redis-6380的主从状态,如下图。发现,此时它自己变成一个独立的服务器了。也就是说,如果slave宕机,将其重启后,它不会自动地称为master的slave。

image.png

(3)从服务器redis-6380挂掉后,主服务器redis-6379更新数据。redis-6380再次重启并且称为slave,它的数据会同步更新吗?

首先,先shutdown一下redis-6380。接着,在redis-6379中写入若干条数据。此时,redis中存的数据有,

image.png

接着,重启redis-6380,使用slaveof 172.17.0.2 6379设置为redis-6379的slave。我们查看此时redis-6380的数据,如下图。发现,此时它是可以同步到最新数据的。这是因为,redis-6380再次成为slave的时候,它会申请进行全量复制。

image.png

(4)主服务器挂掉的时候,其它从服务器会上位吗?

首先,我们shutdown一下redis-6379。然后,我们查看一下redis-6380和redis-6381的主从状态,如下图。我们会发现,此时的从服务器仍然是slave,它们还是认redis-6379为master的,只不过此时master的状态是“down”。因此,此时的整个系统就变成只读的系统了。

image.png

image.png

4. 哨兵模式

刚刚提到的一主二(多)仆的主从结构存在着一个问题:当主服务器挂掉时,从服务器不会越位。如果没有人工地重启主服务器或者将从服务器设为master时,整个系统将一直保持只读的状态。为了解决这个问题,redis提供了哨兵模式,哨兵监听主服务器,当主服务器挂掉时,通知从服务器竞选出一个master(有种农民翻身做主的意思)。 image.png

我们继续使用上节中的主从模式,即redis-6379为master,redis-6380和redis-6381为slave。接着,我们在这次实验中,设置三个哨兵,在本机上对应的端口为26379,26380和26381。我们使用命令wget http://download.redis.io/redis-stable/sentinel.conf下载sentinel.conf配置文件,并写进/usr/local/redis中的sentinel-26379.conf,sentinel-26380.conf和sentinel-26381.conf。修改配置文件中的端口号,日志文件名字,master的IP和端口号,哨兵同意数量,master失效时间,如下图。其中,哨兵同意数量是指要多少个哨兵同意让能让所选的服务器为master;master失效时间是指master挂掉多少秒后,开始竞选。

image.png

image.png

image.png

使用以下命令启动哨兵容器,

docker run -p 26379:26379 --name sentinel-26379 -v /usr/local/redis/sentinel-26379.conf:/etc/redis/sentinel.conf -v /usr/local/redis/data:/data -d redis redis-sentinel /etc/redis/sentinel.conf

我们使用docker ps查看到,三个哨兵都运行起来了。

image.png

接着,我们进入/usr/local/redis/data查看哨兵日志,如下图。可以看到,日志中清楚地写着此时的master是redis-6379,slaves是redis-6380和redis-6381。(这里会出线蓝框中的warning,目前还没找到解决方法。)

image.png

接着,我们shutdown一下redis-6379。现在,我们使用info replication查看redis-6380和redis-6381的主从状态。发现,此时redis-6380为新的master。

image.png

我们去/usr/local/redis/data中查看哨兵日志。日志上写着具体的竞选过程。并且,我们可以看到,redis-6379变为了状态为“down”的从服务器。

image.png

当我们重启redis-6379时,info-replication显示,此时redis-6379为slave。

image.png

5. 总结

以上便是关于redis主从复制的一些基础相关知识。实操过程中出现了一个问题,即第4节哨兵日志中的warning,目前没有找到解决方法。在线求个懂哥。