Redis 持久化 rdb、Aof對比
一、Redis
簡介:
Redis是一個開源的、基于內存的數據結構存儲器,可以用作數據庫、緩存和消息中間件。
Redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。
二、Redis持久化
Redis是一個內存數據庫,數據保存在內存中,但是我們都知道內存的數據變化是很快的,也容易發生丟失。幸好Redis還為我們提供了持久化的機制,會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄磁盤文件,分別是RDB(Redis DataBase)和AOF(Append Only File)。
本節我們重點介紹Redis的兩種持久化機制。
三、rdb機制
RDB持久化是默認的持久化方式,RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤(RDB是在某個時間點將數據寫入一個臨時文件,持久化結束后,用這個臨時文件替換上次持久化的文件,達到數據恢復)。這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名為dump.rdb。
1、rdb的特性
持久化時fork一個進程,遍歷hash table,利用copy on write,把整個db dump保存下來。
save, shutdown, slave 命令會觸發這個操作。
粒度比較大,如果save, shutdown, slave 之前crash了,則中間的操作沒辦法恢復。
優勢:
- RDB文件緊湊,全量備份,非常適合用于進行備份和災難恢復;
- 生成RDB文件的時候,redis主進程會fork()一個子進程來單獨處理所有保存工作,主進程不需要進行任何磁盤IO操作,保證了redis的高性能。
- RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
劣勢:
- RDB快照是一次全量備份,存儲的是內存數據的二進制序列化形式,存儲上非常緊湊。當進行快照持久化時,會開啟一個子進程專門負責快照持久化,子進程會擁有父進程的內存數據,父進程修改內存子進程不會反應出來,所以在快照持久化期間修改的數據不會被保存,可能丟失數據。
既然RDB機制是通過把某個時刻的所有數據生成一個快照來保存,那么就應該有一種觸發機制去實現這個過程。對于RDB來說,提供了三種機制:save、bgsave、自動化。我們分別來看一下
2、觸發方式
save/bgsave, shutdown, slave 命令會觸發這個操作。
2.1、save
該命令會阻塞當前Redis服務器,執行save命令期間,Redis不能處理其他命令,直到RDB過程完成為止。具體流程如下:


客戶端通過命令進行持久化存儲
./redis-cli -h ip -p port save
由于Redis是用主線程來處理所有client請求,這種方式會阻塞所有請求。我們的客戶端可能都是幾萬或者是幾十萬,這種方式顯然不可取。
2.2、bgsave
執行該命令時,Redis會在后臺異步進行快照操作,快照同時還可以響應客戶端請求(這是Redis rdb持久化默認的方式)。具體流程如下:

客戶端通過命令進行后臺持久化存儲
./redis-cli -h ip -p port bgsave
具體操作是Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成后自動結束。阻塞只發生在fork階段,一般時間很短。基本上 Redis 內部所有的RDB操作都是采用 bgsave 命令。
2.3、自動觸發
自動觸發是由我們的配置文件來完成的。在redis.conf配置文件中,我們可以去設置redis在n秒內如果有超過m個key被修改就執行一次RDB操作,這個操作就類似于在這個時間點來保存一次Redis的所有數據,相當于一次快照。所以這個持久化方法也通常叫做snapshots。
默認配置文件解讀:
################################ SNAPSHOTTING ################################ # # Save the DB on disk: # # save <seconds> <changes> # # Will save the DB if both the given number of seconds and the given # number of write operations against the DB occurred. # # In the example below the behaviour will be to save: # after 900 sec (15 min) if at least 1 key changed # after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed # # Note: you can disable saving completely by commenting out all "save" lines. # # It is also possible to remove all the previously configured save # points by adding a save directive with a single empty string argument # like in the following example: # # save "" #若不需要持久化,那么你可以注釋掉所有的 save 行,然后配置save "" 來停用保存功能。 save 900 1 #表示900 秒內如果至少有 1 個 key 的值變化,則保存 save 300 10 #表示60 秒內如果至少有 10000 個 key 的值變化,則保存 save 60 10000 #表示60 秒內如果至少有 10000 個 key 的值變化,則保存 # By default Redis will stop accepting writes if RDB snapshots are enabled # (at least one save point) and the latest background save failed. # By default Redis will stop accepting writes if RDB snapshots are enabled # (at least one save point) and the latest background save failed. # This will make the user aware (in a hard way) that data is not persisting # on disk properly, otherwise chances are that no one will notice and some # disaster will happen. # # If the background saving process will start working again Redis will # automatically allow writes again. # # However if you have setup your proper monitoring of the Redis server # and persistence, you may want to disable this feature so that Redis will # continue to work as usual even if there are problems with disk, # permissions, and so forth. stop-writes-on-bgsave-error yes #默認值為yes。當snapshot時出現錯誤無法繼續時是否阻塞客戶端“變更操作”。“錯誤”可能因為磁盤已滿/磁盤故障/OS級別異常等。如果Redis重啟了,那么又可以重新開始接收數據了 # Compress string objects using LZF when dump .rdb databases? # For default that's set to 'yes' as it's almost always a win. # If you want to save some CPU in the saving child set it to 'no' but # the dataset will likely be bigger if you have compressible values or keys. rdbcompression yes #默認值是yes。對于存儲到磁盤中的快照,可以設置是否進行壓縮存儲。 # Since version 5 of RDB a CRC64 checksum is placed at the end of the file. # This makes the format more resistant to corruption but there is a performance # hit to pay (around 10%) when saving and loading RDB files, so you can disable it # for maximum performances. # # RDB files created with checksum disabled have a checksum of zero that will # tell the loading code to skip the check. rdbchecksum yes #默認值是yes。在存儲快照后,我們還可以讓redis使用CRC64算法來進行數據校驗,但是這樣做會增加大約10%的性能消耗,如果希望獲取到最大的性能提升,可以關閉此功能。 # The filename where to dump the DB dbfilename dump.rdb #設置快照的文件名,默認是 dump.rdb # The working directory. # # The DB will be written inside this directory, with the filename specified # above using the 'dbfilename' configuration directive. # # The Append Only File will also be created inside this directory. # # Note that you must specify a directory here, not a file name. dir /home/cmhy/redis-5.0.5 #設置快照文件的存放路徑,這個配置項一定是個目錄,而不能是文件名
我們可以修改這些配置來實現我們想要的效果。因為第三種方式是配置的,所以我們對前兩種進行一個對比:

3、通過日志看持久化過程
7639:M 22 May 2020 10:12:54.048 * 10000 changes in 60 seconds. Saving... //根據redis.conf 中save 60 1000配置,觸發持久化 7639:M 22 May 2020 10:12:54.240 * Background saving started by pid 28173 //fork一個后臺子進程 28173:C 22 May 2020 10:13:41.728 * DB saved on disk //保存到磁盤 28173:C 22 May 2020 10:13:41.876 * RDB: 585 MB of memory used by copy-on-write 7639:M 22 May 2020 10:13:42.221 * Background saving terminated with success
四、Aof機制
全量備份總是耗時的,有時候我們提供一種更加高效的方式AOF,工作機制很簡單,redis會將每一個收到的寫命令都通過write函數追加到文件中。通俗的理解就是日志記錄。
如果你了解oracle的重做日志,那就容易理解,redis aof持久化和oracle重做日志類似。
1、aof的特性
把寫操作指令,持續的寫到一個類似日志文件里。(類似于從postgresql等數據庫導出sql一樣,只記錄寫操作)
粒度較小,crash之后,只有crash之前沒有來得及做日志的操作沒辦法恢復。
優勢:
AOF可以更好的保護數據不丟失,一般AOF會每隔1秒,通過一個后臺線程執行一次fsync操作,最多丟失1秒鐘的數據;
AOF日志文件沒有任何磁盤尋址的開銷,寫入性能非常高,文件不容易破損;
AOF日志文件即使過大的時候,出現后臺重寫操作,也不會影響客戶端的讀寫;
AOF日志文件的命令通過非常可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用flushall命令清空了所有數據,只要這個時候后臺rewrite還沒有發生,那么就可以立即拷貝AOF文件,將最后一條flushall命令給刪了,然后再將該AOF文件放回去,就可以通過恢復機制,自動恢復所有數據
劣勢:
對于同一份數據來說,AOF日志文件通常比RDB數據快照文件更大;
AOF開啟后,支持的寫QPS會比RDB支持的寫QPS低,因為AOF一般會配置成每秒fsync一次日志文件,當然,每秒一次fsync,性能也還是很高的;
以前AOF發生過bug,就是通過AOF記錄的日志,進行數據恢復的時候,沒有恢復一模一樣的數據出來。
2、AOF持久化原理
ta的原理看下面這張圖:

每當有一個寫命令過來時,就直接保存在我們的AOF文件中。
3、文件重寫原理
為什么重寫?
AOF的方式也同時帶來了另一個問題。持久化文件會變的越來越大。為了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。將內存中的數據以命令的方式保存到臨時文件中,同時會fork出一條新進程來將文件重寫。

重寫aof文件的操作,并沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點類似。
3、 觸發方式
可以通過配置文件看到有三種AOf持久化方式
appendfsync always //每次修改,同步持久化,每次發生數據變更會被立即記錄到磁盤 性能較差但數據完整性比較好 appendfsync everysec //每秒同步,異步操作,每秒記錄 如果一秒內宕機,有數據丟失 appendfsync no //從不同步
比較:

默認配置解讀:
############################## APPEND ONLY MODE ############################### # By default Redis asynchronously dumps the dataset on disk. This mode is # good enough in many applications, but an issue with the Redis process or # a power outage may result into a few minutes of writes lost (depending on # the configured save points). # # The Append Only File is an alternative persistence mode that provides # much better durability. For instance using the default data fsync policy # (see later in the config file) Redis can lose just one second of writes in a # dramatic event like a server power outage, or a single write if something # wrong with the Redis process itself happens, but the operating system is # still running correctly. # # AOF and RDB persistence can be enabled at the same time without problems. # If the AOF is enabled on startup Redis will load the AOF, that is the file # with the better durability guarantees. # # Please check http://redis.io/topics/persistence for more information. appendonly no //是否開啟AOF持久化 # The name of the append only file (default: "appendonly.aof") appendfilename "appendonly.aof" //AOF持久化文件名稱 # The fsync() call tells the Operating System to actually write data on disk # instead of waiting for more data in the output buffer. Some OS will really flush # data on disk, some other OS will just try to do it ASAP. # # Redis supports three different modes: # # no: don't fsync, just let the OS flush the data when it wants. Faster. # always: fsync after every write to the append only log. Slow, Safest. # everysec: fsync only one time every second. Compromise. # # The default is "everysec", as that's usually the right compromise between # speed and data safety. It's up to you to understand if you can relax this to # "no" that will let the operating system flush the output buffer when # it wants, for better performances (but if you can live with the idea of # some data loss consider the default persistence mode that's snapshotting), # or on the contrary, use "always" that's very slow but a bit safer than # everysec. # # More details please check the following article: # http://antirez.com/post/redis-persistence-demystified.html # # If unsure, use "everysec". # appendfsync always appendfsync everysec
//指定aof操作文件同步策略,always、eversec、no,默認為everysec是每s進行一次fsync調用,將緩沖區中的數據同步到磁盤。但是當這一次的fsync調用時間超過1s時Redis會采取延遲fsynccel,再等1s鐘。也就是在2s后再進行一次fsync,這一次的fsync不管執行多久都會進行。這時候由于在fsync時文件描述符會被阻塞,所以當前的寫操作會被阻塞。
//結論:絕大多數情況下Redis會每隔1s進行fsync,最壞情況下,2s鐘會進行一次fsync。
# appendfsync no //如果同步策略設置為always或everysec,會造成后臺存儲進程(后臺存儲或寫入aof文件)會產生很多磁盤I/O開銷,當設置為no時,Redis不會主動調用fsync去將aof日志同步到磁盤,所以這一切都要靠操作系統的調試了,對大多數操作系統,是每30/s進行一次fsync,將緩沖區中數據同步到磁盤; # When the AOF fsync policy is set to always or everysec, and a background # saving process (a background save or AOF log background rewriting) is # performing a lot of I/O against the disk, in some Linux configurations # Redis may block too long on the fsync() call. Note that there is no fix for # this currently, as even performing fsync in a different thread will block # our synchronous write(2) call. # # In order to mitigate this problem it's possible to use the following option # that will prevent fsync() from being called in the main process while a # BGSAVE or BGREWRITEAOF is in progress. # # This means that while another child is saving, the durability of Redis is # the same as "appendfsync none". In practical terms, this means that it is # possible to lose up to 30 seconds of log in the worst scenario (with the # default Linux settings). # # If you have latency problems turn this to "yes". Otherwise leave it as # "no" that is the safest pick from the point of view of durability. no-appendfsync-on-rewrite no #注意,目前對這個情況還沒有完美修正,甚至不同線程的 fsync() 會阻塞我們同步的write(2)調用。 #為了緩解這個問題,可以用下面這個選項。它可以在 BGSAVE 或 BGREWRITEAOF 處理時阻止fsync()。 #這就意味著如果有子進程在進行保存操作,那么Redis就處于"不可同步"的狀態。 #這實際上是說,在最差的情況下可能會丟掉30秒鐘的日志數據。(默認Linux設定) #如果把這個設置成"yes"帶來了延遲問題,就保持"no",這是保存持久數據的最安全的方式。 # Automatic rewrite of the append only file. # Redis is able to automatically rewrite the log file implicitly calling # BGREWRITEAOF when the AOF log size grows by the specified percentage. # # This is how it works: Redis remembers the size of the AOF file after the # latest rewrite (if no rewrite has happened since the restart, the size of # the AOF at startup is used). # # This base size is compared to the current size. If the current size is # bigger than the specified percentage, the rewrite is triggered. Also # you need to specify a minimal size for the AOF file to be rewritten, this # is useful to avoid rewriting the AOF file even if the percentage increase # is reached but it is still pretty small. # # Specify a percentage of zero in order to disable the automatic AOF # rewrite feature. auto-aof-rewrite-percentage 100 #自動重寫AOF文件。如果AOF日志文件增大到指定百分比,Redis能夠通過 BGREWRITEAOF 自動重寫AOF日志文件。 #工作原理:Redis記住上次重寫時AOF文件的大小(如果重啟后還沒有寫操作,就直接用啟動時的AOF大小) #這個基準大小和當前大小做比較。如果當前大小超過指定比例,就會觸發重寫操作。 #你還需要指定被重寫日志的最小尺寸,這樣避免了達到指定百分比但尺寸仍然很小的情況還要重寫。 #指定百分比為0會禁用AOF自動重寫特性。 auto-aof-rewrite-min-size 64mb #文件達到大小閾值的時候進行重寫 # An AOF file may be found to be truncated at the end during the Redis # startup process, when the AOF data gets loaded back into memory. # This may happen when the system where Redis is running # crashes, especially when an ext4 filesystem is mounted without the # data=ordered option (however this can't happen when Redis itself # crashes or aborts but the operating system still works correctly). # # Redis can either exit with an error when this happens, or load as much # data as possible (the default now) and start if the AOF file is found # to be truncated at the end. The following option controls this behavior. # # If aof-load-truncated is set to yes, a truncated AOF file is loaded and # the Redis server starts emitting a log to inform the user of the event. # Otherwise if the option is set to no, the server aborts with an error # and refuses to start. When the option is set to no, the user requires # to fix the AOF file using the "redis-check-aof" utility before to restart # the server. # # Note that if the AOF file will be found to be corrupted in the middle # the server will still exit with an error. This option only applies when # Redis will try to read more data from the AOF file but not enough bytes # will be found. aof-load-truncated yes #如果設置為yes,如果一個因異常被截斷的AOF文件被redis啟動時加載進內存,redis將會發送日志通知用戶 #如果設置為no,erdis將會拒絕啟動。此時需要用"redis-check-aof"工具修復文件。 # When rewriting the AOF file, Redis is able to use an RDB preamble in the # AOF file for faster rewrites and recoveries. When this option is turned # on the rewritten AOF file is composed of two different stanzas: # # [RDB file][AOF tail] # # When loading Redis recognizes that the AOF file starts with the "REDIS" # string and loads the prefixed RDB file, and continues loading the AOF # tail. aof-use-rdb-preamble yes #加載時Redis識別出AOF文件以“REDIS”開頭字符串, #并加載帶此前綴的RDB文件,然后繼續加載AOF
五、總結
1、rdb、aof對比

2、rdb、aof,應該用哪一個?
一般來說,如果想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。
如果你非常關心你的數據,但仍然可以承受數分鐘以內的數據丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但我們并不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便于進行數據庫備份, 并且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快, 除此之外, 使用 RDB 還可以避免之前提到的 AOF 程序的 bug 。因為以上提到的種種原因, 未來我們可能會將 AOF 和 RDB 整合成單個持久化模型。 (這是一個長期計劃。)
3、配置方式
兩種方式:修改配置文件、命令行修改
3.1、配置文件方式(需要重啟)
1)關閉rdb
配置文件將:
Save 900 1 Save 300 10 Save 60 10000
注釋掉,并打開save "" 的注釋,使得 save "" 生效,即可關閉rdb;
2)關閉AOF
進入配置文件,將appendonly設置為no,默認是 appendonly no
3.2、命令行方式(不需要重啟)
1)*關閉rdb的命令:
config set save ""
2)*關閉aof的命令:
config set appendonly no
該兩種設置查詢是否已修改成功,可分別通過config get save, config get appendfsync命令來查看。
參考:
配置文件詳解http://www.rzrgm.cn/pyng/p/11959018.html
http://www.rzrgm.cn/shizhengwen/p/9283973.html
https://baijiahao.baidu.com/s?id=1654694618189745916&wfr=spider&for=pc
作者:運維·拖拉斯基
作者水平很低, 如果有錯誤及時指出, 如果你覺得本文寫的好請點一波贊~(≧▽≦)/~
出處:http://www.rzrgm.cn/-abm/
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
浙公網安備 33010602011771號