首頁  >  文章  >  資料庫  >  詳細解析Redis中的持久化機制

詳細解析Redis中的持久化機制

青灯夜游
青灯夜游轉載
2021-12-29 10:11:461752瀏覽

這篇文章帶大家了解Redis中的持久化機制:RDB和AOF,並比較一下RDB和AOF,希望對大家有幫助!

詳細解析Redis中的持久化機制

Redis持久化機制

#為什麼要持久化

如果Redis再次造訪時,發現Redis的資料是空的,就會形成快取穿透。更重要的是,因為Redis的資料是空的,所以客戶端想要存取的key都沒有,就會造成大量的請求就會瞬間打到資料庫上,造成快取雪崩(少量的key是穿透,大量的key是雪崩)。

這個時候,資料庫可能就掛掉。而又無法保證redis不宕機,所以需要當redis宕機後,迅速將裡面的內容恢復出來。因此需要做一個持久化。持久化是為了恢復資料用的,而不是儲存資料用的。 【相關建議:Redis影片教學

RDB

RDB(Redis DataBase),是Redis預設的存儲方式,RDB方式是透過快照(snapshotting)完成的。

觸發快照的方式

#符合自訂配置的快照規則

  • #save 900 1 # 表示15分鐘(900秒鐘)內至少1個鍵被更改則進行快照。

  • save 300 10 # 表示5分鐘(300秒)內至少10個鍵被更改則進行快照。

  • save 60 10000 # 表示1分鐘內至少10000個鍵被更改則進行快

N秒內資料集至少有M個改動」這一條件被滿足時,自動儲存一次資料集。

執行save或bgsave指令

##執行指令save或bgsave可以產生dump.rdb文件,每次命令執行都會將所有redis內存快照到一個新的rdb文件裡,並覆蓋原有rdb快照文件。

save與bgsave對比:

bgsave同步#是O(n)
##指令 save
#IO類型
非同步 是否阻塞redis其它命令
#否(在產生子程序執行呼叫fork函數時會有短暫阻塞) 複雜度
O(n)###########優點######不會消耗額外記憶體######不阻塞客戶端指令#############缺點######阻塞客戶端指令###### #需要fork子進程,消耗記憶體############

設定自動產生rdb檔案後台使用的是bgsave方式。

執行flushall指令

flushall

清空Redis之前,先儲存目前Redis快照

執行主從複製操作(第一次)

第一次主從複製時需要產生rdb文件,會儲存目前Redis快照

RDB執行流程

詳細解析Redis中的持久化機制

  • 流程分析

      1. #Redis父程式先判斷:目前是否在執行save或bgsave /bgrewriteaof(aof檔案重寫指令)的子進程,如果在執行則bgsave指令直接回傳。
      1. 父程式執行fork(呼叫作業系統函數複製主程序)操作建立子程序,這個過程中父行程是阻塞的,Redis不能執行來自客戶端的任何命令。
      1. 父程式fork後,bgsave指令返回」Background saving started」訊息並不再阻塞父行程,並且可以回應其他指令。
      1. 子程序建立RDB文件,根據父行程記憶體快照產生臨時快照文件,完成後對原有文件進行原子替換。 (RDB始終完整)
      1. 子程序傳送訊號給父行程表示完成,父行程更新統計資料。
      1. 父程式fork子程序後,繼續工作。

RDB檔案結構

詳細解析Redis中的持久化機制

  • 1、頭部5位元組固定為「REDIS」字串
  • 2、4位元組「RDB」版本號(不是Redis版本號),目前為9,填滿後為0009
  • 3、輔助字段,以key-value的形式
  • 4、儲存資料庫號碼
  • 5、字典大小
  • ##6、過期key
  • 7、主要數據,以key-value的形式儲存
  • 8、結束標誌
  • #9、校驗和,就是看檔案是否損壞,或者是否被修改

RDB的優缺點

#優點

  • RDB是二進位壓縮文件,佔用空間小,方便傳輸(傳給slaver)

  • 主程序fork子程序,可以最大化Redis效能,主程序不能太大,複製過程中主程序阻塞

缺點

    不保證資料完整性,會遺失最後一次快照以後變更的所有資料

#AOF

AOF(append only file)是Redis的另一個持久化方式。 Redis預設是不開啟的。開啟AOF持久化後,Redis將所有對資料庫進行過寫入的命令(及其參數)(RESP)記錄到AOF文件,以此達到記錄資料庫狀態的目的,

這樣當Redis重啟後只要依序回放這些命令就會恢復到原始狀態了。 AOF會記錄過程,RDB只管結果

AOF持久化實作

設定redis.conf

# 可以通过修改redis.conf配置文件中的appendonly参数开启 
appendonly yes

# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。 
dir ./

# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改 
appendfilename appendonly.aof

#AOF原理

AOF檔中儲存的是redis的指令,同步指令到AOF 檔的整個過程可以分成三個階段:

  • 指令傳播:Redis將執行完的指令、指令的參數、指令的參數個數等資訊傳送到AOF 程式。

  • 快取追加:AOF程式根據接收到的命令數據,將指令轉換為網路通訊協定的格式,然後將協定內容追加 到伺服器的AOF快取中。

  • 檔案寫入和儲存:AOF 快取中的內容寫入到AOF 檔案末尾,如果設定的AOF 保存條件被滿足的話, fsync函數或fdatasync 函數會被調用,將寫入的內容真正地保存到磁碟中。

詳細解析Redis中的持久化機制

指令傳播

#當一個Redis客戶端需要執行指令時,它會透過網路連接,將協定文字傳送給Redis伺服器。伺服器在接到客戶端的請求之後,它會根據協定文字的內容,選擇適當的命令函數,並將各個參數從字串文字轉換為Redis 字串物件(StringObject)。每當命令函數成功執行之後,命令參數就會被傳播到AOF程式。

快取追加

當指令被傳播到AOF程式之後,程式會根據指令以及指令的參數,將指令從字串物件轉換回原來的協定文本。協定文字產生之後,它會被追加到redis.h/redisServer結構的aof_buf 結尾。

redisServer結構維持Redis伺服器的狀態,aof_buf域則保存著所有等待寫入到AOF 檔案的協定文字(RESP)

檔案寫入與儲存

每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile 函数都会被调用,这个函数执行以下两个工作:

  • WRITE:根据条件将aof_buf中的缓存写入到AOF文件。

  • SAVE:根据条件调用fsync或 fdatasync函数将AOF文件保存到磁盘中。

AOF保存模式

Redis 目前支持三种 AOF 保存模式,它们分别是:

  • AOF_FSYNC_NO :不保存。

  • AOF_FSYNC_EVERYSEC :每一秒钟保存一次。(默认)

  • AOF_FSYNC_ALWAYS :每执行一个命令保存一次。(不推荐)

AOF_FSYNC_NO

从不fsync,将数据交给操作系统来处理。更快,也更不安全的选择。

SAVE只会在以下任意一种情况中被执行:

  • Redis被关闭

  • AOF功能被关闭

  • 系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)

这三种情况下的SAVE操作都会引起Redis主进程阻塞。

AOF_FSYNC_EVERYSEC

SAVE原则上每隔一秒钟就会执行一次,因为SAVE操作是由后台子线程(fork)调用的, 所以它不会引起服务器主进程阻塞,并且在故障时只会丢失1秒钟的数据。

AOF_FSYNC_ALWAYS

每次执行完一个命令之后,WRITE和SAVE都会被执行。每次有新命令追加到AOF文件时就执行一次fsync,非常慢,也非常安全。

因为SAVE是由Redis主进程执行的,所以在SAVE执行期间,主进程会被阻塞,不能接受命令请求。

AOF保存模式对性能和安全性的影响

三种模式的比较

詳細解析Redis中的持久化機制

AOF重写

AOF记录数据的变化过程,越来越大,需要重写“瘦身”

Redis可以在AOF体积变得过大时,自动地在后台(Fork子进程)对AOF进行重写。

重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。

所谓的“重写”其实是一个有歧义的词语,实际上,AOF重写并不需要对原有的AOF文件进行任何写入和读取,它针对的是数据库中键的当前值。

举例说明

set s1 11
set s1 22
set s1 33

lpush list1 1 2 3
lpush list1 4 5 6

AOF重写后

set s1 33

lpush list1 1 2 3 4 5 6

Redis不希望AOF重写造成服务器无法处理请求,所以Redis决定将AOF重写程序放到(后台)子进程里执行,

  • 1、子进程进行AOF重写期间,主进程可以继续处理命令请求。

  • 2、子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性。

不过,使用子进程也有一个问题需要解决:因为子进程在进行AOF重写期间,主进程还需要继续处理命令,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。

为了解决这个问题,Redis增加了一个AOF重写缓存,这个缓存在fork出子进程之后开始启用,Redis主进程在接到新的写命令之后,除了会将这个写命令的协议内容追加到现有的AOF文件之外,还会追加到这个缓存中。

重写过程分析

詳細解析Redis中的持久化機制

Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。

当子进程在执行AOF重写时,主进程需要执行以下三个工作:

  • 处理命令请求。
  • 将写命令追加到现有的AOF文件中。
  • 将写命令追加到AOF重写缓存中

。这样一来可以保证:现有的AOF功能会继续执行,即使在AOF重写期间发生停机,也不会有任何数据丢失。所有对数据库进行修改的命令都会被记录到AOF重写缓存中。

当子进程完成AOF重写之后,它会向父进程发送一个完成信号,父进程在接到完成信号之后,会调用一个信号处理函数,并完成以下工作:

  • 将AOF重写缓存中的内容全部写入到新AOF文件中。
  • 对新的AOF文件进行改名,覆盖原有的AOF文件。

Redis数据库里的+AOF重写过程中的命令------->新的AOF文件---->覆盖老的当步骤1执行完毕之后,现有AOF文件、新AOF文件和数据库三者的状态就完全一致了。

当步骤2执行完毕之后,程序就完成了新旧两个AOF文件的交替。这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接受命令请求了

。在整个AOF后台重写过程中,只有最后的写入缓存和改名操作会造成主进程阻塞,在其他时候,AOF后台重写都不会对主进程造成阻塞,这将AOF重写对性能造成的影响降到了最低。

AOF重写触发方式

  • 1、配置触发
#表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为准
auto-aof-rewrite-percentage 100

#限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
  • 2、执行bgrewriteaof命令
127.0.0.1:6379>bgrewriteaof‘
Backgroundappendonlyfilerewritingstarted

AOF重写总结

詳細解析Redis中的持久化機制

混合持久化

RDB和AOF各有优缺点,Redis 4.0开始支持rdb和aof的混合持久化。

如果把混合持久化打开,aofrewrite的时候就直接把rdb的内容写到aof文件开头。

RDB的头+AOF的身体---->appendonly.aof

开启混合持久化

aof-use-rdb-preambleyes

AOF文件的载入与数据还原

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

于是在Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重启效率大幅得到提升。

  • 1、创建一个不带网络连接的伪客户端(fake client)

因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样

  • 2、从AOF文件中分析并读取出一条写命令

  • 3、使用伪客户端执行被读出的写命令

  • 4、一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止

詳細解析Redis中的持久化機制

Redis数据备份策略

  • 1.写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份

  • 2.每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份

  • 3.每次copy备份的时候,都把太旧的备份给删了

  • 4.每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏

RDB和AOF对比

  • 1、RDB存某个时刻的数据快照,采用二进制压缩存储,AOF存操作命令,采用文本存储(混合)

  • 2、RDB性能高、AOF性能较低

  • 3、RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF设置为每秒保存一次,则最多丢2秒的数据

  • 4、Redis以主服务器模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令。

更多编程相关知识,请访问:编程视频!!

以上是詳細解析Redis中的持久化機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除