Redis持久化錦囊在手,再也不會擔心數(shù)據(jù)丟失了
Redis 的讀寫都是在內(nèi)存中進行的,所以它的性能高。而當我們的服務(wù)器斷開或者重啟的時候,數(shù)據(jù)就會消失,那么我們該怎么解決這個問題呢?
其實 Redis 已經(jīng)為我們提供了一種持久化的機制,分別是 RDB 和 AOF 兩種方式,接下來跟著我一起看看這兩個錦囊都是怎么保證數(shù)據(jù)的持久化的。
持久化
由于 Redis 是基于內(nèi)存的數(shù)據(jù)庫,所以當服務(wù)器出現(xiàn)故障的時候,我們的數(shù)據(jù)就得不到安全保障。
這個時候就需要將內(nèi)存中的數(shù)據(jù)存儲到磁盤中,當我們服務(wù)器重啟時,便可以通過磁盤來恢復(fù)數(shù)據(jù),這個過程就叫做 Redis 持久化。

Redis持久化
RDB
簡介
RDB全稱Redis Database Backup file(Redis數(shù)據(jù)備份文件),也可以稱為Redis數(shù)據(jù)快照。
RDB 文件是一個經(jīng)過壓縮的二進制文件(默認:dump.rdb); RDB 文件保存在硬盤里; 通過保存數(shù)據(jù)庫中的鍵值對來記錄數(shù)據(jù)庫狀態(tài)。
創(chuàng)建

SAVE 和 BGSAVE。SAVE
def SAVE():
# 創(chuàng)建 RDB 文件
rdbSave()

BGSAVE
def BGSAVE():
# 創(chuàng)建子進程
pid = fork()
if pid == 0:
# 子進程負責創(chuàng)建 RDB 文件
rdbSave()
# 完成之后向父進程發(fā)送信號
signal_parent()
elif pid > 0:
# 父進程繼續(xù)處理命令請求,并通過輪訓(xùn)等待子進程的信號
handle_request_and_wait_signal()
else:
handle_fork_error()

載入

主要設(shè)置
設(shè)置保存條件
save 900 1
save 300 10
服務(wù)器在 900 秒之內(nèi),對數(shù)據(jù)庫進行了至少 1 次修改了; 服務(wù)器在 300 秒之內(nèi),對數(shù)據(jù)庫進行了至少 10 次修改。
saveparams
saveparams 屬性。saveparams屬性是一個數(shù)組;數(shù)組中的每一個元素都是一個 saveparam結(jié)構(gòu);每個 saveparam結(jié)構(gòu)都保存了一個save選項設(shè)置的保存條件。
struct saveparam {
// 秒數(shù)
time_t seconds;
// 修改數(shù)
int changes;
}
dirty
dirty 計數(shù)器記錄距離上一次成功執(zhí)行 SAVE 命令或 BGSAVE 命令之后,服務(wù)器對數(shù)據(jù)庫狀態(tài)進行了多少次修改(包括寫入、刪除、更新等操作)。lastsave
UNINX 時間戳,記錄了服務(wù)器上一次成功執(zhí)行 SAVE 命令或者 BGSAVE 命令的時間。檢查保存條件是否滿足
serverCron (該函數(shù)對正在運行的服務(wù)器進行維護)默認每隔 100 毫秒就會執(zhí)行一次,其中一項工作就是檢查 save 選項所設(shè)置的保存條件是否已經(jīng)滿足,滿足的話就執(zhí)行 BGSAVE 命令。def serverCron():
# ....
# 遍歷所有保存條件
for saveparam in server.saveparams:
# 計算距離上次執(zhí)行保存操作有多少秒
save_interval = unixtime_now() - server.lastsave
# 如果數(shù)據(jù)庫狀態(tài)的修改次數(shù)超過條件所設(shè)置的次數(shù)
# 如果距離上次保存的時間超過條件所設(shè)置的時間
if server.dirty >= saveparam.changes and save_interval > saveparam.seconds:
BGSAVE()
默認配置
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#在給定的秒數(shù)和給定的對數(shù)據(jù)庫的寫操作數(shù)下,自動持久化操作。
# save <seconds> <changes>
#
save 900 1
save 300 10
save 60 10000
#bgsave發(fā)生錯誤時是否停止寫入,一般為yes
stop-writes-on-bgsave-error yes
#持久化時是否使用LZF壓縮字符串對象?
rdbcompression yes
#是否對rdb文件進行校驗和檢驗,通常為yes
rdbchecksum yes
# RDB持久化文件名
dbfilename dump.rdb
#持久化文件存儲目錄
dir ./
AOF
簡介
Append Only File(追加日志文件)。日志是寫后日志,Redis 是先執(zhí)行命令,把數(shù)據(jù)寫入內(nèi)存,然后才記錄日志。
通過保存 Redis 服務(wù)器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫狀態(tài); 寫入 AOF 文件的所有命令都是以 Redis 的命令請求協(xié)議格式保存的。
實現(xiàn)

命令追加
aof_buf 緩沖區(qū)的末尾。文件同步
flushAppendOnlyFile 函數(shù),這個函數(shù)會考慮是否需要將 aof_buf 緩沖區(qū)中的內(nèi)容寫入和保存到 AOF 文件里。flushAppendOnlyFile 函數(shù)執(zhí)行以下流程:WRITE:根據(jù)條件,將 aof_buf 中的緩存寫入到 AOF 文件; SAVE:根據(jù)條件,調(diào)用 fsync 或 fdatasync 函數(shù),將 AOF 文件保存到磁盤中。
appendfsync 的三個值:always、everysec、no 來影響的,也被稱為三種策略。Always

everysec

no

數(shù)據(jù)加載
創(chuàng)建一個不帶網(wǎng)絡(luò)連接的偽客戶端; 從 AOF 文件中分析并讀取出一條寫命令; 使用偽客戶端執(zhí)行被讀出的寫命令; 一直執(zhí)行步驟 2 和 3,直到 AOF 文件中的所有寫命令都被處理完畢為止。
文件重寫
為了解決 AOF 文件體積膨脹的問題; 通過重寫創(chuàng)建一個新的 AOF 文件來替代現(xiàn)有的 AOF 文件,新的 AOF 文件不會包含任何浪費空間的冗余命令。
實現(xiàn)
不需要對現(xiàn)有的 AOF 文件進行任何操作; 從數(shù)據(jù)庫中直接讀取鍵現(xiàn)在的值; 用一條命令記錄鍵值對,從而代替之前記錄這個鍵值對的多條命令。
后臺重寫
執(zhí)行客戶端發(fā)來的命令; 將執(zhí)行后的寫命令追加到 AOF 緩沖區(qū); 將執(zhí)行后的寫命令追加到 AOF 重寫緩沖區(qū)。

默認配置
############################## APPEND ONLY MODE ###############################
#開啟AOF持久化方式
appendonly no
#AOF持久化文件名
appendfilename "appendonly.aof"
#每秒把緩沖區(qū)的數(shù)據(jù)fsync到磁盤
appendfsync everysec
# appendfsync no
#是否在執(zhí)行重寫時不同步數(shù)據(jù)到AOF文件
no-appendfsync-on-rewrite no
# 觸發(fā)AOF文件執(zhí)行重寫的增長率
auto-aof-rewrite-percentage 100
#觸發(fā)AOF文件執(zhí)行重寫的最小size
auto-aof-rewrite-min-size 64mb
#redis在恢復(fù)時,會忽略最后一條可能存在問題的指令
aof-load-truncated yes
#是否打開混合開關(guān)
aof-use-rdb-preamble yes
總結(jié)
對于大中型的應(yīng)用,我們既想保證數(shù)據(jù)完整性又想保證高效率,就應(yīng)該結(jié)合使用 RDB 和 AOF 兩種方式; 如果只是需要保證數(shù)據(jù)的完整性,保護數(shù)據(jù)不會丟失,那么優(yōu)先使用 AOF 方式; 如果是處理大規(guī)模的數(shù)據(jù)恢復(fù),追求更高更快的效率的話,優(yōu)先使用 RDB 方式。

有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
