由於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實現伺服器崩潰宕機的資料恢復的詳細內容。更多資訊請關注PHP中文網其他相關文章!