[翻譯自官方]什麼是RDB和AOF? 一文了解Redis持久化!

 

​概述


本文提供Redis持久化技術說明,  建議全部Redis用戶閱讀. 若是您想更深刻了解Redis持久性原理機制和底層持久性保證, 請參考文章 揭祕Redis持久化: http://antirez.com/post/redis-persistence-demystified.htmlhtml

 

Redis持久化


 

Redis提供了不一樣級別的持久化選項:python

  • RDB模式, Redis數據庫備份文件(Redis Database Backup)持久化方式, 提供週期性基於時間點的數據集快照備份, 好比每小時生成一個快照備份.linux

  • AOF模式, 僅追加到文件(AppendOnlyFile)持久化方式, 在每次數據庫服務收到寫操做時記錄日誌文件, 當服務重啓時, 自動回放該日誌來重建原始數據集. 日誌中使用Redis本身的協議, 並按照統一的格式, 採用只追加的方法記錄. 當日志文件太大時, Redis能夠在後臺重寫該日誌, 生成一個最小化版本的日誌文件.redis

  • 你也能夠徹底禁用持久化, 好比只要保證服務在運行中有數據或能夠自動生成緩存數據便可.數據庫

  • 你還能夠在同一個Redis實例上結合AOF和RDB兩種持久化方式. 請注意: 這種方式在Redis重啓時, AOF文件會被用來重建原始數據集, 由於, 相對RDB週期快照的方式, AOF被認爲是更完整的數據備份, 好比它能夠作到準實時備份(只丟失1秒的數據).編程

接下來, 讓咱們來對比RDB和AOF的優缺點:緩存

 

RDB優勢


  • RDB採用一個壓縮單文件來表示基於時間點的Redis數據, RDB文件是完美的備份. 例如, 你能夠保留過去24小時的每小時的快照備份, 而且保存過去30天, 天天的快照備份, 當數據遇到丟失時, 你能夠很方便的從不一樣的備份粒度(版本)來恢復數據集.安全

  • RDB用來作災備恢復很是好, 由於緊湊的單文件很是便於在遠端數據中心或者亞馬遜S3(對象存儲,能夠加密)間傳輸.服務器

  • RDB使Redis性能最大化, 由於Redis父進程只須要啓動一個子進程完成快照備份便可, 父進程不執行由備份引發的磁盤I/O網絡

  • 與AOF模式相比, RDB在大數據集的狀況下, 數據恢復時, 服務重啓速度更快.

 

RDB缺點


  • 若是你想要在Redis意外中止工做時(好比斷電), 最小可能的丟失數據, RDB不是一個好的方案. 你能夠在RDB生成的地方, 配置不一樣的保存點(好比每5分鐘,對數據集產生至少100次寫操做時,建立一個保存點, 你也能夠配置多個保存點策略). 然而, 這樣你一般會在每5分鐘甚至更長時間間隔才建立RDB快照, 因此當Redis異常中止工做時, 你會丟失最後產生快照時間點到如今的數據.

  • RDB會調用系統fork()方法派生一個子進程來完成數據持久化到硬盤. 若是數據集比較大, Fork()方法會很是耗時, 形成Redis中止爲客戶端服務, 中止時間多是上微秒, 若是數據集很是大而且CPU性能不是很好, 中止時間能夠達到1秒鐘或更多. 在持久化時, AOF也會調用fork()方法, 可是你能夠不帶任何協商(trade-off), 調整重寫日誌的頻率.

 

AOF優勢


使用AOF持久化程度更高: 你能夠配置不一樣的fsync策略:

  • 不帶fsync

  • 每秒鐘一次fsync

  • 每次查詢的時候fsync

注: fsync(https://man7.org/linux/man-pages/man2/fsync.2.html)是系統方法, 用於將內核態的緩存數據持久化到存儲設備, 好比將內存數據寫入硬盤

默認使用每秒執行一次fsync的策略, 這種場景下, Redis的寫性能也能很是好, 由於fsync運行在一個後臺線程, 而主線程會盡力完成寫操做. 因此你最多丟失1秒鐘的數據.

  • AOF日誌是一個只能追加的文件, 因此在斷電後, 該文件不會出現查找(seek)或損壞的問題. 即便因爲磁盤滿或其餘緣由致使日誌中存在只寫了一半的命令, 也可使用redis-check-aof工具輕鬆修復.

  • Redis會在AOF文件太大的時候, 自動在後臺重寫日誌. 重寫十分安全, 重寫時, Redis派生一個子進程將大的AOF文件重寫爲最小可用的數據集日誌文件, 此時有寫操做時, Redis繼續追加到舊的AOF文件的同時也追加到AOF重寫緩衝區aof_rewrite_buf, 重寫完成時, 新的小AOF文件將合併緩衝區中的新數據, 最後將新的AOF文件重命名爲老的AOF文件完成替換操做, 之後的數據將寫入新的AOF文件.

  • AOF日誌文件以一種容易理解和解析的格式依次記錄了全部的操做. 導出一個AOF文件很是容易.  甚至在失誤執行了清除命令FLUSHALL(https://redis.io/commands/flushall) , 若是這時候重寫操做沒有被執行, 你仍然能夠經過關閉服務, 刪除文件最後的錯誤命令, 重啓Redis完成數據恢復.

 

AOF缺點


    • 對於相同的數據集, AOF文件通常比RDB文件大.

    • 根據具體的fsync策略, AOF可能比RDB速度慢. 一般默認的每秒fsync策略下, Reids性能也很是高, 若是禁用fsync, 即便在高負載的狀況下, AOF的速度應該和RDB同樣快. 儘管如此, 在巨大寫負載的狀況下, RDB提供了更多最大延遲的保證.

    • 在過去, 當執行一些特殊的命令時(好比這裏有一個涉及到阻塞的命令BRPOPLPUSH:https://redis.io/commands/brpoplpush), Redis遇到了一些罕見的BUG, 它會致使AOF重建數據時, 數據出現不一致.這些問題很是罕見, 咱們進行了單元測試, 自動建立隨機複雜的數據集來執行重建測試, 沒有出現這些問題.  可是若是使用RDB持久化, 幾乎不可能出現這類問題. 爲了清楚的說明這一點: AOF相似MySQL或者MongoDB, 採用增量更新現有狀態的工做機制, 可是RDB快照是每次從頭開始建立, 從概念上來講, RDB更具備魯棒性(健壯). 可是有如下兩點值得注意:

      1. 每次AOF被Redis重寫的時候,它會從包含在數據集中的實際數據中從頭開始從新建立,使新AOF文件對bug的抵抗力比不重寫的, , 一直追加的AOF文件更強.

      2. 在實際使用中, 咱們重來沒有收到過一個關於AOF文件出錯的用戶報告.

 

那我該使用哪一個?


一般, 若是你想得到像PostgreSQL那樣的數據安全性, 你應該結合RDB和AOF.

若是你很是關心你的數據, 可是容許丟失幾分鐘的數據, 你能夠只使用RDB持久化.

有不少用戶只使用AOF, 可是咱們不建議那樣作, 由於RDB的基於時間點的快照在作數據庫備份, 快速重啓, 或AOF引擎出現問題時, 很是有用.

注意: 基於這些緣由, 在未來(長期計劃), 咱們最終會統一AOF和RDB爲一個持久化模型方案.

下面幾節, 咱們來舉例說明更多, 關於RDB和AOF的細節.

 

快照


Redis默認保存快照到硬盤上的dump.rdb文件. 你能夠配置, 每N分鐘, 至少出現了M次數據集改變執行一次快照, 或者手動執行保存 SAVE 或後臺保存BGSAVE 命令.

save 60 1000

 

它是如何工做的?


每當Redis須要保存數據集到磁盤, 會執行下面的任務:

  • Redis forks 派生子進程, 這時候會存在一個父進程和一個子進程.

  • 子進程開始將數據集寫到RDB臨時文件.

  • 當子進程完成新RDB文件寫入後, 會將原來的舊RDB文件替換.

這種方法就是Redis的寫即拷語義(copy-on-write)

 

AOF僅追加文件


快照不是很持久, 若是Redis服務異常中止, 掉電中止, 或者意外執行了kill -9殺掉Redis服務進程, 最後的數據寫入將會丟失. 雖然對於有些應用來講這是個小問題, 但對於要求徹底持久化的場景, RDB不是一個很好的選擇.

appendonly yes

從如今開始, 每當Redis收到一個改變數據集的命令(好比SET), 該操做將追加到AOF文件, 當你重啓Redis時, 會基於AOF文件重建數據集.

 

日誌重寫


AOF文件大小隨着操做的增長而增長. 舉個例子, 若是你想遞增計數100次, 最終數據集中只包含一個鍵值就是最終的結果, 可是在AOF文件中有100條記錄, 實際上在重建數據集時, 不須要剩餘的99次記錄.

因此Redis支持這個有趣的功能: 在不中斷Redis服務的狀況下, 後臺進行AOF文件重寫. 當執行後臺重寫命令 BGREWRITEAOF 時, Reids會將當前內存中的數據集以最短的有序命令集寫下來. 若是你使用Redis2.2, 你須要定時執行 BGREWRITEAOF(https://redis.io/commands/bgrewriteaof) , 從Redis2.4開始, 它能夠自動觸發日誌重寫(更多信息能夠查看2.4的配置示例, 不一樣版本的配置(https://redis.io/topics/config)).

 

AOF怎麼持久化?



你能夠配置時間間隔, Redis來執行fsync到磁盤. 這裏有三個策略:

  • appendfsync always: 每一個新的命令追加到AOF文件時執行fsync. 很是慢, 可是很是安全. 注意, 若是追加的命令來自多個客戶端或管道的批量命令, 在發送響應以前, 這會被當作一次寫操做, 只會執行一次fsync.

  • appendfsync everysec:  每秒執行一次fsync. 速度足夠快(在Redis2.4版本中, 與RDB快照的速度同樣快), 若是出現意外, 你最多丟失1秒的數據.

  • appendfsync no: 從不執行 fsync, 只把數據交給操做系統. 這雖然更快, 可是更不安全. 這種配置, 一般Linux會每30秒刷新一次數據到硬盤, 但實際時間能夠經過內核配置調優.

每秒執行一次fsync是建議而且是默認的方式. 它既快又安全. appendfsync always策略在實踐中很是慢, 可是支持組提交, 因此能夠將多個並行寫操做合併, 執行一次fsync便可.

 

若是AOF文件被截斷了應該怎麼作?


在寫AOF文件時, 服務器出現crash或磁盤空間滿了, 這時候AOF依然包含一致的數據, 表明了給定時間點版本的數據集(默認fsync策略可能會丟失1秒的數據), 可是最後的命令在AOF記錄中會被截斷, 最新的Redis主幹版本依然會導入全部的AOF文件內容, 可是會忽略最後的不完整的命令, 這時候, 服務器會發出警告日誌:

* Reading RDB preamble from AOF file...* Reading the remaining AOF tail...# !!! Warning: short read while loading the AOF file !!!# !!! Truncating the AOF at offset 439 !!!# AOF loaded anyway because aof-load-truncated is enabled

你能夠改變默認配置來強制中止這種事情發生, 可是默認配置會忽略最後這個不完整的命令, 爲了保證服務重啓後可用.

老版本的Redis不會自動恢復, 須要作如下步驟來恢復:

  • 對AOF文件進行備份.

  • 使用Redis提供的工具redis-check-aof 修復該AOF文件:

    $ redis-check-aof --fix

  • 能夠執行 diff -u 檢查兩個AOF文件的差別, 確認錯誤被修復.

  • 用修復後的AOF文件重啓Redis服務, 重建數據集.

 

AOF文件被損壞了怎麼辦?


若是AOF文件不只被截斷了, 中間還被插入了無效的字節, 事情將變得更加複雜, Redis在啓動的時候會中斷並提示:

* Reading the remaining AOF tail...
# Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

最好是用 redis-check-aof 工具修復, 首先不適用 --fix 選項, 找到問題, 跳過該文件的錯誤位置, 查看是否能夠手動修復該文件, AOF使用與Reids一致的協議格式,因此很是便於手動修復,  不然就使用工具修復該文件, 這種狀況, 從無效的位置到文件結束的數據均可能被丟失, 若是損壞位置發生在開頭的位置, 則至關於丟失整個數據集.

 

它是怎樣工做的?


日誌重寫使用了與快照一致的拷貝即寫(copy-on-write)的方式, 步驟以下:

  • Redis執行 forks派生, 這樣就有一個主進程和一個子進程.

  • 子進程開始寫入一個新的AOF到零時文件中.

  • Redis繼續追加到舊的AOF文件的同時也追加到AOF重寫緩衝區aof_rewrite_buf, 因此即便從新失敗, 也是數據安全的.

  • 當子進程完成了AOF文件重寫, 父進程收到一個完成信號, 將緩存中的數據追加到新的AOF文件.

  • 最後將新的AOF文件重命名爲老的AOF文件完成替換操做, 之後的數據將寫入新的AOF文件.

 

怎樣從dump.rdb快照切換到AOF


在Redis2.0和Redis2.2用不一樣的步驟來切換到AOF, 並且Redis2.2切換到AOF更簡單, 不須要重啓.

Redis >= 2.2

  • 將最近的dump.rdb文件備份.

  • 將備份文件傳輸到安全的地方.

  • 執行如下兩個命令:

    • redis-cli config set save ""  #取消RDB

    • redis-cli config set appendonly yes  #開啓AOF

  • 檢查確認數據庫中的鍵個數沒有丟失.

  • 檢查寫操做都正確的追加進了AOF文件.

第一個配置命令表示啓用AOF功能. 這樣Redis會阻塞來生成初始的備份, 而後打開新文件來寫入操做記錄, 後面的寫操做將會持續追加到該AOF文件中.

第二個配置命令用來關閉RDB快照持久化. 這是可選的, 若是保留save表示同時使用RDB和AOF持久化.

重要: 記住同時修改redis.conf配置文件來打開AOF, 不然服務重啓時將使用原來的配置.

Redis 2.0

  • 將最近的dump.rdb文件備份.

  • 將備份文件傳輸到安全的地方.

  • 中止全部寫操做.

  • 執行後臺重寫AOF命令redis-cli BGREWRITEAOF. 該操做會建立AOF文件.

  • 當AOF備份完成後, 中止Redis服務.

  • 編輯redis.conf, 啓用AOF功能.

  • 重啓服務

  • 檢查確認數據庫中的鍵個數沒有丟失.

  • 檢查寫操做都正確的追加進了AOF文件.

 

在AOF和RDB之間交互


Redis >= 2.4會保證當RDB快照在運行時, 避免觸發一個AOF重寫進程, 或者當AOF重寫已經運行時, 不容許後臺保存快照BGSAVE. 這能夠防止兩個後臺進程同時產生高負載的磁盤I/O.

 

備份Redis數據


開始本節內容前, 請確認已經對數據庫進行備份, 若是磁盤損壞, 雲實例消失等, 沒有備份意味着數據面臨着巨大風險, 會消失在"黑洞" /dev/null中.

Redis對於數據備份很是友好, 即便數據庫數據庫運行中也容許你對數據進行拷貝備份: RDB文件產生時就不會被修改, 快照備份期間, 它會生成零時的文件, 當快照最終備份完成後採用重命名替換原來的RDB文件.

這意味着服務在運行時, 拷貝RDB文件是很是安全的, 下面是咱們的建議:

  • 在服務器上, 建立定時任務CronJob, 每小時執行一次RDB快照, 保存到一個目錄,  而且在另一個目錄下保存每日快照.

  • 每次定時任務執行時, 確認使用find命令查找最舊的快照, 將它們刪除, 對於每小時快照, 你能夠保留最近48小時, 對於天天快照, 你能夠保留1~2個月. 並確包快照名包含時間信息.

  • 天天至少作一次數據轉存, 好比將RDB快照轉存到其餘數據中心, 或者至少從當前Redis服務物理機轉存到其餘地方.

若是你使用ROF持久化方式, 仍然能夠拷貝AOF文件來作備份. 這個AOF文件即便丟失最後一小段數據, Redis也能夠重建它們(請參考上面的截斷AOF文件處理方式)

 

災難恢復


災難恢復和備份基本是一致的, 加上能夠在許多不一樣的數據中心間轉存這些備份數據. 這種狀況下, 即便影響到最主要的數據中心, 其餘地方的備份也是安全而且能夠恢復的.

針對剛起步, 沒有太多的資金來作大型備份, 這裏也提供了一些不須要太大開銷的災備恢復技術:

  • AmazonS3對象存儲或其餘相似服務是一個實現災備恢復系統的好方法. 只需將每小時或每日的RDB快照加密後傳輸到S3便可, 你可使用gpg -c(使用對稱加密模式)對數據加密. 請確認將密碼保存到不一樣的安全的地方(好比拷貝一份交給最重要的人來管理). 建議使用多種存儲服務來提升數據安全性.

  • 使用SCP(SSH的一部分)命令來將數據轉存到其餘服務器. 這是一個簡單並且安全的方法: 在雲端, 獲取遠離當前Redis服務的一個小型虛擬專用服務器VPS, 在數據端, 安裝ssh, 生成不帶密碼的ssh客戶端密鑰, 將它添加到VPS的authorized_keys文件, 這樣就能夠繼續實現自動免密轉存備份數據到VPS, 爲了提升數據安全, 可使用不一樣運營商, 不一樣網絡區域的VPS.

這種方式可能會致使文件傳輸失敗, 因此在傳輸完成後, 至少要增長文件完整性校驗, 好比校驗文件大小, 若是使用VPS, 甚至可使用SHA1校驗.

你也須要部署獨立的監控報警系統, 對備份過程進行監控, 在備份失敗時能及時發現並修復.

 

參考文檔


Redis官方文檔: https://redis.io/topics/persistence


END已結束

歡迎你們留言, 訂閱, 交流哦!


往期回顧


Golang GinWeb框架9-編譯模板/自定義結構體綁定/http2/操做Cookie/完結

Golang GinWeb框架8-重定向/自定義中間件/認證/HTTPS支持/優雅重啓等

Golang GinWeb框架7-靜態文件/模板渲染

Golang GinWeb框架6-XML/JSON/YAML/ProtoBuf等渲染

Golang GinWeb框架5-綁定請求字符串/URI/請求頭/複選框/表單類型

Golang GinWeb框架4-請求參數綁定和驗證

Golang GinWeb框架3-自定義日誌格式和輸出方式/啓禁日誌顏色

Golang GinWeb框架2-文件上傳/程序panic崩潰後自定義處理方式

Golang GinWeb框架-快速入門/參數解析

Golang與亞馬遜對象存儲服務AmazonS3快速入門

Golang+Vue實現Websocket全雙工通訊入門

GolangWeb編程之控制器方法HandlerFunc與中間件Middleware

Golang鏈接MySQL執行查詢並解析-告別結構體

Golang的一種發佈訂閱模式實現

Golang 併發數據衝突檢測器(Data Race Detector)與併發安全

Golang"驅動"MongoDB-快速入門("快碼加鞭")

相關文章
相關標籤/搜索