什麼是數據庫狀態redis
redis是一個鍵值對的數據庫服務器,服務器中一般包含中任意個非空的數據庫,而每一個數據庫又能夠包含任意個鍵值對,爲了方便起見,咱們將服務器中的非空數據庫以及他們的鍵值對統稱爲數據庫狀態。數據庫
RDB持久化的邏輯數組
RDB持久化就能夠手動執行也能夠根據服務器配置選項按期的執行,該功能能夠將某個時間點上的數據庫狀態保存到一個RDB文件中,這個文件實際上是一個二進制的文件,經過這個文件能夠還原生成RDB文件時的數據庫狀態。安全
RDB文件的建立服務器
有兩個生成redisRDB文件的命令,一個是SAVE,一個是BGSAVE。SAVE命令是使用服務器進程來生成RDB文件,在生成RDB文件的時候,會阻塞全部的讀寫操做,服務器不能處理任何命令請求。BGSAVE命令是同過服務器進程派生出來一個子進程,而後有子進程負責建立RBD文件,服務器進程能夠繼續處理命令請求。併發
其實建立RDB文件的工做都是經過rdbsave函數實現的是不過兩種命令以不一樣的方式調用這個函數。app
SAVE命令執行時的服務器狀態函數
其實這個很簡單,咱們上面已經提到過SAVE命令或阻塞一切請求,固然擁抱口BGSAVE請求了,因此在執行SAVE期間,再次執行BGSAVE命令會被直接拒絕。工具
BGSAVE命令執行時的服務器狀態性能
咱們知道BGSAVE命令是服務器的子進程來完成的,服務器進程能夠繼續接收和執行命令,可是再BGSAVE命令執行期間服務器處理SAVE、BGSAVE、BGREWRITEAOF三個命令的方式和平時有所不一樣,主要有一下幾種情形:
1.在BGSAVE命令執行期間,客戶端發起的SAVE命令會被服務器拒絕。服務器禁止SAVE命令和BGDAVE命令同時執行是爲了不父進程和子進程同時執行兩個rdbsave調用,防止產生競爭條件。
2.在BGSAVE命令執行期間客戶端發起BGSAVE命令會被服務器拒絕,由於同時執行兩個BGSAVE命令也會產生競爭條件
3.在BGSAVE命令執行期間,客戶端發起BGREWRITEAOF命令會被延遲到BGSAVE命令執行完畢以後執行
4.在BGREWRITEAOF命令執行期間,客戶端發起BGSAVE命令會被服務器直接拒絕,主要是由於BGREWRITEAOF和BGSAVE命令都是由子進程來完成的,禁止他們同時執行知識一個性能方面的考慮,由於併發出兩個子進程,而且這兩個子進程同時進行大量的磁盤寫入操做,並非什麼好事情。
RDB文件的載入
對於RDB文件的載入就相對簡單了,RDB文件的載入工做是在服務器啓動的時候自動執行的,而且在服務器載入RDB文件期間,會一直處於阻塞狀態,直到載入工做完成爲止。
RDB自動間歇性保存
上面咱們講了如何建立RDB文件,可是何時來建立RBD文件呢?除了手動的執行命令以外,咱們還能夠經過配置來讓服務器自動來建立RDB文件,咱們能夠在redis的配置文件中經過如下配置來實現:
save 900 1 save 300 10 save 60 10000
用戶能夠經過save選項設置多個保存條件(固然能夠超過三個了,十個八個均可以,由於這些保存條件實際上是保存在一個數組中的),可是隻要其實任意一個條件知足,服務器就會執行BGSAVE命令。而上面的三條保存配置其實也是在咱們開啓了RDB持久化可是沒有配置相關保存條件下時服務器給的默認的配置。
RDB自動保存的觸發原理
咱們知道了如何配置保存條件的,可是這個保存條件是怎麼觸發的呢?
其實服務器除了經過一個數據存儲咱們的保存條件外,還會維持一個dirty的計數器,以及一個lastsave屬性,其中dirty計數器用來統計距離上一次成功執行SAVE命令或者BGSAVE命令後服務器對數據庫狀態進行了多少次修改(包括寫入,刪除,更新等操做),而lastsave屬性是一個UNIX的時間戳,記錄了服務器上一次成功執行SAVE命令或者BGSAVE命令的時間。這兩個值都會在成功執行完BGSAVE命令後重置:dirty重置成0,lastsave更新爲當前時間。
而對於條件的判斷則是Redis服務器會週期性的操做函數serverCron默認每隔100毫秒執行一次,該函數用於對正在運行的服務器進行維護,它的其中一項工做就是檢查save選項所設置的保存條件是否知足,若是知足則執行BGSAVe命令。必須同時知足的條件是:1.距離上一次成功執行保存的時間超過設置的時間,2.數據庫狀態的修改次數超過設置的修改次數
RDB的文件結構
暫略
AOF持久化的邏輯
與RBD持久化經過保存數據庫中的鍵值對來記錄數據庫狀態不一樣,AOF持久化是經過保存redis服務器所執行的寫命令來記錄數據庫狀態的。
被寫入到AOF文件的命令都是以Redis的命令請求協議格式保存的,由於Redis的命令請求協議是純文本的,因此咱們能夠直接打開一個AOF文件,裏面保存的基本都是咱們執行的命令,可是會有一些SELECT命令,SELECT命令是用於指定數據庫的,此命令是服務器自動添加的。
AOF持久化的過程
AOF持久化過程的實現能夠分爲命令追加、文件寫入、文件同步三個步驟。
命令追加:當AOF功能打開的時候,服務器執行一條命令以後,會以協議格式將被執行的寫命令追加到服務器狀態的aof_buf緩衝區的額末尾,可是aof_buf緩衝區的命令何時寫入aof文件這個要根據額咱們的appendfsync的相關配置來決定
文件寫入和同步:爲了提升文件的寫入效率,在現代的操做系統中,當用戶調用write函數,將一些數據寫入到文件的時候,操做系統一般會將寫入數據暫時存放到一個內存緩衝區裏面,等到緩衝區滿了或者超過了執行的時限以後,才真正的將緩衝區中的數據寫入到磁盤裏面
咱們須要注意的是,Redis的服務器進程就是一個事件循環,這個循環中的文件時間負責接收客戶端的命令請求,以及向客戶端發送命令回覆,而時間時間則負責執行向serverCron函數這樣的須要定時運行的函數
由於服務器在處理文件事件時可能會執行寫命令,使得這些內容被追加到aof_buf緩衝區裏面,因此在服務器每次結束一個時間循環以前,它都會調用flushAppendOnlyFile函數,考慮是否須要將aof_buf緩衝區中的內容寫入和保存到AOF文件裏面。
flushAppendOnlyFile函數的行爲是有服務器配置文件的appendfsync選項的值來決定的,appendfsync的值有三種:
1.always:將aof_buf緩衝區中的數據寫入並同步到AOF文件。這種設置時最安全的,就變機器出現故障,也只是會丟失一個事件循環中所產生的命令數據
2.everysec:將aof_buf緩衝區的全部內容寫入到AOF文件,若是上次同步AOF文件的時間距離如今超過1s,那麼再次對AOF文件進行同步,而且這個同步操做有一個線程專門完成。這種設置,服務器在每一個事件循環中都要將aof_buf緩衝區中的全部內容寫入到Aof文件,而且每隔1s就要在子線程中對AOF文件進行一次同步。從效率上來說everysec模式足夠快,而且就算出現故障停機,數據庫也只丟失一秒鐘的命令數據。
3.no:在服務器的每一個事件循環鍾都要將aof緩衝區中的全部內容寫入到AOF文件,但不對AOF文件進行同步,什麼時候同步有操做系統來同步,因此這種設置是若是服務器停機,將會丟掉上次AOF文件同步後的全部寫命令數據。
AOF文件的載入和數據還原
由於AOF文件中包含了重建數據庫狀態所需的全部寫命令,因此服務器只要讀入並從新執行一邊AOF文件裏面保存的寫命令,就能夠還原服務器關閉以前的數據狀態。
AOF重寫
由於Aof持久化是經過保存被執行的寫命令來記錄數據庫狀態的,因此隨着服務器事件的流逝,AOF文件內容會愈來愈大,文件體積也會也來越大,若是不加控制體積過大的AOF文件極可能對Redis服務器甚至宿主機形成影響。對於數據恢復來講,AOF文件中會有不少冗餘的命令,好比對某個key操做了八次,AOF文件中會記錄八條寫命令,可是咱們關心的只是最後一次命令執行後的數據狀態,爲了解決AOF文件體積膨脹問題,Redis提供了AOF重寫功能。
AOF重寫沒有對進行AOF任何操做,只是對AOF重寫時候的數據狀態轉成寫命令保存起來,也就是說重寫後的AOF文件中保存着可以換膚重寫時數據庫狀態的最小的寫命令數,這樣就能夠大大的減小文件的體積了。
須要注意的是在重寫程序中在處理列表、哈希表、集合、有序集合這四種可能會帶來多個元素的鍵時,會先檢查包含元素的數量,若是數量超過了設置的常量值(這個值不通版本是不同的),就會用多條命令來記錄這個鍵而不僅僅時一條命令。
由於Reids是單線程的,爲了避免是AOF重寫時阻塞服務器的正常運行,redis決定將AOF重寫放到一個子進程中進行,這樣作有兩個好處:
1.子進程進行AOF重寫期間,服務器進程(父進程)能夠繼續處理命令請求
2.子進程帶有服務器進程的數據副本,使用子進程而不是線程,能夠在避免使用所得狀況下,保證數據得安全性
有個問題咱們要注意,在子進程AOF重寫期間,服務器進程還須要繼續處理命令請求,這個時候redis用來一個AOF重寫緩衝區來解決這個問題,也就是說,在子進程AOF重寫期間,服務器進程會進行三個工做:
1.執行客戶端發來得命令
2.將執行後得寫命令追加得AOF緩衝區
3.將執行後得寫命令追加得AOF重寫緩衝區
這樣一來能夠保證:
1.AOF緩衝區得內容會按期被寫入和同步到AOF文件,對如今AOF文件得處理工做會如常進行
2.從建立子進程開始,服務器得全部寫命令都會被記錄到AOF重寫緩衝區裏面
當子進程完成AOF重寫後,會向服務器進程發一個信號,並調用一個信號處理函數執行一下工做:
1.將Aof重寫緩衝區中得全部內容寫入到新得Aof文件中,這是新AOF文件所保存得數據庫狀態將和服務器當前得數據庫狀態保持一致
2.對新的AOF文件進行更名,原子的覆蓋如今的AOF文件,完成新舊文件的交替
在整個AOF後臺重寫過程當中,只有信號處理的時候會對服務器進程(父進程)形成阻塞,其餘時候AOF後臺重寫都不會阻塞父進程,這將AOF重寫對服務器形成的影響講到了最低。
RDB持久化和AOF持久化的對比
RDB優劣勢
優點:
劣勢:
AOF優劣勢
優點:
劣勢: