在现代的软件开发中,数据的可靠性和可用性是至关重要的。Redis,作为一个开源的、内存中的数据结构存储系统,以其出色的性能和灵活的数据结构,赢得了开发者们的广泛喜爱。而 Redis 的主从复制功能,更是为我们提供了一种简单有效的方式来提高数据的可靠性和可用性。今天,我们要探讨的是 Redis 的主从复制集群。
主从复制集群是一种常见的数据库集群架构,它包含一个主服务器和多个从服务器。主服务器负责处理写操作,所有的写操作会被复制到从服务器。从服务器主要用于处理读操作,分担读负载。通过这种方式,我们可以在多台服务器上读取相同的数据,提高读取性能,同时也可以防止数据丢失。
在接下来的文章中,我们将详细介绍 Redis 的主从复制集群,包括它的工作原理,如何搭建和配置,以及一些常见的使用场景。无论你是刚接触 Redis,还是已经有一定的使用经验,我相信你都能从这篇文章中学到一些新的知识。
Redis 主从复制是 Redis 数据备份和高可用性的重要机制之一。主从复制允许你有一个或多个从服务器复制主服务器的数据。这样,你可以在多个服务器上读取相同的数据,提高读取性能,同时也可以防止数据丢失。
以下是 Redis 主从复制的基本步骤:
配置从服务器:你可以通过在从服务器上执行 SLAVEOF
命令来配置从服务器。这将使从服务器开始监听主服务器,准备复制数据。
数据同步:一旦从服务器接收到 SLAVEOF
命令,它将开始一个同步过程。在这个过程中,主服务器会创建一个当前数据的快照并将其发送给从服务器。
命令复制:数据同步完成后,主服务器会继续在接收到写命令时将其发送给所有从服务器。这样,所有的从服务器都能实时地保持和主服务器一致的数据。
读取数据:你可以配置应用程序从从服务器读取数据,以此来分担主服务器的读取负载。
故障转移:如果主服务器出现故障,你可以手动或通过 Sentinel 系统自动将一个从服务器提升为新的主服务器。
注意:在 Redis 4.0 以后,SLAVEOF
命令已经被 REPLICAOF
命令替代,但是为了向后兼容,SLAVEOF
命令仍然可以使用。
Redis 主从复制的主要作用有以下几点:
Redis 的复制拓扑结构可以支持单层或多层复制关系,根据拓扑复杂性可以分为以下三种:一主一从、一主多从、树状主从结构。
主从复制虽好,但也存在一些问题:
Redis主从复制的工作流程大概可以分为如下几步:
(全量复制)Redis 同步数据集的主要步骤就是发送和加载数据快照。具体来说,包括以下步骤:
主服务器生成数据快照:当主服务器接收到从服务器的同步请求后,会开始在后台生成一个数据快照(RDB 文件)。这个数据快照包含了主服务器在接收到同步请求时的所有数据。
主服务器发送数据快照:数据快照生成后,主服务器会将这个快照文件发送给从服务器。同时,主服务器还会将生成数据快照期间接收到的所有写命令缓存起来。
从服务器加载数据快照:从服务器接收到数据快照后,会清空旧数据,然后加载这个数据快照。这样,从服务器的数据就和主服务器在生成数据快照时的数据一致了。
主服务器发送缓存的写命令:数据快照发送完毕后,主服务器会将生成数据快照期间缓存的写命令发送给从服务器。从服务器执行这些写命令后,就和主服务器的当前数据状态一致了。
以上就是 Redis 同步数据集的主要步骤。需要注意的是,从 Redis 2.8 版本开始,Redis 使用了一种叫做部分重同步(PSYNC)的机制,可以使得在网络连接断开后,从服务器只需要复制断开期间主服务器上发生变化的部分,而不需要重新复制所有数据,大大提高了复制的效率。
(部分复制)在 Redis 主从复制过程中,如果主从服务器之间的连接断开,从服务器会尝试重新连接主服务器,并重新开始同步过程。具体来说,包括以下步骤:
检测连接断开:从服务器会定期检测与主服务器的连接状态。如果检测到连接已经断开,从服务器会尝试重新连接主服务器。
重新连接主服务器:从服务器会尝试重新连接主服务器。如果连接失败,从服务器会在一段时间后再次尝试,直到连接成功。
请求同步:一旦重新连接成功,从服务器会向主服务器发送一个同步请求。这个请求会告诉主服务器,从服务器需要的数据的起始位置。
部分重同步:如果可能,主服务器会进行部分重同步。也就是说,主服务器只会发送从服务器缺失的数据,而不是所有数据。这是通过在主服务器上维护一个缓冲区实现的,这个缓冲区保存了最近的写命令。如果从服务器请求的数据都在这个缓冲区内,主服务器就可以进行部分重同步。
全量重同步:如果部分重同步无法进行,例如缓冲区的数据已经被覆盖,或者从服务器是第一次进行同步,主服务器就会进行全量重同步。也就是说,主服务器会发送所有数据给从服务器。
以上就是 Redis 主从复制进行断线重连的主要步骤。通过这种机制,Redis 可以在网络连接不稳定的情况下,保证数据的一致性。
Redis 在 2.8 及以上版本使用 psync
命令完成主从数据同步,同步过程分为:全量复制和部分复制。
一般用于初次复制场景,Redis 早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。
全量复制的完整运行流程如下:
psync
命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行ID,所以发送 psync-1
;psync-1
解析出当前为全量复制,回复 +FULLRESYNC
响应;bgsave
保存 RDB 文件到本地;bgrewriteaof
(异步 AOF 重写命令)操作,为了保证全量复制后 AOF 持久化文件立刻可用。部分复制主要是 Redis 针对全量复制的过高开销做出的一种优化措施,使用 psync{runId}{offset}
命令实现。当从节点(slave)正在复制主节点(master)时,如果出现网络闪断或者命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,如果主节点的复制积压缓冲区内存在这部分数据则直接发送给从节点,这样就可以保持主从节点复制的一致性。
全量复制的完整运行流程如下:
psync
参数发送给主节点,要求进行部分复制操作;psync
命令后首先核对参数 runId 是否与自身一致,如果一致,说明之前复制的是当前主节点;之后根据参数 offset 在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送 +CONTINUE
响应,表示可以进行部分复制;这里我们基于 Docker 搭建一个 Redis 主从模式集群
拉取 Redis 镜像:
docker pull redis
创建所需文件夹,用于映射容器相应文件路径:
mkdir -p ~/data/redis/master/data
touch ~/data/redis/master/redis.confmkdir
touch ~/data/redis/master/redis.conf
mkdir -p ~/data/redis/slave-1/data
touch ~/data/redis/slave-1/redis.confmkdir
touch ~/data/redis/slave-1/redis.conf
mkdir -p ~/data/redis/slave-2/data
touch ~/data/redis/slave-2/redis.confmkdir
touch ~/data/redis/slave-2/redis.conf
运行容器并指定挂载路径:
docker run -p 16379:6379 --name redis-master -v ~/data/redis/master/data/:/data -v ~/data/redis/master/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf --appendonly yes
---
docker run -p 26379:6379 --name redis-slave-1 -v ~/data/redis/slave-1/data/:/data -v ~/data/redis/slave-1/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf --appendonly yes
---
docker run -p 36379:6379 --name redis-slave-2 -v ~/data/redis/slave-2/data/:/data -v ~/data/redis/slave-2/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf --appendonly yes
通过 Docker Desktop 查看:
这种搭建模式在重启容器之后将被重置,看个人情况考虑搭建
可以通过以下命令查看节点IP
docker inspect [CONTAINER ID]
docker inspect [CONTAINER ID]
是一个 Docker 命令,用于获取 Docker 对象的详细信息。这个 Docker 对象可以是一个容器、镜像、网络或者卷。这个命令的各个部分的含义如下:
docker inspect
:这是 Docker 的一个命令,用于获取 Docker 对象的详细信息。[CONTAINER ID]
:这是你要获取信息的 Docker 对象的 ID。你需要将其替换为实际的对象 ID。所以,
docker inspect [CONTAINER ID]
命令的作用就是获取指定容器的详细信息,包括容器的配置、网络设置、挂载的卷等等。这个命令返回的是一个 JSON 格式的数据,你可以通过这个数据来查看容器的各种详细信息。
分别进入 slave-1,slave-2 从节点,将该节点设置为主节点的从属节点:
# 进入从节点服务
docker exec -it [CONTAINER ID] redis-cli
docker exec -it [CONTAINER ID] redis-cli
是一个 Docker 命令,用于在运行的 Redis 容器中启动一个 redis-cli 客户端。这个命令的各个部分的含义如下:
docker exec
:这是 Docker 的一个命令,用于在运行的容器中执行一个命令。-it
:这是docker exec
命令的两个选项,-i
(或--interactive
)表示保持 STDIN 打开,-t
(或--tty
)表示分配一个伪终端。这两个选项通常一起使用,可以让你交互地运行命令。[CONTAINER ID]
:这是你要在其中运行命令的容器的 ID。你需要将其替换为实际的容器 ID。redis-cli
:这是你要在容器中运行的命令,也就是启动 redis-cli 客户端。
# 将该节点设置为主节点的从属节点,
slaveof 172.17.0.2 6379
此时再次查看主节点的角色信息和主从复制信息:
# 查看角色信息
role
# 查看主从复制信息
info replication
此时再次查看从节点的角色信息和主从复制信息:
# 查看角色信息
role
# 查看主从复制信息
info replication
这种搭建模式在重启容器之后不会被重置,看个人情况考虑搭建。
修改 redis-master 配置文件:
# 修改之前挂载的 redis 的配置文件
vim ~/data/redis/master/redis.conf
在 redis.conf 里加入以下内容:
# 允许所有ip地址访问
bind 0.0.0.0
# 以守护进程的方式运行,就是关闭了远程连接窗口,redis依然运行,使用容器时必须注释,否则启动容器失败
# daemonize yes
# 设置需要密码才能访问
requirepass root
# 设置redis持久化,默认是no
appendonly yes
# 设置主节点的密码(当主节点设置了requirepass配置时需要配置该项或者需要搭建哨兵模式的时候也需要配置该项,因为如果主节宕机重启之后就会# # 装换为slave节点,这个时候需要去连接sentinel选举出来的新的master节点)
# masterauth root
修改 redis-slave-1 配置文件:
#修改之前挂载的redis的配置文件
vim ~/data/redis/slave-1/redis.conf
# 允许所有ip地址访问
bind 0.0.0.0
# 以守护进程的方式运行,就是关闭了远程连接窗口,redis依然运行,使用容器时必须注释,否则启动容器失败
# daemonize yes
# 设置需要密码才能访问
requirepass root
# 设置redis持久化,默认是no
appendonly yes
# 设置主节点的密码(当主节点设置了requirepass配置时需要配置该项)
masterauth root
# 主从模式下主节点的IP和PORT(这里要根据实际情况来定,我这里使用的是容器内部的IP和端口)
#容器内部ip和端口可以使用 docker inspect 镜像id来查看
# 这里也可以使用容器的名称,使用容器名称的时候在构建容器的时候就需要使用--link参数
# 这里也可以使用物理地址,使用物理地址的时候在构建容器的时候就需要使用--net参数
replicaof 172.17.0.3 6379
修改 redis-slave-2 配置文件:
#修改之前挂载的redis的配置文件
vim ~/data/redis/slave-2/redis.conf
# 允许所有ip地址访问
bind 0.0.0.0
# 以守护进程的方式运行,就是关闭了远程连接窗口,redis依然运行,使用容器时必须注释,否则启动容器失败
# daemonize yes
# 设置需要密码才能访问
requirepass root
# 设置redis持久化,默认是no
appendonly yes
# 设置主节点的密码(当主节点设置了requirepass配置时需要配置该项)
masterauth root
# 主从模式下主节点的IP和PORT(这里要根据实际情况来定,我这里使用的是容器内部的IP和端口)
#容器内部ip和端口可以使用 docker inspect 镜像id来查看
# 这里也可以使用容器的名称,使用容器名称的时候在构建容器的时候就需要使用--link参数
# 这里也可以使用物理地址,使用物理地址的时候在构建容器的时候就需要使用--net参数
replicaof 172.17.0.3 6379
重启 Redis 主节点和从节点容器
docker restart redis-master redis-slave-1 redis-slave-2
验证是否搭建成功,这里我们看一下主节点
#进入redis-master主节点
docker exec -it redis-master redis-cli
#输入密码验证root
auth root
#查看实例所属角色
role
查看主从复制信息
info replication