通過redis實現服務器崩潰宕機的數據恢復

通過redis實現服務器崩潰宕機的數據恢復

由于redis存儲在內存中且提供一般編程語言常用的數據結構存儲類型,所以經常被用于做服務器崩潰宕機的數據恢復處理。

服務器可以在某些指定過程中將需要保存的數據以json對象等方式存儲到redis中,也就是我們常說的快照,當服務器運行時讀取redis來判斷是否有待需要恢復數據繼續處理的業務。

當一次業務處理結束后再刪除redis的數據即可。

redis提供兩種將內存數據導出到硬盤實現數據備份的方法:

RDB方式(默認)

RDB方式的持久化是通過快照(snapshotting)完成的,當符合一定條件時Redis會自動將內存中的所有數據進行快照并存儲在硬盤上。進行快照的條件可以由用戶在配置文件中自定義,由兩個參數構成:時間和改動的鍵的個數。當在指定的時間內被更改的鍵的個數大于指定的數值時就會進行快照。RDB是redis默認采用的持久化方式,在配置文件中已經預置了3個條件:

save 900 1? ? # 900秒內有至少1個鍵被更改則進行快照

save 300 10? ?# 300秒內有至少10個鍵被更改則進行快照

save 60 10000 # 60秒內有至少10000個鍵被更改則進行快照

可以存在多個條件,條件之間是“或”的關系,只要滿足其中一個條件,就會進行快照。 如果想要禁用自動快照,只需要將所有的save參數刪除即可。

Redis默認會將快照文件存儲在當前目錄(可CONFIG GET dir來查看)的dump.rdb文件中,可以通過配置dir和dbfilename兩個參數分別指定快照文件的存儲路徑和文件名。

Redis實現快照的過程

Redis使用fork函數復制一份當前進程(父進程)的副本(子進程);

父進程繼續接收并處理客戶端發來的命令,而子進程開始將內存中的數據寫入硬盤中的臨時文件;

當子進程寫入完所有數據后會用該臨時文件替換舊的RDB文件,至此一次快照操作完成。

在執行fork的時候操作系統(類Unix操作系統)會使用寫時復制(copy-on-write)策略,即fork函數發生的一刻父子進程共享同一內存數據,當父進程要更改其中某片數據時(如執行一個寫命令 ),操作系統會將該片數據復制一份以保證子進程的數據不受影響,所以新的RDB文件存儲的是執行fork一刻的內存數據。

Redis在進行快照的過程中不會修改RDB文件,只有快照結束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。這使得我們可以通過定時備份RDB文件來實 現Redis數據庫備份。RDB文件是經過壓縮(可以配置rdbcompression參數以禁用壓縮節省CPU占用)的二進制格式,所以占用的空間會小于內存中的數據大小,更加利于傳輸。

除了自動快照,還可以手動發送SAVE或BGSAVE命令讓Redis執行快照,兩個命令的區別在于,前者是由主進程進行快照操作,會阻塞住其他請求,后者會通過fork子進程進行快照操作。 Redis啟動后會讀取RDB快照文件,將數據從硬盤載入到內存。根據數據量大小與結構和服務器性能不同,這個時間也不同。通常將一個記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內 存中需要花費20~30秒鐘。 通過RDB方式實現持久化,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數據。這就需要開發者根據具體的應用場合,通過組合設置自動快照條件的方式來將可能發生的數據損失控制在能夠接受的范圍。如果數據很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。

AOF方式

默認情況下Redis沒有開啟AOF(append only file)方式的持久化,可以在redis.conf中通過appendonly參數開啟:

appendonly yes

在啟動時Redis會逐個執行AOF文件中的命令來將硬盤中的數據載入到內存中,載入的速度相較RDB會慢一些

開啟AOF持久化后每執行一條會更改Redis中的數據的命令,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數設置的,默認的文件名是appendonly.aof,可以通過appendfilename參數修改:

appendfilename appendonly.aof

配置redis自動重寫AOF文件的條件

auto-aof-rewrite-percentage 100? # 當目前的AOF文件大小超過上一次重寫時的AOF文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫過,則以啟動時的AOF文件大小為依據

auto-aof-rewrite-min-size 64mb? ?# 允許重寫的最小AOF文件大小

配置寫入AOF文件后,要求系統刷新硬盤緩存的機制

# appendfsync always? ?# 每次執行寫入都會執行同步,最安全也最慢

appendfsync everysec? ?# 每秒執行一次同步操作

# appendfsync no? ? ? ?# 不主動進行同步操作,而是完全交由操作系統來做(即每30秒一次),最快也最不安全

Redis允許同時開啟AOF和RDB,既保證了數據安全又使得進行備份等操作十分容易。此時重新啟動Redis后Redis會使用AOF文件來恢復數據,因為AOF方式的持久化可能丟失的數據更少

redis?=?require('redis'),//導入js模塊 RDS_PORT?=?,????????//端口號 RDS_HOST?=?'',????//服務器IP RDS_OPTS?=?{},????????????//設置項 redisdb?=?redis.createClient(RDS_PORT,?RDS_HOST,?RDS_OPTS);//創建連接 ? redisdb.select(20);//指定分區庫 ? redisdb.on('ready',?function?(res)?{ ????console.log('ready'); }); ? redisdb.on('connect',?function?()?{ ????console.log('connect'); }); exports.redisdb?=?redisdb; ? function?redis_opt(opt,?key,?value,?callback)?{ ? ????if?(opt?==?'get')?{ ????????redisdb.get(key,?function?(err,?data)?{ ????????????if?(err?==?null)?{ ????????????????callback(data); ????????????} ????????????else?{ ????????????????callback(err); ????????????} ????????}); ????} ????else?if?(opt?==?'set') ????{ ????????redisdb.set(key,value,?function?(err,result)?{ ????????????if?(err?==?null)?{ ????????????????callback(result); ????????????} ????????????else?{ ????????????????callback(err); ????????????} ????????}); ????} ????else?if?(opt?==?'del') ????{ ????????redisdb.del(key,?function?(err,?result)?{ ????????????if?(err?==?null)?{ ????????????????callback(result); ????????????} ????????????else?{ ????????????????callback(err); ????????????} ????????}); ????} ????else ????{ ????????callback("error?opt!"); ????} ???? } ? function?update(key) { ????redis_opt("get",?key,?null,?function?(data)?{ ????????console.log("the?redis?data?is?"?+?data); ????????if?(data)?{ ????????????count?=?parseInt(data); ????????????redis_opt("set",?key,?++count?,?function?(data)?{ ????????????????console.log("set?"?+?count??+?"?"?+?data); ????????????});?? ????????} ????????else?{ ????????????redis_opt("set",?key,?10000,?function?(data)?{ ????????????????console.log("set?"?+?10000?+?"?"?+?data); ????????????});?? ????????} ????}); ? ? ? ? ? ???? ? ? ??? ? ? } ? function?clear(key) { ????redis_opt("del",?key,?null,?function?(ret)?{ ????????console.log("del?"?+?key?+?"?"?+?ret); ????});?? } ? ? ? function?main() { ? ????var?key?=?"count_test"; ? ????setInterval(function?()?{?clear(key)?},?5000); ? ????setInterval(function?()?{?update(key)?},?1000); ? } ? ? ? ? //testmain(); ? ? main();

以上代碼為簡單的計時器函數,即服務器啟動后定時讀取redis的數據,如果存在則累加修改,不存在則初始化,同時為了方便說明,又設置了一個定時刪除數據的定時器。

通過redis實現服務器崩潰宕機的數據恢復

通過redis實現服務器崩潰宕機的數據恢復

更多redis知識請關注redis入門教程欄目。

以上就是通過

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享