這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了關於持久化策略的相關內容,RDB持久化指的是在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,下面一起來看一下,希望對大家有幫助。
推薦學習:Redis影片教學
#Redis(Remote Dictionary Server ),即遠端字典服務,是一個開源的記憶體快取資料儲存服務。使用ANSI C 語言編寫,支援網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料存儲,並提供多種語言的API
Redis 是記憶體資料庫,資料都是儲存在記憶體中,為了避免進程退出導致資料的永久遺失,需要定期將Redis 中的資料以某種形式(資料或命令)從記憶體保存到硬碟。當下次 Redis 重新啟動時,利用持久化檔案實現資料復原。除此之外,為了進行災難備份,可以將持久化文件拷貝到一個遠端位置。 Redis 的持久化機制有兩種:
RDB 將目前資料儲存到硬碟,AOF 則是將每次執行的寫入指令儲存到硬碟(類似MySQL 的Binlog)。 AOF 持久化的即時性較好,即當進程意外退出時遺失的資料較少。
RDB(Redis
Data Base)
指的是指定的時間間隔內將記憶體中的資料集快照寫入磁碟,RDB 是記憶體快照(記憶體資料的二進位序列化形式)的方式持久化,每次都是從Redis 產生一個快照進行資料的全量備份。適合全量備份、全量複製的場景,經常用於災難復原(對資料的完整性和一致性要求相對較低的場合)。
RDB 透過 fork 子程序對記憶體快照進行全量備份,是一個重量級操作,頻繁執行成本高。
RDB 檔案結構
#在預設情況下,Redis 將資料庫快照保存在名字為dump.rdb 的二進位檔案中。 RDB 檔案結構由五個部分組成:
REDIS
常數字串。 (2)4位元組的 db_version,標識 RDB 檔案版本。 (3)databases:不定長度,包含零個或多個資料庫,以及各資料庫中的鍵值對資料。 (4)1位元組的 EOF 常數,表示檔案內文內容結束。(5)check_sum: 8位元組長的無符號整數,儲存校驗和。
資料結構舉例,以下是資料庫[0]和資料庫[3]有資料的情況:
RDB 檔案的建立
手動指令觸發#手動觸發RDB 持久化的方式可以使用
save
bgsave指令,這兩個指令的差異如下:
save
save指令,阻塞Redis 的其他動作,會導致Redis 無法回應客戶端請求,不建議使用。
bgsave
bgsave指令,Redis 後台建立子程序,非同步進行快照的儲存操作,此時 Redis 仍能回應客戶端的請求。
自動間隔性保存
在預設情況下,Redis 將資料庫快照保存在名字為 dump.rdb的二進位檔案中。可以對 Redis 進行設置,讓它在「 N 秒內資料集至少有 M 個改動」這一條件被滿足時,自動保存一次資料集。
Redis 的預設配置如下,三個設定滿足其一即可觸發自動儲存:
save 60 10000 save 300 10 save 900 1
#自動儲存配置的資料結構
##記錄了伺服器觸發自動BGSAVE條件的
saveparams屬性。
lastsave屬性:記錄伺服器最後一次執行
SAVE或
BGSAVE# 的時間。
dirty屬性:以及自從最後一次儲存 RDB 檔案以來,伺服器進行了多少次寫入。
在產生 RDB 檔案的步驟中,在同步到磁碟和持續寫入這個過程是如何處理資料不一致的情況呢?產生快照 RDB 檔案時是否會對業務產生影響?
AOF(Append Only File)是把所有对内存进行修改的指令(写操作)以独立日志文件的方式进行记录,重启时通过执行 AOF 文件中的 Redis 命令来恢复数据。类似MySql bin-log 原理。AOF 能够解决数据持久化实时性问题,是现在 Redis 持久化机制中主流的持久化方案。
优点:
缺点:
被写入 AOF 文件的所有命令都是以 RESP 格式保存的,是纯文本格式保存在 AOF 文件中。
Redis 客户端和服务端之间使用一种名为
RESP(REdis Serialization Protocol)
的二进制安全文本协议进行通信。
下面以一个简单的 SET 命令进行举例:
redis> SET mykey "hello" //客户端命令OK
客户端封装为以下格式(每行用\r\n
分隔)
*3$3SET$5mykey$5hello
AOF 文件中记录的文本内容如下
*2\r\n$6\r\nSELECT\r\n$1\r\n0\r\n //多出一个SELECT 0 命令,用于指定数据库,为系统自动添加 *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nhello\r\n
AOF 持久化方案进行备份时,客户端所有请求的写命令都会被追加到 AOF 缓冲区中,缓冲区中的数据会根据 Redis 配置文件中配置的同步策略来同步到磁盘上的 AOF 文件中,追加保存每次写的操作到文件末尾。同时当 AOF 的文件达到重写策略配置的阈值时,Redis 会对 AOF 日志文件进行重写,给 AOF 日志文件瘦身。Redis 服务重启的时候,通过加载 AOF 日志文件来恢复数据。
AOF 的执行流程包括:
命令追加(append)
Redis 先将写命令追加到缓冲区 aof_buf,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘 IO 成为 Redis 负载的瓶颈。
struct redisServer { //其他域... sds aof_buf; // sds类似于Java中的String //其他域...}
文件写入(write)和文件同步(sync)
根据不同的同步策略将 aof_buf 中的内容同步到硬盘;
Linux 操作系统中为了提升性能,使用了页缓存(page cache)。当我们将 aof_buf 的内容写到磁盘上时,此时数据并没有真正的落盘,而是在 page cache 中,为了将 page cache 中的数据真正落盘,需要执行 fsync / fdatasync 命令来强制刷盘。这边的文件同步做的就是刷盘操作,或者叫文件刷盘可能更容易理解一些。
AOF 缓存区的同步文件策略由参数 appendfsync 控制,有三种同步策略,各个值的含义如下:
always
:命令写入 aof_buf 后立即调用系统 write 操作和系统 fsync 操作同步到 AOF 文件,fsync 完成后线程返回。这种情况下,每次有写命令都要同步到 AOF 文件,硬盘 IO 成为性能瓶颈,Redis 只能支持大约几百TPS写入,严重降低了 Redis 的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低 SSD 的寿命。可靠性较高,数据基本不丢失。no
:命令写入 aof_buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。everysec
:命令写入 aof_buf 后调用系统 write 操作,write 完成后线程返回;fsync 同步文件操作由专门的线程每秒调用一次。everysec 是前述两种策略的折中,是性能和数据安全性的平衡,因此是 Redis 的默认配置,也是我们推荐的配置。文件重写(rewrite)
定期重写 AOF 文件,达到压缩的目的。
AOF 重写是 AOF 持久化的一个机制,用来压缩 AOF 文件,通过 fork 一个子进程,重新写一个新的 AOF 文件,该次重写不是读取旧的 AOF 文件进行复制,而是读取内存中的Redis数据库,重写一份 AOF 文件,有点类似于 RDB 的快照方式。
文件重写之所以能够压缩 AOF 文件,原因在于:
前面提到 AOF 的缺点时,说过 AOF 属于日志追加的形式来存储 Redis 的写指令,这会导致大量冗余的指令存储,从而使得 AOF 日志文件非常庞大,比如同一个 key 被写了 10000 次,最后却被删除了,这种情况不仅占内存,也会导致恢复的时候非常缓慢,因此 Redis 提供重写机制来解决这个问题。Redis 的 AOF 持久化机制执行重写后,保存的只是恢复数据的最小指令集,我们如果想手动触发可以使用如下指令:
bgrewriteaof
文件重写时机
相关参数:
同时满足下面两个条件,则触发 AOF 重写机制:
AOF重写流程如下:
bgrewriteaof 触发重写,判断是否存在 bgsave 或者 bgrewriteaof 正在执行,存在则等待其执行结束再执行
子进程遍历 Redis 内存快照中数据写入临时 AOF 文件,同时会将新的写指令写入 aof_buf 和 aof_rewrite_buf 两个重写缓冲区,前者是为了写回旧的 AOF 文件,后者是为了后续刷新到临时 AOF 文件中,防止快照内存遍历时新的写入操作丢失
子进程结束临时 AOF 文件写入后,通知主进程
主进程会将上面 3 中的 aof_rewirte_buf 缓冲区中的数据写入到子进程生成的临时 AOF 文件中
在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出,重写程序会检查集合元素数量是否超过 REDIS_AOF_REWRITE_ITEMS_PER_CMD 常量的值,如果超过了,则会使用多个命令来记录,而不单单使用一条命令。
Redis 2.9版本中该常量为64,如果一个命令的集合键包含超过了64个元素,重写程序会拆成多个命令。
AOF重写是一个有歧义的名字,该功能是通过直接读取数据库的键值对实现的,程序无需对现有AOF文件进行任何读入、分析或者写入操作。
Redis 为什么考虑使用 AOF 而不是 WAL 呢?
很多数据库都是采用的 Write Ahead Log(WAL)写前日志,其特点就是先把修改的数据记录到日志中,再进行写数据的提交,可以方便通过日志进行数据恢复。
但是 Redis 采用的却是 AOF(Append Only File)写后日志,特点就是先执行写命令,把数据写入内存中,再记录日志。
如果先讓系統執行指令,只有指令能執行成功,才會被記錄到日誌中。因此,Redis 使用寫後日誌這種形式,可以避免出現記錄錯誤命令的情況。
另外還有一個原因是:AOF 是在指令執行後才記錄日誌,所以不會阻塞目前的寫入操作。
在版本編號大於等於2.4的 Redis 中,BGSAVE 執行的過程中,不可以執行 BGREWRITEAOF。反過來說,在 BGREWRITEAOF 執行的過程中,也不可以執行 BGSAVE。這可以防止兩個 Redis 後台程序同時對磁碟進行大量的 I/O 操作。
如果 BGSAVE 正在執行,並且用戶顯示地調用 BGREWRITEAOF 命令,那麼伺服器將向用戶回復一個 OK 狀態,並告知用戶,BGREWRITEAOF 已經被預定執行:一旦 BGSAVE 執行完畢 BGREWRITEAOF 就會正式開始。
當 Redis 啟動時,如果 RDB 持久化和 AOF 持久化都被打開了,那麼程式會優先使用 AOF 檔案來還原資料集,因為 AOF 檔案所保存的資料通常是最完整的。
Redis4.0 後來大部分的使用情境都不會單獨使用RDB 或AOF 來做持久化機制,而是兼顧二者的優勢混合使用。原因是 RDB 雖然快,但會遺失比較多的數據,不能保證數據完整性;AOF 雖然能盡可能保證數據完整性,但是性能確實是一個詬病,例如重播恢復數據。
Redis從4.0版本開始引入RDB-AOF 混合持久化模式,這個模式是基於AOF 持久化模式建構而來的,混合持久化透過aof-use-rdb-preamble yes
開啟。
那麼Redis 伺服器在執行AOF 重寫操作時,就會像執行BGSAVE 指令那樣,根據資料庫目前的狀態產生出對應的RDB 數據,並將這些資料寫入新建的AOF 檔案中,至於那些在AOF 重寫開始之後執行的Redis 命令,則會繼續以協議文本的方式追加到新AOF 文件的末尾,即已有的RDB 數據的後面。
換句話說,在開啟了RDB-AOF 混合持久化功能之後,伺服器產生的AOF 檔案將由兩個部分組成,其中位於AOF 檔案開頭的是RDB 格式的數據,而跟在RDB 數據後面的則是AOF 格式的資料。
當一個支援 RDB-AOF 混合持久化模式的 Redis 伺服器啟動並載入 AOF 檔案時,它會檢查 AOF 檔案的開頭是否包含了 RDB 格式的內容。
其日誌檔案結構如下:
最後來總結這兩者,到底用哪個比較好呢?
推薦學習:Redis影片教學
#以上是Redis持久化策略淺析的詳細內容。更多資訊請關注PHP中文網其他相關文章!