1. 程式人生 > 其它 >第四章 虛擬機器類載入機制

第四章 虛擬機器類載入機制

Redis持久化的功能

Redis是記憶體資料庫,資料都是儲存在記憶體中,為了避免伺服器斷電等原因導致Redis程序異常退出後資料的永久丟失,需要定期將Redis中的資料以某種形式(資料或命令)從記憶體儲存到硬碟; 當下次Redis重啟時,利用持久化檔案實現資料恢復。除此之外,為了進行災難備份,可以將持久化檔案拷貝到一個遠端位置。

Redis 提供持久化兩種方式

1RDB持久化∶原理是將 Reids在記憶體中的資料庫記錄定時儲存到磁碟上

2AOF 持久化(append only file)∶原理是將Reids 的操作日誌以追加的方式寫入檔案,類似於MySQL的binlog

由於AOF持久化的實時性更好,即當程序意外退出時丟失的資料更少,因此AOF是目前主流的持久化方式,不過RDB持久化仍然有其用武之地

RDB 持久化

RDB持久化是指在指定的時間間隔內將記憶體中當前程序中的資料生成快照儲存到硬碟(因此也稱作快照持久化),用二進位制壓縮儲存,儲存的檔案字尾是rdb; 當Redis重新啟動時可以讀取快照檔案恢復資料。

1.觸發條件

RDB持久化的觸發分為手動觸發和自動觸發兩種。

(1)手動觸發

save命令和bgsave命令都可以生成RDB檔案。

save命令會阻塞Redis伺服器程序,直到RDB檔案建立完畢為止,在Redis伺服器阻塞期間,伺服器不能處理任何命令請求。

bgsave命令會建立一個子程序,由子程序來負責建立RDB檔案,父程序(即Redis主程序) 則繼續處理請求。

注意bgsave命令執行過程中,只有

fork子程序(建立子程序的時候時會阻塞伺服器,而對於save命令,整個過程都會阻塞伺服器,因此save已基本被廢棄,線上環境要杜絕save的使用。

(2)自動觸發

在自動觸發RDB持久化時, Redis也會選擇bgsave而不是save來進行持久化。

格式:save m n

自動觸發最常見的情況是在配置檔案中通過save m n,指定當m秒內發生n次變化時,會觸發bgsave。

vim /etc/redis/6379.conf

--219行---以下三個save條件滿足任意一個時,都會引起bgsave的呼叫

save 900 1∶當時間到900秒時,如果redis資料發生了至少1次變化,則執bgsave

save 300 10∶當時間到300秒時,如果redis資料發生了至少10次變化,則執行bgsave

save 60 10000∶當時間到60秒時,如果redis資料發生了至少10000次變化,則執行bgsave

--- 254行--指定RDB檔名

dbfilename dump. rdb

--- 264行---指定RDB檔案和AOF檔案所在目錄

dir /var/lib/redis/6379

--- 242行---是否開啟RDB檔案壓縮

rdbcompression yes

##其他自動觸發機制##

除了save m n以外,還有一些其他情況會觸發bgsave

●在主從複製場景下,如果從節點執行全量複製操作,則主節點會執行bgsave命令,並將rdb檔案傳送給從節點。

●執行shutdown命令時,自動執行rdb持久化。

2.執行流程

(1)當接收到bgsave命令時Redis父程序首先判斷當前是否在執行save或bgsave/barewriteaofaof重新的子程序,如果在執行則bgsave命今直接返

bgsave/bgrewriteaof的子程序不能同時執行,主要是基於效能方面的考慮∶兩個併發的子程序同時執行大量的磁碟寫操作,可能引起嚴重的效能問題。

(2)如果沒有父程序執行fork操作建立子程序,這個過程中父程序是阻塞的, Redis不能執行來自客戶端的任何命令

(3)父程序fork後,bgsave命令返回"Background saving started"資訊並不再阻塞父程序,Redis則可以正常響應其他命令

(4)子程序建立RDB檔案,根據父程序記憶體快照生成臨時快照檔案,完成後對原有檔案進行原子替換要麼都執行要麼都不執行

(5)替換完成後子程序傳送訊號給父程序表示完成,父程序更新統計資訊

3.啟動時載入

RDB檔案的載入工作是在伺服器啟動時自動執行的,並沒有專門的命令。但是由於AOF的優先順序更高,因此當AOF開啟時,Redis會優先載入 AOF檔案來恢復資料只有當AOF關閉時,才會在Redis伺服器啟動時檢測RDB檔案,並自動載入。伺服器載入RDB檔案期間處於阻塞狀態,到載入完成為止。

Redis載入RDB檔案時,會對RDB檔案進行校驗,如果檔案損壞,則日誌中會列印錯誤,Redis啟動失敗。

AOF 持久化

RDB持久化是將程序資料寫入檔案,指定的時間間隔內將記憶體中的資料集快照寫入磁碟,實際操作過程是fork一個子程序,先將資料集寫入臨時檔案,寫入成功後,再替換之前的檔案,用二進位制壓縮儲存。

而AOF持久化則是將Redis執行的每次寫、刪除命令記錄到單獨的日誌檔案中查詢操作不會記錄當Redis重啟時再次執行AOF檔案中的命令來恢復資料。

與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案。

1.開啟AOF

Redis伺服器預設開啟RDB,關閉AOF要開啟AOF,需要在配置檔案中配置∶

vim /etc/redis/6379.conf

--- 700行---修改,開啟AOF

appendonly yes

--- 704行---指定AOF檔名稱

appendfilename "appendonly.aof"

--- 796行---是否忽略最後一條可能存在問題的指令

aof-load-truncated yes

#該配置是作用於當redis在異常退出的時候可能未完整儲存,下一次啟動則會失敗,類似於RDB檔案啟動之前的校驗,可以設定忽略最後一條資料,這樣異常退出導致未完整儲存的資料不會影響伺服器的下一次啟動

/etc/init.d/redis_6379 restart

A0F 持久化執行流程

由於需要記錄Redis的每條寫命令,因此AOF不需要觸發,下面AOF執行流程。

AOF的執行流程包括∶

●命令追加(append)∶將Redis的寫命令追加到緩衝區aof_buf;

●檔案寫入(write)和檔案同步(sync)∶根據不同的同步策略將aof_buf中的內容同步到硬碟;

●檔案重寫(rewrite∶定期重寫AOF檔案,達到壓縮的目的。

1. 命令追加(append)

Redis先將寫命令追加到緩衝區,而不是直接寫入檔案,主要是為了避免每次有寫命令都直接寫入硬碟導致資源的佔用以及硬碟的使用消耗增加縮短硬碟的壽命),導致硬碟IO成為Redis負載的瓶頸

命令追加的格式是Redis命令請求的協議格式,它是一種純文字格式,具有相容性好、可讀性強、容易處理、操作簡單避免二次開銷等優點。在AOF檔案中,除了用於指定資料庫的select命令(如select 0為選中0號資料庫)是由Redis新增的,其他都是客戶端傳送來的寫命令。

2. 檔案寫入(write)和檔案同步(sync)

Redis提供了多種AOF快取區的同步檔案策略,策略涉及到作業系統的write函式寫入函式和fsync函式同步函式,說明如下∶

為了提高檔案寫入效率,在現代作業系統中,當用戶呼叫write函式將資料寫入檔案時,作業系統通常會將資料暫存到一個記憶體緩衝區裡,當緩衝區被填滿或超過了指定時限後,才真正將緩衝區的資料寫入到硬盤裡。這樣的操作雖然提高了效率,但也帶來了安全問題如果計算機停機,記憶體緩衝區中的資料會丟失因此係統同時提供了fsync、fdatasync等同步函式,可以強制作業系統立刻將緩衝區中的資料寫入到硬盤裡,從而確保資料的安全性。

AOF快取區的同步檔案策略存在三種同步方式,它們分別是∶

vim /etc/redis/6379.conf

--- 729行 ---

appendfsync always

命令寫入aof_buf後立即呼叫系統fsync操作同步到AOF檔案,fsync完成後執行緒返回。這種情況下,每次有寫命令都要同步到AOF檔案,硬碟IO成為效能瓶頸,Redis只能支援大約幾百TPS寫入,嚴重降低了Redis的效能即便是使用固態硬碟(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。

appendfsync no

命令寫入aof_buf後呼叫系統write操作,不對AOF檔案做fsync同步同步由作業系統負責,通常同步週期為30秒。這種情況下,檔案同步的時間不可控,且緩衝區中堆積的資料會很多,資料安全性無法保證。

appendfsync everysec

命令寫入aof_buf後呼叫系統write操作,write完成後執行緒返回fsync同步檔案操作由專門的執行緒每秒呼叫一次。everysec是前述兩種策略的折中,是效能和資料安全性的平衡,因此是Redis的預設配置,也是推薦的配置

3. 檔案重寫(rewrite)

隨著時間流逝,Redis伺服器執行的寫命令越來越多,AOF檔案也會越來越大過大的AOF檔案不僅會影響伺服器的正常執行, 也會導致資料恢復需要的時間過長。

檔案重寫是指定期重寫AOF檔案,減小AOF檔案的體積。需要注意的是,AOF重寫是把Redis程序內的資料轉化為寫命令,同步到新的AOF檔案不會對舊的AOF檔案進行任何讀取、寫入操作!

關於檔案重寫需要注意的另一點是對於AOF持久化來說,檔案重寫雖然是強烈推薦的,但並不是必須的即使沒有檔案重寫,資料也可以被持久化並在Redis啟動的時候匯入因此在一些現實中,會關閉自動的檔案重寫,然後通過定時任務在每天的某一時刻定時執行。

#檔案重寫之所以能夠壓縮AOF檔案,原因在於

過期的資料不再寫入檔案

無效的命令不再寫入檔案∶如有些資料被重複設值(set mykey v1,set mykey v2)、有些資料被刪除了(set myset v1,del myset)等

多條命令可以合併為一個∶如sadd myset v1,sadd myset v2,sadd myset v3可以合併為sadd myset v1 v2 v3。

通過上述內容可以看出,由於重寫後AOF執行的命令減少了,檔案重寫既可以減少檔案佔用的空間,也可以加快恢復速度。

#檔案重寫的觸發,分為手動觸發和自動觸發

手動觸發∶直接呼叫bgrewriteaof命令,該命令的執行與bgsave有些類似都是fork子程序進行具體的工作,且都只有在fork時阻塞。

自動觸發∶通過設定auto-aof-rewrite-min-size選項auto-aof-rewrite-percentage選項來自動執行BGREWRITEAOF。

只有當auto-aof-rewrite-min-size和auto-aof-rewrite-percentage兩個選項同時滿足時,才會自動觸發AOF重寫,即bgrewriteaof操作

vim /etc/redis/6379.conf

---771 行---預設已經配置

auto-aof-rewrite-percentage 100

∶當前AOF檔案大小(即aof_current_size)是上次日誌重寫時AOF檔案大小(aof_base_size)兩倍時,發生BGREWRITEAOF操作

auto-aof-rewrite-min-size 64mb

∶當前AOF檔案執行BGREWRITEAOF命令的最小值,避免剛開始啟動Reids時由於檔案尺寸較小導致頻繁的BGREWRITEAOF可能剛開始啟動檔案只有1mb,如果達到兩倍就開始重寫也就是2mb以此類推,檔案過小重寫也沒有太大必要

4. 檔案重寫的流程

關於檔案重寫的流程,有兩點需要特別注意∶(1)重寫由父程序fork子程序進行(2)重寫期間Redis執行的寫命令,需要追加到新的AOF檔案中,為此Redis引入了aof_rewrite_buf快取。

具體流程

(1)Redis父程序首先判斷當前是否存在正在執行bgsave/bqrewriteaof的子程序,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執行完成後再執行。

(2)父程序執行fork操作建立子程序,這個過程中父程序是阻塞的

(3.1)父程序fork後bgrewriteaof命令返回"Background append only file rewrite started"資訊並不再阻塞父程序,並可以響應其他命令。Redis的所有寫命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確。

(3.2)由於fork操作使用寫時複製技術,子程序只能共享fork操作時的記憶體資料。由於父程序依然在響應命令,因此Redis使用AOF重寫緩衝區(aof_rewrite_buf)儲存這部分資料,防止新AOF檔案生成期間丟失這部分資料。也就是說,bqrewriteaof執行期間,Redis的寫命令同時追加到aof_buf和aof_rewirte_buf兩個緩衝區。

(4)子程序根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。

(5.1)子程序寫完新的AOF檔案後,向父程序發訊號,父程序更新統計資訊,具體可以通過info persistence檢視。

(5.2)父程序把AOF重寫緩衝區的資料寫入到新的AOF檔案,這樣就保證了新AOF檔案所儲存的資料庫狀態和伺服器當前狀態一致。

6)使用新的AOF檔案替換老檔案,完成AOF重寫。

5.啟動時載入

當AOF開啟時,Redis啟動時會優先載入AOF檔案來恢復資料,只有當AOF關閉時,才會載入RDB檔案恢復資料。當AOF開啟,但AOF檔案不存在時,即使RDB檔案存在也不會載入。

Redis載入AOF檔案時,會對AOF檔案進行校驗,如果檔案損壞,則日誌中會列印錯誤,Redis啟動失敗。但如果是AOF檔案結尾不完整(機器突然宥機等容易導致檔案尾部不完整的情況),且aof-load-truncated引數開啟,則日誌中會輸出警告,Redis忽略掉AOF檔案的尾部,啟動成功。

aof-load-truncated引數預設是開啟的。

RDB和AOF的優缺點

●RDB持久化

優點∶ RDB檔案緊湊,體積小,網路傳輸快,適合全量複製,恢復速度比AOF快很多。

一旦採用該方式,那麼整個Redis資料庫將只包含一個檔案,這對於檔案備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的資料,同時還要每天歸檔一次最近30天的資料。通過這樣的備份策略,一旦系統出現災難性故障,可以非常容易的進行恢復

缺點∶ RDB檔案的致命缺點在於其資料快照的持久化方式決定了必然做不到實時持久化,而在資料越來越重要的今天,資料的大量丟失很多時候是無法接受的,因此AOF持久化成為主流。

此外,RDB檔案需要滿足特定格式,相容性差(如老版本的Redis不相容新版本的RDB檔案

由於RDB是通過fork子程序來協助完成資料持久化工作的,因此,如果當資料集較大時,可能會導致整個伺服器停止服務幾百毫秒,甚至是1秒鐘。

對於RDB持久化,一方面是bgsave在進行fork操作時Redis主程序會阻塞,另一方面,子程序向硬碟寫資料也會帶來IO壓力。

●AOF持久化

優點

1)RDB持久化相對應,AOF的優點在於來更高的資料安全性支援秒級持久化、相容性好

2)由於該機制對日誌檔案的寫入操作採用的是append模式,因此在寫入過程中即使出現宕機現象,也不會破壞日誌檔案中已經存在的內容

3)AOF包含一個格式清晰、易於理解的日誌檔案用於記錄所有的修改操作

缺點是檔案大、恢復速度慢、對效能影響大執行會慢於RDB

對於AOF持久化,向硬碟寫資料的頻率大大提高(everysec策略下為秒級), IO壓力更大,甚至可能造成AOF追加阻塞問題。

AOF檔案的重寫與RDB的bgsave類似,會有fork時的阻塞和子程序的IO壓力問題。相對來說,由於AOF向硬碟中寫資料的頻率更高,因此對 Redis主程序效能的影響會更大。

二者選擇的標準,就是看系統是願意犧牲一些效能,換取更高的快取一致性(aof),還是願意寫操作頻繁的時候,不啟用備份來換取更高的效能,待手動執行save的時候,再做備份(rdb)