民工哥死磕Redis教程(八):主从复制及数据恢复实践

2023-06-0716:49:22数据库教程Comments827 views字数 15732阅读模式

概念

主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称之为主节点(master/leader),后者称之为从节点(slave/flower);数据的复制都是单向的,只能从主节点到从节点。Master 以写为主,Slave 以读为主。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

默认情况下,每台 Redis 服务器都是主节点。且一个主节点可以有多个从节点或者没有从节点,但是一个从节点只能有一个主节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

主从复制的作用

1、数据冗余:主从复制实现了数据的热备份,是持久化的之外的一种数据冗余方式。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。实际也是一种服务的冗余。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写 Redis 数据时应用连接主节点,读 Redis 的时候应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个节点分担读负载,可以大大提高 Redis 服务器的并发量。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

4、高可用(集群)的基石:除了上述作用以外,主从复制还是哨兵模式和集群能够实施的基础,因此说主从复制是 Redis 高可用的基础。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

一般来说,要将Redis 运用于工程项目中,只使用一台 Redis 是万万不能的(可能会宕机),原因如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 1、从结构上,单个 Redis 服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力很大;
  • 2、从容量上,单个 Redis 服务器内存容量有限,就算一台 Redis 服务器内存容量为 265G, 也不能将所有的内存用作 Redis 存储内存,一般来说,单台 Redis最大使用内存不应该超过 20G。

电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点就是“多读少写”。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

对于这种场景,我们可以使用如下这种架构:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

民工哥死磕Redis教程(八):主从复制及数据恢复实践文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

主从复制,读写分离!80% 的情况下,都是在进行读操作。这种架构可以减少服务器压力,经常使用实际生产环境中,最少是“一主二从”的配置。真实环境中不可能使用单机 Redis。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

主从复制原理

注意:在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 全量(同步)复制:比如第一次同步时
  • 增量(同步)复制:只会把主从库网络断连期间主库收到的命令,同步给从库

全量复制

当我们启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 确立主从关系

例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

replicaof 172.16.19.3 6379
  • 全量复制的三个阶段

你可以先看一下下面这张图,有个整体感知,接下来我再具体介绍。民工哥死磕Redis教程(八):主从复制及数据恢复实践第一阶段是主从库间建立连接、协商同步的过程,主要是为全量复制做准备。在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

具体来说,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset,此时设为 -1,表示第一次复制。主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。这里有个地方需要注意,FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

第二阶段,主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。这个过程依赖于内存快照生成的 RDB 文件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

具体来说,主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

第三个阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库。具体的操作是,当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

增量复制

在 Redis 2.8 版本引入了增量复制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 为什么会设计增量复制?

如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 增量复制的流程

你可以先看一下下面这张图,有个整体感知,接下来我再具体介绍。民工哥死磕Redis教程(八):主从复制及数据恢复实践先看两个概念:replication buffer 和 repl_backlog_buffer文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

repl_backlog_buffer:它是为了从库断开之后,如何找到主从差异数据而设计的环形缓冲区,从而避免全量复制带来的性能开销。如果从库断开时间太久,repl_backlog_buffer环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能乖乖地进行一次全量复制,所以repl_backlog_buffer配置尽量大一些,可以降低主从断开后全量复制的概率。而在repl_backlog_buffer中找主从差异的数据后,如何发给从库呢?这就用到了replication buffer。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

replication buffer:Redis和客户端通信也好,和从库通信也好,Redis都需要给分配一个 内存buffer进行数据交互,客户端是一个client,从库也是一个client,我们每个client连上Redis后,Redis都会分配一个client buffer,所有数据交互都是通过这个buffer进行的:Redis先把数据写到这个buffer中,然后再把buffer中的数据发到client socket中再通过网络发送出去,这样就完成了数据交互。所以主从在增量同步时,从库作为一个client,也会分配一个buffer,只不过这个buffer专门用来传播用户的写命令到从库,保证主从数据一致,我们通常把它叫做replication buffer。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 如果在网络断开期间,repl_backlog_size环形缓冲区写满之后,从库是会丢失掉那部分被覆盖掉的数据,还是直接进行全量复制呢?

对于这个问题来说,有两个关键点:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

1.一个从库如果和主库断连时间过长,造成它在主库repl_backlog_buffer的slave_repl_offset位置上的数据已经被覆盖掉了,此时从库和主库间将进行全量复制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

2.每个从库会记录自己的slave_repl_offset,每个从库的复制进度也不一定相同。在和主库重连进行恢复时,从库会通过psync命令把自己记录的slave_repl_offset发给主库,主库会根据从库各自的复制进度,来决定这个从库可以进行增量复制,还是全量复制。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

Redis 主从复制部署实践

环境配置

只配置从库,不用配置主库。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

[root@itzhouc bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> info replication   # 查看当前库的信息
# Replication
role:master         # 角色
connected_slaves:0       # 当前没有从库
master_replid:2467dd9bd1c252ce80df280c925187b3417055ad
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> 

复制 3 个配置文件,然后修改对应的信息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 1、端口
  • 2、pid 名称
  • 3、log 文件名称
  • 4、dump.rdb 名称
port 6381
pidfile /var/run/redis_6381.pid
logfile "6381.log"
dbfilename dump6381.rdb

修改完毕后,启动我们的 3 个 redis 服务器,可以通过进程信息查询。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

[root@itzhouc ~]# ps -ef|grep redis
root       426     1  0 16:53 ?        00:00:00 redis-server *:6379
root       446     1  0 16:54 ?        00:00:00 redis-server *:6380
root       457     1  0 16:54 ?        00:00:00 redis-server *:6381
root       464   304  0 16:54 pts/3    00:00:00 grep --color=auto redis

一主二从环境

默认情况下,每台 Redis 服务器都是主节点,我们一般情况下,只用配置从机就好了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

主机:6379, 从机:6380 和 6381文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

配置的方式有两种:一种是直接使用命令配置,这种方式当 Redis 重启后配置会失效。另一种方式是使用配置文件。这里使用命令演示一下。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

下面将80 和 81 两个配置为在从机。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379  # SLAVEOF host  port
OK
127.0.0.1:6380> info replication
# Replication
role:slave   # 角色已经是从机了
master_host:127.0.0.1 # 主节点地址
master_port:6379   # 主节点端口
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:907bcdf00c69d361ede43f4f6181004e2148efb7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0
127.0.0.1:6380> 

配置好了之后,看主机:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2  # 主节点下有两个从节点
slave0:ip=127.0.0.1,port=6380,state=online,offset=420,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=420,lag=1
master_replid:907bcdf00c69d361ede43f4f6181004e2148efb7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:420
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:420
127.0.0.1:6379> 

真实的主从配置应该是在配置文件中配置,这样才是永久的。这里使用命令是暂时的。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

配置文件 redis.conf文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

################################# REPLICATION #################################

# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
#   +------------------+      +---------------+
#   |      Master      | ---> |    Replica    |
#   | (receive writes) |      |  (exact copy) |
#   +------------------+      +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition replicas automatically try to reconnect to masters
#    and resynchronize with them.
#
# replicaof <masterip> <masterport>   # 这里配置

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
#
# masterauth <master-password>

配置方式也是一样的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

几个问题

1、主机可以写,从机不能写只能读。主机中的所有信息和数据都会保存在从机中。如果从机尝试进行写操作就会报错。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

127.0.0.1:6381> get k1   # k1的值是在主机中写入的,从机中可以读取到。
"v1"
127.0.0.1:6381> set k2 v2   # 从机尝试写操作,报错了
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381> 

2、如果主机断开了,从机依然链接到主机,可以进行读操作,但是还是没有写操作。这个时候,主机如果恢复了,从机依然可以直接从主机同步信息。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

3、使用命令行配置的主从机,如果从机重启了,就会变回主机。如果再通过命令变回从机的话,立马就可以从主机中获取值。这是复制原理决定的。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

复制的两种模式

Slave 启动成功连接到 Master 后会发送一个 sync 同步命令。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

Master 接收到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,master 将传送整个数据文件到 slave ,并完成一次完全同步。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

但是只要重新连接 master ,一次完全同步(全量复制)将被自动执行。我们的数据一定可以在从机中看到。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

这种模式的原理图:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

民工哥死磕Redis教程(八):主从复制及数据恢复实践文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

第二种模式文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

民工哥死磕Redis教程(八):主从复制及数据恢复实践文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

这种模式的话,将 6381 的主节点配置为 6380 。主节点 6379 只有一个从机。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

如果现在 6379 节点宕机了, 6380 和 6381 节点都是从节点,只能进行读操作,都不会自动变为主节点。需要手动将其中一个变为主节点,使用如下命令:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

SLAVEOF no one

redis主从复制危险操作

使用热更新配置误操作

redis主从复制如果使用热更新配置,有时候会因为选错主机把从库误认为主库,结果在主库上执行了slaveof,这样就会导致主库上的数据被清空,因为从库上是没有数据的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

从库在同步主库的时候会把原本自己的数据全部清空。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

误操作过程文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#从库数据为0
127.0.0.1:6379> DBSIZE
(integer) 0
#主库数据为2001
127.0.0.1:6379> DBSIZE
(integer) 2001

#在主库上操作同步本该从库的数据
127.0.0.1:6379> SLAVEOF 192.168.81.220 6379
OK

#再次查看数据,数据已经清空
127.0.0.1:6379> DBSIZE
(integer) 0

避免热更新配置误操作

1.不使用热更新,直接在配置文件里配置主从。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

2.在执行slaveof的时候先执行bgsave,把数据手动备份一下,然后在数据目录,将rdb文件复制成另一个文件,做备份,这样即使出现问题也能即使恢复。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

bgsave之后不用重启,直接备份rdb文件即可。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#手动持久化
127.0.0.1:6379> BGSAVE
Background saving started

#备份rdb文件
[root@redis-1 ~]# cd /data/redis_cluster/redis_6379/
[root@redis-1 /data/redis_cluster/redis_6379]# cd data/
[root@redis-1 /data/redis_cluster/redis_6379/data]# cp redis_6379.rdb redis_6379.rdb.bak

#再次同步错误的主库,造成数据丢失
127.0.0.1:6379> SLAVEOF 192.168.81.220 6379
OK
127.0.0.1:6379> keys *
(empty list or set)

#还原备份的rdb文件,先停掉redis,在还原
[root@redis-1 ~]# redis-cli shutdown
[root@redis-1 /data/redis_cluster/redis_6379/data]# cp redis_6379.rdb.bak redis_6379.rdb

#查看还原后的数据
[root@redis-1 ~]# redis-server /data/redis_cluster/redis_6379/conf/redis_6379.conf 
127.0.0.1:6379> DBSIZE
(integer) 2001

模拟 redis 主从复制错误数据恢复

模拟 redis 主从同步误操作数据恢复。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

大致思路
  • 1.清空两台redis的数据
  • 2.在主库上创建一些数据,然后使用bgsave命令,将数据保存到磁盘,再将磁盘的rdb文件备份
  • 3.再将从库的数据同步过来,模拟主库数据丢失
  • 4.从rdb备份文件还原数据库

这个实验的主要的目的是操作redis备份还原。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

清空数据

两台redis都需要操作,先关闭再删除数据再启动。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

[root@redis-1 ~]# redis-cli shutdown
[root@redis-1 ~]# rm -rf /data/redis_cluster/redis_6379/data/*
[root@redis-1 ~]# redis-server /data/redis_cluster/redis_6379/conf/redis_6379.conf 

[root@redis-1 ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
民工哥死磕Redis教程(八):主从复制及数据恢复实践

在主库批量创建数据并备份

#批量创建数据
[root@redis-1 ~]# for i in {0..2000}; do redis-cli set k_${i} v_${i}; echo "k_${i} is ok"; done
127.0.0.1:6379> DBSIZE
(integer) 2001

#将近数据写入到
127.0.0.1:6379> BGSAVE
Background saving started

#备份rdb文件
[root@redis-1 /data/redis_cluster/redis_6379/data]# cp redis_6379.rdb redis_6379.rdb.bak
[root@redis-1 /data/redis_cluster/redis_6379/data]# ll
总用量 56
-rw-r--r--. 1 root root 27877 1月  28 21:00 redis_6379.rdb
-rw-r--r--. 1 root root 27877 1月  28 21:01 redis_6379.rdb.bak

同步从库的数据造成数据丢失

这时从库的数据应该是空的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

[root@redis-2 ~]# redis-cli 
127.0.0.1:6379> keys *
(empty list or set)

主库同步从库的数据,同步完主库数据丢失,这样就模拟了主库数据丢失的情况。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

127.0.0.1:6379> SLAVEOF 192.168.81.220 6379
OK

127.0.0.1:6379> keys *
(empty list or set)

恢复主库的数据

先关掉redis,还原,最后在开启redis。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#关掉redis
[root@redis-1 ~]# redis-cli shutdown

#还原rdb备份文件
[root@redis-1 /data/redis_cluster/redis_6379/data]# cp redis_6379.rdb.bak redis_6379.rdb
cp:是否覆盖"redis_6379.rdb"?y

#启动redis
[root@redis-1 ~]# redis-server /data/redis_cluster/redis_6379/conf/redis_6379.conf 

#查看数据是否还原
[root@redis-1 ~]# redis-cli 
127.0.0.1:6379> keys *
民工哥死磕Redis教程(八):主从复制及数据恢复实践

模拟线上环境主库宕机故障恢复

思路
  • 1.首先保证主从同步已经配置完成,主库从库都有数据
  • 2.关闭redis主库,模拟redis主库宕机
  • 3.查看redis从库是否还存在数据,是否可读可写(不能写,只能读)
  • 4.关闭从库的slaveof,停止主从同步,将应用连接redis的地址改成从库,保证业务不断
  • 5.修复主库,主库上线后,与从库建立主从复制关系,原来的从库(redis-2)就变成了主库,现在的主库变成了从库(redis-1)这时 关掉应用程序,停止数据写入
  • 6.然后将现在主库(redis-2)的数据同步到现在的从库(redis-1)
  • 7.关闭现在从库(redis-1)的slaveof,停止主从复制,然后将现在主库(redis-2)配置salveof,同步原来的主库(redis-1)
  • 8.数据同步完,原来的主库从库就恢复完毕了

简单明了的一句话:主库因为某种原因宕机无法提供服务了,直接将从库切换成主库提供服务,然后后原来的主库恢复后同步当前主库的数据,然后停掉所有线上运行的程序,将现在的主库去同步恢复后的主库,重新生成主从关系。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

配置主从模拟线上环境

配置主从前先保证主库上面有数据文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#登陆主库redis-1查看是否有数据
[root@redis-1 ~]# redis-cli
127.0.0.1:6379> DBSIZE
(integer) 2001

#登陆从库redis-2查看是否有数据
[root@redis-2 ~]# redis-cli 
127.0.0.1:6379> keys *
(empty list or set)

#从库没有数据的情况下在从库上配置主从,同步主库的数据
127.0.0.1:6379> SLAVEOF 192.168.81.210 6379
OK
#数据已经同步
127.0.0.1:6379> DBSIZE 
(integer) 2001

模拟主库宕机验证从库是否可读写

#直接关掉主库,造成宕机
[root@redis-1 ~]# redis-cli shutdown

#查看从库是否可读写
只能读,不能写
[root@redis-2 ~]# redis-cli get k_1
"v_1"
[root@redis-2 ~]# redis-cli set k999 k_1
(error) READONLY You can't write against a read only slave.

主库一宕机,从库就会一直输出日志提示连接不上主库民工哥死磕Redis教程(八):主从复制及数据恢复实践文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

关闭从库的主从复制保证业务的不间断

现在主库是不可用的,从库也只能读不能写,但是数据只有这么一份了,我们只能关闭从库上的主从复制,让从库变成主库,再配置业务的redis地址,首先要保证业务的不中断文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#关闭从库redis-2的主从同步配置,使其成为主库
[root@redis-2 ~]# redis-cli slaveof no one
OK

#将应用的redis地址修改为从库,只要从库关掉了主从配置,他自己就是一个可读可写的库了,库里有故障前的所有数据,可以先保证业务的不间断

修复故障的主库同步原来从库的数据

修复完主库,已经是有数据的了,为什么还要同步从库的数据呢,因为在主库挂掉的那一瞬间,从库去掉了主从配置,自己已经成了主库,并且也提供了一段时间的数据写入,这时从库的数据时最完整的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

同步现在主库(原来的从库)的数据时,先要将应用关掉,不要在往里写数据了文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

在主库(原来的从库上)写入几个新的数据,模拟产生的新数据文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

[root@redis-2 ~]# redis-cli 
127.0.0.1:6379> set zuixinshujv vvvvv
OK

在重新上线的主库上配置主从同步,使自己变成从库,同步主库的(原来的从库)数据文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

同步之后,现在从库(重新修复的主库已经有最新数据了)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

同步之前先将应用停掉,不要再往redis中写数据
[root@redis-1 ~]# redis-cli 
127.0.0.1:6379> SLAVEOF 192.168.81.220 6379
OK
127.0.0.1:6379> get zuixinshujv
"vvvvv"

从库重新上线为主库

这里的从库重新上线指的就是原来故障的主库,现在已经同步到最新数据了,因此要上线成为主库,之前选他作为主库就是因为他的性能比从库各方面都要高,避免将来因为性能再次发生故障,因此要切换文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

#关闭从库(原来的主库)的主从配置
[root@redis-1 ~]# redis-cli 
127.0.0.1:6379> SLAVEOF no one
OK

#在主库(原来的从库)配置主从复制
[root@redis-2 ~]# redis-cli 
127.0.0.1:6379> SLAVEOF 192.168.81.210 6379
OK

将应用的redis地址再次修改为主库的地址

目前主库已经恢复了,并且主从之前重新建立了主从同步关系,现在就可以把应用的redis地址修改为主库,启动应用就可以了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

更深入理解 Redis 主从复制

我们通过几个问题来深入理解主从复制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

当主服务器不进行持久化时复制的安全性

在进行主从复制设置时,强烈建议在主服务器上开启持久化,当不能这么做时,比如考虑到延迟的问题,应该将实例配置为避免自动重启。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

为什么不持久化的主服务器自动重启非常危险呢?为了更好的理解这个问题,看下面这个失败的例子,其中主服务器和从服务器中数据库都被删除了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 我们设置节点A为主服务器,关闭持久化,节点B和C从节点A复制数据。
  • 这时出现了一个崩溃,但Redis具有自动重启系统,重启了进程,因为关闭了持久化,节点重启后只有一个空的数据集。
  • 节点B和C从节点A进行复制,现在节点A是空的,所以节点B和C上的复制数据也会被删除。
  • 当在高可用系统中使用Redis Sentinel,关闭了主服务器的持久化,并且允许自动重启,这种情况是很危险的。比如主服务器可能在很短的时间就完成了重启,以至于Sentinel都无法检测到这次失败,那么上面说的这种失败的情况就发生了。

如果数据比较重要,并且在使用主从复制时关闭了主服务器持久化功能的场景中,都应该禁止实例自动重启。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

为什么全量复制使用RDB而不使用AOF?

1、RDB文件内容是经过压缩的二进制数据(不同数据类型数据做了针对性优化),文件很小。而AOF文件记录的是每一次写操作的命令,写操作越多文件会变得很大,其中还包括很多对同一个key的多次冗余操作。在主从全量数据同步时,传输RDB文件可以尽量降低对主库机器网络带宽的消耗,从库在加载RDB文件时,一是文件小,读取整个文件的速度会很快,二是因为RDB文件存储的都是二进制数据,从库直接按照RDB协议解析还原数据即可,速度会非常快,而AOF需要依次重放每个写命令,这个过程会经历冗长的处理逻辑,恢复速度相比RDB会慢得多,所以使用RDB进行主从全量复制的成本最低。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

2、假设要使用AOF做全量复制,意味着必须打开AOF功能,打开AOF就要选择文件刷盘的策略,选择不当会严重影响Redis性能。而RDB只有在需要定时备份和主从全量复制数据时才会触发生成一次快照。而在很多丢失数据不敏感的业务场景,其实是不需要开启AOF的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

为什么还有无磁盘复制模式?

Redis 默认是磁盘复制,但是如果使用比较低速的磁盘,这种操作会给主服务器带来较大的压力。Redis从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

无磁盘复制模式:master 创建一个新进程直接 dump RDB 到slave的socket,不经过主进程,不经过硬盘。适用于disk较慢,并且网络较快的时候。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

使用repl-diskless-sync配置参数来启动无磁盘复制。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

使用repl-diskless-sync-delay 参数来配置传输开始的延迟时间;master等待一个repl-diskless-sync-delay的秒数,如果没slave来的话,就直接传,后来的得排队等了; 否则就可以一起传。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

为什么还会有从库的从库的设计?

通过分析主从库间第一次数据同步的过程,你可以看到,一次全量复制中,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

如果从库数量很多,而且都要和主库进行全量复制的话,就会导致主库忙于 fork 子进程生成 RDB 文件,进行数据全量复制。fork 这个操作会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢。此外,传输 RDB 文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力。那么,有没有好的解决方法可以分担主库压力呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

其实是有的,这就是“主 - 从 - 从”模式。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

在刚才介绍的主从库模式中,所有的从库都是和主库连接,所有的全量复制也都是和主库进行的。现在,我们可以通过“主 - 从 - 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

简单来说,我们在部署主从集群的时候,可以手动选择一个从库(比如选择内存资源配置较高的从库),用于级联其他的从库。然后,我们可以再选择一些从库(例如三分之一的从库),在这些从库上执行如下命令,让它们和刚才所选的从库,建立起主从关系。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

replicaof 所选从库的IP 6379

这样一来,这些从库就会知道,在进行同步时,不用再和主库进行交互了,只要和级联的从库进行写操作同步就行了,这就可以减轻主库上的压力,如下图所示:民工哥死磕Redis教程(八):主从复制及数据恢复实践级联的“主-从-从”模式好了,到这里,我们了解了主从库间通过全量复制实现数据同步的过程,以及通过“主 - 从 - 从”模式分担主库压力的方式。那么,一旦主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,可以避免频繁建立连接的开销。更多关于 Redis 学习的文章,请参阅:NoSQL 数据库系列之 Redis ,本系列持续更新中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

读写分离及其中的问题

在主从复制基础上实现的读写分离,可以实现Redis的读负载均衡:由主节点提供写服务,由一个或多个从节点提供读服务(多个从节点既可以提高数据冗余程度,也可以最大化读负载能力);在读负载较大的应用场景下,可以大大提高Redis服务器的并发量。下面介绍在使用Redis读写分离时,需要注意的问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 延迟与不一致问题

前面已经讲到,由于主从复制的命令传播是异步的,延迟与数据的不一致不可避免。如果应用对数据不一致的接受程度程度较低,可能的优化措施包括:优化主从节点之间的网络环境(如在同机房部署);监控主从节点延迟(通过offset)判断,如果从节点延迟过大,通知应用不再通过该从节点读取数据;使用集群同时扩展写负载和读负载等。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

在命令传播阶段以外的其他情况下,从节点的数据不一致可能更加严重,例如连接在数据同步阶段,或从节点失去与主节点的连接时等。从节点的slave-serve-stale-data参数便与此有关:它控制这种情况下从节点的表现;如果为yes(默认值),则从节点仍能够响应客户端的命令,如果为no,则从节点只能响应info、slaveof等少数命令。该参数的设置与应用对数据一致性的要求有关;如果对数据一致性要求很高,则应设置为no。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 数据过期问题

在单机版Redis中,存在两种删除策略:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 惰性删除:服务器不会主动删除数据,只有当客户端查询某个数据时,服务器判断该数据是否过期,如果过期则删除。
  • 定期删除:服务器执行定时任务删除过期数据,但是考虑到内存和CPU的折中(删除会释放内存,但是频繁的删除操作对CPU不友好),该删除的频率和执行时间都受到了限制。

在主从复制场景下,为了主从节点的数据一致性,从节点不会主动删除数据,而是由主节点控制从节点中过期数据的删除。由于主节点的惰性删除和定期删除策略,都不能保证主节点及时对过期数据执行删除操作,因此,当客户端通过Redis从节点读取数据时,很容易读取到已经过期的数据。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

Redis 3.2中,从节点在读取数据时,增加了对数据是否过期的判断:如果该数据已过期,则不返回给客户端;将Redis升级到3.2可以解决数据过期问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

  • 故障切换问题

在没有使用哨兵的读写分离场景下,应用针对读和写分别连接不同的Redis节点;当主节点或从节点出现问题而发生更改时,需要及时修改应用程序读写Redis数据的连接;连接的切换可以手动进行,或者自己写监控程序进行切换,但前者响应慢、容易出错,后者实现复杂,成本都不算低。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

总结

在使用读写分离之前,可以考虑其他方法增加Redis的读负载能力:如尽量优化主节点(减少慢查询、减少持久化等其他情况带来的阻塞等)提高负载能力;使用Redis集群同时提高读负载能力和写负载能力等。如果使用读写分离,可以使用哨兵,使主从节点的故障切换尽可能自动化,并减少对应用程序的侵入。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html

参考文章:https://jiangxl.blog.csdn.net/article/details/120646992 https://www.cnblogs.com/itzhouq/p/redis5.html
https://www.pdai.tech/md/db/nosql-redis/db-redis-x-copy.html
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/45571.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/sjk/45571.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定