10分钟彻底理解Redis持久化和主从复制

可莉
• 阅读 713

在这篇文章,我们一起了解 Redis 使用中非常重要的两个机制:Reids 持久化和主从复制。

什么是 Redis 持久化?

Redis 作为一个键值对内存数据库(NoSQL),数据都存储在内存当中,在处理客户端请求时,所有操作都在内存当中进行,如下所示10分钟彻底理解Redis持久化和主从复制

这样做有什么问题呢?其实,只要稍微有点计算机基础知识的人都知道,存储在内存当中的数据,只要服务器关机(各种原因引起的),内存中的数据就会消失了。

不仅服务器关机会造成数据消失,Redis 服务器守护进程退出,内存中的数据也一样会消失。10分钟彻底理解Redis持久化和主从复制

对于只把 Redis 当缓存来用的项目来说,数据消失或许问题不大,重新从数据源把数据加载进来就可以了。

但如果直接把用户提交的业务数据存储在 Redis 当中,把 Redis 作为数据库来使用,在其放存储重要业务数据,那么 Redis 的内存数据丢失所造成的影响也许是毁灭性。

为了避免内存中数据丢失,Redis 提供了对持久化的支持,我们可以选择不同的方式将数据从内存中保存到硬盘当中,使数据可以持久化保存。

10分钟彻底理解Redis持久化和主从复制

Redis 提供了 RDB 和 AOF 两种不同的数据持久化方式,下面我们就来详细介绍一下这种不同的持久化方式吧。

RDB

RDB 是一种快照存储持久化方式,具体就是将 Redis 某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为 dump.rdb,而在 Redis 服务器启动时,会重新加载 dump.rdb 文件的数据到内存当中恢复数据。

①开启 RDB 持久化方式

开启 RDB 持久化方式很简单,客户端可以通过向 Redis 服务器发送 Save 或 Bgsave 命令让服务器生成 RDB 文件,或者通过服务器配置文件指定触发 RDB 条件。

save 命令:是一个同步操作。
# 同步数据到磁盘上
> save

10分钟彻底理解Redis持久化和主从复制

10分钟彻底理解Redis持久化和主从复制

当客户端向服务器发送 Save 命令请求进行持久化时,服务器会阻塞 Save 命令之后的其他客户端的请求,直到数据同步完成。

如果数据量太大,同步数据会执行很久,而这期间 Redis 服务器也无法接收其他请求,所以,最好不要在生产环境使用 Save 命令。

Bgsave:与 Save 命令不同,Bgsave 命令是一个异步操作。
# 异步保存数据集到磁盘上
> bgsave

10分钟彻底理解Redis持久化和主从复制

当客户端发服务发出 Bgsave 命令时,Redis 服务器主进程会 Forks 一个子进程来数据同步问题,在将数据保存到 RDB 文件之后,子进程会退出。

所以,与 Save 命令相比,Redis 服务器在处理 Bgsave 采用子线程进行 IO 写入。

而主进程仍然可以接收其他请求,但 Forks 子进程是同步的,所以 Forks 子进程时,一样不能接收其他请求。

这意味着,如果 Forks 一个子进程花费的时间太久(一般是很快的),Bgsave 命令仍然有阻塞其他客户的请求的情况发生。

服务器配置自动触发:除了通过客户端发送命令外,还有一种方式,就是在 Redis 配置文件中的 Save 指定到达触发 RDB 持久化的条件,比如【多少秒内至少达到多少写操作】就开启 RDB 数据同步。

例如我们可以在配置文件 redis.conf 指定如下的选项:

# 900s内至少达到一条写命令
save 900 1
# 300s内至少达至10条写命令
save 300 10
# 60s内至少达到10000条写命令
save 60 10000

之后在启动服务器时加载配置文件。

# 启动服务器加载配置文件
redis-server redis.conf

这种通过服务器配置文件触发 RDB 的方式,与 Bgsave 命令类似,达到触发条件时,会 Forks 一个子进程进行数据同步。

不过最好不要通过这方式来触发 RDB 持久化,因为设置触发的时间太短,则容易频繁写入 RDB 文件,影响服务器性能,时间设置太长则会造成数据丢失。

②RDB 文件

前面介绍了三种让服务器生成 RDB 文件的方式,无论是由主进程生成还是子进程来生成,其过程如下:

  • 生成临时 RDB 文件,并写入数据。

  • 完成数据写入,用临时文代替代正式 RDB 文件。

  • 删除原来的 DB 文件。

RDB 默认生成的文件名为 dump.rdb,当然,我可以通过配置文件进行更加详细配置。

比如在单机下启动多个 Redis 服务器进程时,可以通过端口号配置不同的 RDB 名称,如下所示:

# 是否压缩rdb文件
rdbcompression yes

# rdb文件的名称
dbfilename redis-6379.rdb

# rdb文件保存目录
dir ~/redis/

RDB的几个优点:

  • 与 AOF 方式相比,通过 RDB 文件恢复数据比较快。

  • RDB 文件非常紧凑,适合于数据备份。

  • 通过 RDB 进行数据备份,由于使用子进程生成,所以对 Redis 服务器性能影响较小。

RDB 的几个缺点:

  • 如果服务器宕机的话,采用 RDB 的方式会造成某个时段内数据的丢失,比如我们设置 10 分钟同步一次或 5 分钟达到 1000 次写入就同步一次,那么如果还没达到触发条件服务器就死机了,那么这个时间段的数据会丢失。

  • 使用 Save 命令会造成服务器阻塞,直接数据同步完成才能接收后续请求。

  • 使用 Bgsave 命令在 Forks 子进程时,如果数据量太大,Forks 的过程也会发生阻塞,另外,Forks 子进程会耗费内存。

AOF

聊完了 RDB,来聊聊 Redis 的另外一个持久化方式:AOF(Append-only file)。

与 RDB 存储某个时刻的快照不同,AOF 持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以 Redis 协议追加保存到以后缀为 AOF 文件末尾。

在 Redis 服务器重启时,会加载并运行 AOF 文件的命令,以达到恢复数据的目的。

10分钟彻底理解Redis持久化和主从复制

①开启 AOF 持久化方式

Redis 默认不开启 AOF 持久化方式,我们可以在配置文件中开启并进行更加详细的配置,如下面的 redis.conf 文件:

# 开启aof机制
appendonly yes

# aof文件名
appendfilename "appendonly.aof"

# 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no
appendfsync always

# 默认不重写aof文件
no-appendfsync-on-rewrite no

# 保存目录
dir ~/redis/

②三种写入策略

在上面的配置文件中,我们可以通过 appendfsync 选项指定写入策略,有三个选项:

appendfsync always
# appendfsync everysec
# appendfsync no
always:客户端的每一个写操作都保存到 AOF 文件当中,这种策略很安全,但是每个写操作都有 IO 操作,所以也很慢。
everysec:appendfsync 的默认写入策略,每秒写入一次 AOF 文件,因此,最多可能会丢失 1s 的数据。
no:Redis 服务器不负责写入 AOF,而是交由操作系统来处理什么时候写入 AOF 文件。更快,但也是最不安全的选择,不推荐使用。

③AOF 文件重写

AOF 将客户端的每一个写操作都追加到 AOF 文件末尾,比如对一个 Key 多次执行 Incr 命令,这时候,AOF 保存每一次命令到 AOF 文件中,AOF 文件会变得非常大。

incr num 1
incr num 2
incr num 3
incr num 4
incr num 5
incr num 6 ... incr num 100000

AOF 文件太大,加载 AOF 文件恢复数据时,就会非常慢,为了解决这个问题,Redis 支持 AOF 文件重写。

通过重写 AOF,可以生成一个恢复当前数据的最少命令集,比如上面的例子中那么多条命令,可以重写为:

set num 100000

AOF 文件是一个二进制文件,并不是像上面的例子一样,直接保存每个命令,而使用 Redis 自己的格式,上面只是方便演示。

两种重写方式:通过在 redis.conf 配置文件中的选项 no-appendfsync-on-rewrite 可以设置是否开启重写。
这种方式会在每次 Fsync 时都重写,影响服务器性能,因此默认值为 no,不推荐使用。
# 默认不重写aof文件
no-appendfsync-on-rewrite no

客户端向服务器发送 bgrewriteaof 命令,也可以让服务器进行 AOF 重写。

# 让服务器异步重写追加aof文件命令
> bgrewriteaof

AOF 重写方式也是异步操作,即如果要写入 AOF 文件,则 Redis 主进程会 Forks 一个子进程来处理,如下所示:

10分钟彻底理解Redis持久化和主从复制

重写 AOF 文件的好处:
  • 压缩 AOF 文件,减少磁盘占用量。

  • 将 AOF 的命令压缩为最小命令集,加快了数据恢复的速度。

③AOF 文件损坏

在写入 AOF 日志文件时,如果 Redis 服务器宕机,则 AOF 日志文件文件会出格式错误。

在重启 Redis 服务器时,Redis 服务器会拒绝载入这个 AOF 文件,可以通过以下步骤修复 AOF 并恢复数据:

  • 备份现在 AOF 文件,以防万一。

  • 使用 redis-check-aof 命令修复 AOF 文件,该命令格式如下:

    修复aof日志文件

    $ redis-check-aof -fix file.aof

  • 重启 Redis 服务器,加载已经修复的 AOF 文件,恢复数据。

AOF 的优点:

  • AOF 只是追加日志文件,因此对服务器性能影响较小,速度比 RDB 要快,消耗的内存较少。

AOF 的缺点:

  • AOF 方式生成的日志文件太大,即使通过 AFO 重写,文件体积仍然很大。

  • 恢复数据的速度比 RDB 慢。

选择 RDB 还是 AOF 呢?

通过上面的介绍,我们了解了 RDB 与 AOF 各自的优点与缺点,到底要如何选择呢?
通过下面的表示,我们可以从几个方面对比一下 RDB 与 AOF,在应用时,要根据自己的实际需求,选择 RDB 或者 AOF。

其实,如果想要数据足够安全,可以两种方式都开启,但两种持久化方式同时进行 IO 操作,会严重影响服务器性能,因此有时候不得不做出选择。

10分钟彻底理解Redis持久化和主从复制

当 RDB 与 AOF 两种方式都开启时,Redis 会优先使用 AOF 日志来恢复数据,因为 AOF 保存的文件比 RDB 文件更完整。

小结:上面讲了一大堆 Redis 的持久化机制的知识,其实,如果你只是单纯把 Redis 作为缓存服务器,那么可以完全不用考虑持久化。

但是,在如今的大多数服务器架构中,Redis 不单单只是扮演一个缓存服务器的角色,还可以作为数据库,保存我们的业务数据,此时,我们则需要好好了解有关 Redis 持久化策略的区别与选择。

什么是 Reids 主从复制?

上面,我们了解了 Redis 两种不同的持久化方式,Redis 服务器通过持久化,把 Redis 内存中持久化到硬盘当中,当 Redis 宕机时,我们重启 Redis 服务器时,可以由 RDB 文件或 AOF 文件恢复内存中的数据。
不过持久化后的数据仍然只在一台机器上,因此当硬件发生故障时,比如主板或 CPU 坏了,这时候无法重启服务器,有什么办法可以保证服务器发生故障时数据的安全性?或者可以快速恢复数据呢?

想做到这一点,我们需要再了解 Redis 另外一种机制:主从复制。

Redis 的主从复制机制是指可以让从服务器(Slave)能精确复制主服务器(Master)的数据,如下图所示:

10分钟彻底理解Redis持久化和主从复制

上面的图表示的是一台 Master 服务器与 Slave 服务器的情况,其实一台 Master 服务器也可以对应多台 Slave 服务器,如下图所示:10分钟彻底理解Redis持久化和主从复制

另外,Slave 服务器也可以有自己的 Slave 服务器,这样的服务器称为 Sub-Slave。

而这些 Sub-Slave 通过主从复制最终数据也能与 Master 保持一致,如下图所示:

10分钟彻底理解Redis持久化和主从复制

主从复制的方式和工作原理

Redis 的主从复制是异步复制,异步分为两个方面:

  • 一个是 Master 服务器在将数据同步到 Slave 时是异步的,因此 Master 服务器在这里仍然可以接收其他请求。

  • 一个是 Slave 在接收同步数据也是异步的。

①复制方式

Redis 主从复制分为以下三种方式:

  • 当 Master 服务器与 Slave 服务器正常连接时,Master 服务器会发送数据命令流给 Slave 服务器,将自身数据的改变复制到 Slave 服务器。

  • 当因为各种原因 Master 服务器与 Slave 服务器断开后,Slave 服务器在重新连上 Master 服务器时会尝试重新获取断开后未同步的数据即部分同步,或者称为部分复制。

  • 如果无法部分同步(比如初次同步),则会请求进行全量同步,这时 Master 服务器会将自己的 RDB 文件发送给 Slave 服务器进行数据同步,并记录同步期间的其他写入,再发送给 Slave 服务器,以达到完全同步的目的,这种方式称为全量复制。

②工作原理

Master 服务器会记录一个 Replication Id 的伪随机字符串,用于标识当前的数据集版本,还会记录一个当数据集的偏移量 Offset。

不管 Master 是否有配置 Slave 服务器,Replication Id 和 Offset 会一直记录并成对存在,我们可以通过以下命令查看 Replication Id和 Offset:

> info repliaction

通过 redis-cli 在 Master 或 Slave 服务器执行该命令会打印类似以下信息(不同服务器数据不同,打印信息不同):

connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=9472,lag=1
master_replid:2cbd65f847c0acd608c69f93010dcaa6dd551cee
master_repl_offset:9472

当 Master 与 Slave 正常连接时,Slave 使用 PSYNC 命令向 Master 发送自己记录的旧 Master 的 Replication id 和 Offset。

而 Master 会计算与 Slave 之间的数据偏移量,并将缓冲区中的偏移数量同步到 Slave,此时 Master 和 Slave 的数据一致。
而如果 Slave 引用的 Replication 太旧了,Master 与 Slave 之间的数据差异太大,则 Master 与 Slave 之间会使用全量复制的进行数据同步。

配置主从复制

Redis 的主从配置非常简单,我们可以使用两种方式来配置主从服务器,在这时我们先假设 Redis 的 Master 服务器地址为 192.168.0.101。

客户端发送同步命令:

# 向客户端
saveof 192.168.1.101 6379

Slave 服务器配置主服务器:在这里 Slave 服务器的 redis.conf 通过 saveof 选项,可以指定 Master 服务器,如下:

slaveof 192.168.1.101 6379

通过上面两种方式的配置,Master 服务器与 Slave 服务器便已经可以开始进行数据同步了。

Master 要求验证:上面配置的是 Master 服务器没有设置密码的情况,如果 Master 设置了密码,则可以在连接到 Slave 服务器的 redis-cli 执行下面的命令:

# <password>指代实际的密码
config set masterauth <password>

或者在 Slave 服务器的 redis.conf 中配置下面的选项:

# <password>指代实际的密码
masterauth <password>

避免 Slave 被清空

Slave 会被清空?Slave 不用同步了 Master 的数据吗?备份的数据怎么会清空了呢?

当 Master 服务器关闭了持久化时,如果发生故障后自动重启时,由本地没有保存持久化的数据,重启的 Redis 内存数据为空,而 Slave 会自动同步 Master 的数据,这时候,Slave 服务器的数据也会被清空。

如何避免 Slave 被清空呢?如果条件允许(一般都可以的),Master 服务器还是要开启持久化,这样 Master 故障重启时,可以快速恢复数据,而同步这台 Master 的 Slave 数据也不会被清空。

如果 Master 不能开启持久化,则不应该设置让 Master 发生故障后重启(有些机器会配置自动重启),而是将某个 Slave 服务器升级为 Master 服务器,对外继续提供服务。

Slave 默认为只读的

在 Redis 2.6 以后,Slave 只读模式是默认开启的,我们可以通过配置文件中的 slave-read-only 选项配置是否开启只读模式:

# 默认是yes
slave-read-only yes/no

或者在客户端中通过 config set 命令设置是否开启只读模式:

config set slave-read-only no 

上面将 Slave 服务器设置为可以写入,但是要注意,如果 Slave 也配置了自己的从服务器(Sub-Slave),那么 Sub-Slave 只会同步从 Master 服务器同步到 Slave 的数据,而并会同步我们直接写入 Slave 服务器的数据。

主从复制中的 Key 过期问题

我们都知道 Redis 可以通过设置 Key 的过期时间来限制 Key 的生存时间,Redis 处理 Key 过期有惰性删除和定期删除两种机制。

而在配置主从复制后,Slave 服务器就没有权限处理过期的 Key,这样的话,对于在 Master 上过期的 Key,在 Slave 服务器就可能被读取。

所以 Master 会累积过期的 Key,积累一定的量之后,发送 Del 命令到 Slave,删除 Slave 上的 Key。

如果 Slave 服务器升级为 Master 服务器 ,则它将开始独立地计算 Key 过期时间,而不需要通过 Master 服务器的帮助。

主从复制的作用

①保存 Redis 数据副本

当我们只是通过 RDB 或 AOF 把 Redis 的内存数据持久化毕竟只是在本地,并不能保证绝对的安全,而通过将数据同步 Slave 服务器上,可以保留多一个数据备份,更好地保证数据的安全。

②读写分离

在配置了主从复制之后,如果 Master 服务器的读写压力太大,可以进行读写分离,客户端向 Master 服务器写入数据,在读数据时,则访问 Slave 服务器,从而减轻 Master 服务器的访问压力10分钟彻底理解Redis持久化和主从复制

10分钟彻底理解Redis持久化和主从复制

③高可用性与故障转移

服务器的高可用性是指服务器能提供 7*24 小时不间断的服务,Redis 可以通过 Sentinel 系统管理多个 Redis 服务器。

当 Master 服务器发生故障时,Sentineal 系统会根据一定的规则将某台 Slave 服务器升级为 Master 服务器,继续提供服务,实现故障转移,保证 Redis 服务不间断。

小结:Redis 的主从复制可以让我们把 Redis 中的数据同步到其他服务器上,为数据安全提供更加安全的保障,也可以让我们的服务器在发生故障而无法重启时,可以更加快速地切换服务器,继续对外提供服务。

作者:张君鸿

编辑:陶家龙、孙淑娟

出处:https://juejin.im/user/5c6665476fb9a049a81fd8e9

本文同步分享在 博客“lxw1844912514”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
子非鱼 子非鱼
2年前
Redis高级
第一章Redis的持久化由于redis是一个内存数据库,所有的数据都是保存在内存当中的,内存当中的数据极易丢失,所以redis的数据持久化就显得尤为重要,在redis当中,提供了两种数据持久化的方式,分别为RDB以及AOF,且Redis默认开启的数据持久化方式为RDB方式。1、RDB持久化方案Redis会定期保存数据快照至一个rbd文件中,并在启动时自动
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这