草庐IT

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

张君鸿 2023-03-28 原文

什么是Redis持久化?

Redis作为一个键值对内存数据库(NoSQL),数据都存储在内存当中,在处理客户端请求时,所有操作都在内存当中进行,如下所示:

这样做有什么问题呢?

其实,只要稍微有点计算机基础知识的人都知道,存储在内存当中的数据,只要服务器关机(各种原因引起的),内存中的数据就会消失了,不仅服务器关机会造成数据消失,Redis服务器守护进程退出,内存中的数据也一样会消失。

对于只把Redis当缓存来用的项目来说,数据消失或许问题不大,重新从数据源把数据加载进来就可以了,但如果直接把用户提交的业务数据存储在Redis当中,把Redis作为数据库来使用,在其放存储重要业务数据,那么Redis的内存数据丢失所造成的影响也许是毁灭性。为了避免内存中数据丢失,Redis提供了对持久化的支持,我们可以选择不同的方式将数据从内存中保存到硬盘当中,使数据可以持久化保存。

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

RDB

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

开启RDB持久化方式

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

1. save命令

save命令是一个同步操作。

# 同步数据到磁盘上
> save

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

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

2. bgsave

与save命令不同,bgsave命令是一个异步操作。

# 异步保存数据集到磁盘上
> bgsave

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

所以,与save命令相比,Redis服务器在处理bgsave采用子线程进行IO写入,而主进程仍然可以接收其他请求,但forks子进程是同步的,所以forks子进程时,一样不能接收其他请求,这意味着,如果forks一个子进程花费的时间太久(一般是很快的),bgsave命令仍然有阻塞其他客户的请求的情况发生。

3. 服务器配置自动触发

除了通过客户端发送命令外,还有一种方式,就是在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文件的方式,无论是由主进程生成还是子进程来生成,其过程如下:

  1. 生成临时rdb文件,并写入数据。
  2. 完成数据写入,用临时文代替代正式rdb文件。
  3. 删除原来的db文件。
RDB默认生成的文件名为dump.rdb,当然,我可以通过配置文件进行更加详细配置,比如在单机下启动多个redis服务器进程时,可以通过端口号配置不同的rdb名称,如下所示:

# 是否压缩rdb文件
rdbcompression yes

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

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

RDB的几个优点

  1. 与AOF方式相比,通过rdb文件恢复数据比较快。
  2. rdb文件非常紧凑,适合于数据备份。
  3. 通过RDB进行数据备,由于使用子进程生成,所以对Redis服务器性能影响较小。

RDB的几个缺点

  1. 如果服务器宕机的话,采用RDB的方式会造成某个时段内数据的丢失,比如我们设置10分钟同步一次或5分钟达到1000次写入就同步一次,那么如果还没达到触发条件服务器就死机了,那么这个时间段的数据会丢失。
  2. 使用save命令会造成服务器阻塞,直接数据同步完成才能接收后续请求。
  3. 使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。

AOF

聊完了RDB,来聊聊Redis的另外一个持久化方式:AOF(Append-only file)。与RDB存储某个时刻的快照不同,AOF持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以Redis协议追加保存到以后缀为aof文件末尾,在Redis服务器重启时,会加载并运行aof文件的命令,以达到恢复数据的目的。

开启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

1. always

客户端的每一个写操作都保存到aof文件当,这种策略很安全,但是每个写请注都有IO操作,所以也很慢。

2. everysec

appendfsync的默认写入策略,每秒写入一次aof文件,因此,最多可能会丢失1s的数据。

3. 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文件的好处

  1. 压缩aof文件,减少磁盘占用量。
  2. 将aof的命令压缩为最小命令集,加快了数据恢复的速度。

AOF文件损坏

在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过以下步骤修复aof并恢复数据。

  1. 备份现在aof文件,以防万一。
  2. 使用redis-check-aof命令修复aof文件,该命令格式如下:
# 修复aof日志文件
$ redis-check-aof -fix file.aof
  1. 重启Redis服务器,加载已经修复的aof文件,恢复数据。

AOF的优点

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

AOF的缺点

  1. AOF方式生成的日志文件太大,即使通过AFO重写,文件体积仍然很大。
  2. 恢复数据的速度比RDB慢。

选择RDB还是AOF呢?

通过上面的介绍,我们了解了RDB与AOF各自的优点与缺点,到底要如何选择呢?

通过下面的表示,我们可以从几个方面对比一下RDB与AOF,在应用时,要根本自己的实际需求,选择RDB或者AOF,其实,如果想要数据足够安全,可以两种方式都开启,但两种持久化方式同时进行IO操作,会严重影响服务器性能,因此有时候不得不做出选择。

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

小结

上面讲了一大堆Redis的持久化机制的知识,其实,如果你只是单纯把Redis作为缓存服务器,那么可以完全不用考虑持久化,但是,在如今的大多数服务器架构中,Redis的单单只是扮演一个缓存服务器的角色,还可以作为数据库,保存我们的业务数据,此时,我们则需要好好了解有关Redis持久化策略的区别与选择。

有关十分钟彻底理解 Redis 的持久化和主从复制的更多相关文章

  1. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  2. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  3. ruby - 在两个 ActiveRecord 类之间合并/复制属性的好方法? - 2

    之前有人问过这个问题,我发现了以下clip关于如何一次设置一个类对象的所有属性,但由于批量分配保护,这在Rails中是不可能的。(例如,您不能Object.attributes={})有没有一种很好的方法可以将一个类的属性合并到另一个类中?object1.attributes=object2.attributes.inject({}){|h,(k,v)|h[k]=vifObjectModel.column_names.include?(k);h}谢谢。 最佳答案 利用assign_attributes使用:without_prote

  4. Ruby:我怎样才能复制这个数组? - 2

    (跟进我之前的问题,Ruby:howcanIcopyavariablewithoutpointingtothesameobject?)我正在编写一个简单的Ruby程序来在.svg文件中进行一些替换。第一步是从文件中提取信息并将其放入数组中。为了避免每次调用此函数时都从磁盘读取文件,我尝试使用memoize设计模式-在第一次调用后的每次调用中都使用缓存结果。为此,我使用了一个在函数之前定义的全局变量。但是,即使我在返回局部变量之前将该变量.dup为局部变量,调用该变量的函数仍在修改全局变量。这是我的实际代码:#memoizetokeepfromhavingtoreadoriginalfi

  5. 三分钟集成 TapTap 防沉迷 SDK(Unity 版) - 2

    三分钟集成Tap防沉迷SDK(Unity版)一、SDK介绍基于国家对上线所有游戏必须增加防沉迷功能的政策下,TapTap推出防沉迷SDK,供游戏开发者进行接入;允许未成年用户在周五、六、日以及法定节假日晚上8:00-9:00进行游戏,防沉谜时间段进入游戏会弹窗进行提示!开发环境要求:Unity2019.4或更高版本iOS10或更高版本Android5.0(APIlevel21)或更高版本🔗Unity集成Demo参考链接🔗UnityTapSDK功能体验APK下载链接二、集成前准备1.创建应用进入开发者后台,按照提示开始创建应用;2.开通服务在使用TDS实名认证和防沉迷服务之前,需要在上面创建的应

  6. ruby-on-rails - 应用程序显示错误的小时和分钟 - 2

    起初:那不是错误区域的问题。在irb和数据库中,一切都很好。当我想在我的View中显示日期(created_at、updated_at和所有由我自己在每个模型中定义的日期)时,就会出现问题。我试图在application.rb中设置时区并从初始化程序中删除时间格式,但这并没有解决我的问题。Annotategem生成的架构信息:#created_at:datetime#updated_at:datetime#publish_at:datetime来自irb:1.9.2-p290:004>Time.zone=>(GMT+00:00)UTC1.9.2-p290:005>Time.zone.n

  7. ruby - 如何让 Ruby 每 10 分钟运行一次任务? - 2

    我想每10分钟执行一次cron作业,但我的系统只执行1小时。所以我正在寻找一种方法来做到这一点。我看过Timer和sleep但我不确定如何执行此操作,甚至不知道如何实现此操作。 最佳答案 看看http://rufus.rubyforge.org/rufus-scheduler/rufus-scheduler是一个用于调度代码片段(作业)的Rubygem。它了解在特定时间、在特定时间、每x次或仅通过CRON语句运行作业。rufus-scheduler不能替代cron/at,因为它在Ruby内部运行。

  8. 手机 & 电脑数据,这样删除才彻底! - 2

    恢复出厂设置后数据还在吗?格式化真的彻底吗?数据到底该怎么删?文章目录前言为什么不能彻底删除数据?手机如何彻底删除数据?第一步:恢复出厂设置第二步:手动覆写数据电脑如何彻底删除数据?方法一:命令提示符方法二:文件粉碎方法三:低级格式化硬盘总结前言个人数据安全再次成为大家关注的热门话题:在日常使用手机和电脑时,我们可能需要删除一些敏感数据,例如银行账户信息、个人照片、聊天记录等。数据删除的目的是保护个人隐私,避免泄露。以下是一些关于如何删除数据的方法。恢复出厂设置,不一定彻底清除手机数据电子产品迭代升级速度越来越快,大家家中的旧手机、旧电脑也越来越多,一键删除、格式化、恢复出厂设置能彻底清除个人

  9. ruby - 如何将文件从一台服务器复制到另一台服务器? - 2

    我有一台服务器,其中只有xls日志文件。每个文件为5-15Mb,并且在文件随时添加的意义上是动态的。现在我需要一种使用Ruby执行以下过程的方法。通过将文件名从一台只有日志文件的服务器发送到另一台服务器来复制文件。我需要将服务器密码作为参数传递。一切都在后台发生,由Ruby脚本触发。 最佳答案 查看Net::SCP和Net::SSHgem。第一个让您使用安全副本检索文件,第二个让您轻松找到可用于检索的文件的名称。在Net::SSH中,ssh.exec!将成为您的friend。来自Net::SCP文档:Net::SCPimplemen

  10. ruby - 复制.blank?在标准的 Ruby 中 - 2

    Rails有一个.blank?如果对象为空,将返回true的方法?还是零?可以找到实际代码here.当我尝试在1.9.2上复制它时:classObjectdefblank?respond_to?(:empty?)?empty?:!selfendend调用“.blank”?返回true但调用"".blank?根据railsdocumentation返回false对于.blank,空白字符串应该eval为true?在查看我最初编写的代码之前:classObjectdefblank?!!self.empty?||!!self.nil?endend结果相同。我错过了什么?

随机推荐