前言:持久化是什么?簡單的說就是將數據放在斷電后不會丟失的設備中,比如磁盤,數據庫在進行寫操作時做了哪些事呢?
主要有五個過程
1、客戶端向服務端發送寫操作(數據在客戶端的內存中)。
2、數據庫服務端接收到寫請求的數據(數據在服務端的內存中)。
3、服務端調用write這個系統調用,將數據往磁盤上寫(數據在系統內存的緩沖區中)。
4、操作系統將緩沖區中的數據轉移到磁盤控制器上(數據在磁盤緩存中)。
5、磁盤控制器將數據寫到磁盤的物理介質中(數據真正落到磁盤上)。
從上面可以看出,當數據庫發生故障時,如果系統內核是完好的。那么執行完了第三步,那么數據就是安全的,如果斷電,上面五項中所有的緩存都會失效,數據庫和操作系統都會停止工作。所以只有全部走完才能保證數據不丟失。
通過上面的分析,我們可能有一些疑惑。
1、數據庫多長時間調用一次write,將數據寫到內核緩沖區?
2、內核多長時間會將系統緩沖區中的數據寫到磁盤控制器?
3、磁盤控制器又在什么時候把緩存中的數據寫到物理介質上?
其中第一個問題通常都是由數據庫層面控制。第二個問題呢操作系統都有默認的策略,但是可以通過通過POSIX API提供的fsync系列命令強制操作系統將數據從內核區寫到磁盤控制器上
對於第三個問題數據庫已經無法觸及,但實際上,大多數情況下磁盤緩存是被設置關閉的,或者是只開啟為讀緩存,也就是說寫操作不會進行緩存,直接寫到磁盤。建議的做法是僅僅當你的磁盤設備有備用電池時才開啟寫緩存。
數據備份一般有三種方式:
A:數據同步備份的方式
B:記錄每一步的操作行為
C:以追加的方式記錄數據,數據本身不修改,數據本身就是一份日志。
Redis有兩種持久化策略:RDB和AOF
一、RDB快照
RDB 持久化可以在指定的時間間隔內生成數據集的時間點快照。如何生成快照呢?Redis借助了fork命令的copy on write機制。在生成快照時,將當前進程fork出一個子進程,然后在子進程中循環所有的數據,將數據寫成為RDB文件。
子進程基本上是復制父進程,這等於兩個相同的redis進程在系統上運行,會造成內存使用率的大幅增加。redis.conf中配置參數如下:含義為X秒改變了N次
Background saving started by pid 19064 19064:C 19 Sep 23:55:45.087 # Failed opening the RDB file dump.rdb (in server root dir /home/matao/redis-3.2.9/src) for saving: Permission denied # Will save the DB if both the given number of seconds and the given --More--(15%)2470:M 19 Sep 23:55:45.186 # Background saving error # 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 900 1 save 300 10 save 60 10000
# The filename where to dump the DB dbfilename 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 ./ //保存的文件路徑
手動保存有兩種方式:
1、save 同步進行 阻塞客戶端請求
2、bgsave異步進行 不妨礙目前的寫入。
二、AOF
AOF是通過保存對redis服務端的寫命令來記錄數據庫狀態的,即保存你對redis數據庫的寫操作。AOF的運作方式是不斷的將寫命令追加到文件的末尾,所以隨着寫入命令的不斷增減,AOF的文件體積也會變大越來越大。
例如:一個計數器調用了100次INCR,那么AOF文件就記錄了100條記錄。實際上只使用一條set命令足以保存計數器當前的值了,為了控制AOF文件的大小,redis支持執行 BGREWRITEAOF 命令, Redis 將生成一個新的 AOF 文件, 這個文件包含重建當前數據集 所需的最少命令。
Redis調用write寫入后,何時調用fsync將其寫到磁盤上,通過appendfsync來控制
1、appendfsync no
當設置appendfsync為no的時候,Redis不會主動調用fsync去將AOF日志內容同步到磁盤,所以這一切就完全依賴於操作系統的調試了。對大多數Linux操作系統,是每30秒進行一次fsync,將緩沖區中的數據寫到磁盤上。
2、appendfsync everysec
當設置appendfsync為everysec的時候,Redis會默認每隔一秒進行一次fsync調用,將緩沖區中的數據寫到磁盤。但是當這一 次的fsync調用時長超過1秒時。Redis會采取延遲fsync的策略,再等一秒鍾。也就是在兩秒后再進行fsync,這一次的fsync就不管會執行多長時間都會進行。這時候由於在fsync時文件描述符會被阻塞,所以當前的寫操作就會阻塞。 所以,結論就是:在絕大多數情況下,Redis會每隔一秒進行一次fsync。在最壞的情況下,兩秒鍾會進行一次fsync操作。 這一操作在大多數數據庫系統中被稱為group commit,就是組合多次寫操作的數據,一次性將日志寫到磁盤。
3、appednfsync always
當設置appendfsync為always時,每一次寫操作都會調用一次fsync,這時數據是最安全的,當然,由於每次都會執行fsync,所以其性能也會受到影響。
優點:RDB非常適合用於備份,恢復速度很快。AOF會使redis變得非常耐久,使數據安全性進一步提高。
缺點:RDB在服務器故障時會丟失一段時間的數據。AOF文件的體積大於RDB,AOF的速度可能會慢於RDB。