Redis持久化策略淺析
這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了關於持久化策略的相關內容,RDB持久化指的是在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,下面一起來看一下,希望對大家有幫助。
推薦學習:Redis影片教學
#Redis(Remote Dictionary Server ),即遠端字典服務,是一個開源的記憶體快取資料儲存服務。使用ANSI C 語言編寫,支援網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料存儲,並提供多種語言的API
Redis 是記憶體資料庫,資料都是儲存在記憶體中,為了避免進程退出導致資料的永久遺失,需要定期將Redis 中的資料以某種形式(資料或命令)從記憶體保存到硬碟。當下次 Redis 重新啟動時,利用持久化檔案實現資料復原。除此之外,為了進行災難備份,可以將持久化文件拷貝到一個遠端位置。 Redis 的持久化機制有兩種:
- RDB(Redis Data Base) 記憶體快照
- AOF(Append Only File) 增量日誌
RDB 將目前資料儲存到硬碟,AOF 則是將每次執行的寫入指令儲存到硬碟(類似MySQL 的Binlog)。 AOF 持久化的即時性較好,即當進程意外退出時遺失的資料較少。
RDB 持久化
#簡介
RDB ( Redis
Data Base)
指的是指定的時間間隔內將記憶體中的資料集快照寫入磁碟,RDB 是記憶體快照(記憶體資料的二進位序列化形式)的方式持久化,每次都是從Redis 產生一個快照進行資料的全量備份。- 優點:
- 儲存緊湊,節省記憶體空間。
- 恢復速度非常快。
適合全量備份、全量複製的場景,經常用於災難復原(對資料的完整性和一致性要求相對較低的場合)。
- 缺點:
- 容易遺失數據,容易遺失兩次快照之間 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 檔案以來,伺服器進行了多少次寫入。
- Redis 父程式先判斷:目前是否在執行save,或bgsave/bgrewriteaof 的子進程,如果在執行則bgsave 指令直接回傳。 bgsave/bgrewriteaof 的子程序不能同時執行,主要是基於效能方面的考量:兩個並發的子程序同時執行大量的磁碟寫入操作,可能會造成嚴重的效能問題。 父進程執行 fork 操作建立子進程,這個過程中父進程是阻塞的,Redis 不能執行來自客戶端的任何命令。父進程 fork 後,bgsave 指令返回」Background saving started」訊息並不再阻塞父進程,並且可以回應其他指令。
- 子進程對記憶體資料產生快照檔案。
- 父進程在此期間接收的新的寫入操作,使用 COW 機制寫入。
- 子程序完成快照寫入,取代舊 RDB 文件,隨後子程序退出。
在產生 RDB 檔案的步驟中,在同步到磁碟和持續寫入這個過程是如何處理資料不一致的情況呢?產生快照 RDB 檔案時是否會對業務產生影響?
Fork 子程序的作用
上面說到了RDB 持久化過程中,主程序會fork 一個子程序來負責RDB 的備份,這裡簡單介紹一下fork:- Linux 作業系統中的程序,fork 會產生一個和父進程完全相同的子進程。子進程與父進程所有的資料一致,但是子進程是全新的進程,與原進程是父子進程關係。
- 出於效率考慮,Linux 作業系統中使用COW(Copy On Write)寫時複製機制,fork 子進程一般情況下與父進程共同使用一段物理內存,只有在當進程空間中的記憶體發生修改時,記憶體空間才會複製一份出來。
AOF 持久化
简介
AOF (Append Only File) 是把所有对内存进行修改的指令(写操作)以独立日志文件的方式进行记录,重启时通过执行 AOF 文件中的 Redis 命令来恢复数据。类似MySql bin-log 原理。AOF 能够解决数据持久化实时性问题,是现在 Redis 持久化机制中主流的持久化方案。
优点:
- 数据的备份更加完整,丢失数据的概率更低,适合对数据完整性要求高的场景
- 日志文件可读,AOF 可操作性更强,可通过操作日志文件进行修复
缺点:
- AOF 日志记录在长期运行中逐渐庞大,恢复起来非常耗时,需要定期对 AOF 日志进行瘦身处理
- 恢复备份速度比较慢
- 同步写操作频繁会带来性能压力
AOF 文件内容
被写入 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 持久化方案进行备份时,客户端所有请求的写命令都会被追加到 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 文件,原因在于:
- 过期的数据不再写入文件
- 无效的命令不再写入文件:如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset)等等
- 多条命令可以合并为一个:如 sadd myset v1, sadd myset v2, sadd myset v3 可以合并为 sadd myset v1 v2 v3。不过为了防止单条命令过大造成客户端缓冲区溢出,对于 list、set、hash、zset类型的 key,并不一定只使用一条命令;而是以某个常量为界将命令拆分为多条。这个常量在 redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD 中定义,不可更改,2.9版本中值是64。
AOF 重写
前面提到 AOF 的缺点时,说过 AOF 属于日志追加的形式来存储 Redis 的写指令,这会导致大量冗余的指令存储,从而使得 AOF 日志文件非常庞大,比如同一个 key 被写了 10000 次,最后却被删除了,这种情况不仅占内存,也会导致恢复的时候非常缓慢,因此 Redis 提供重写机制来解决这个问题。Redis 的 AOF 持久化机制执行重写后,保存的只是恢复数据的最小指令集,我们如果想手动触发可以使用如下指令:
bgrewriteaof
文件重写时机
相关参数:
- aof_current_size:表示当前 AOF 文件空间
- aof_base_size:表示上一次重写后 AOF 文件空间
- auto-aof-rewrite-min-size: 表示运行 AOF 重写时文件的最小体积,默认为64MB
- auto-aof-rewrite-percentage: 表示当前 AOF 重写时文件空间(aof_current_size)超过上一次重写后 AOF 文件空间(aof_base_size)的比值多少后会重写。
同时满足下面两个条件,则触发 AOF 重写机制:
- aof_current_size 大于 auto-aof-rewrite-min-size
- 当前 AOF 相比上一次 AOF 的增长率:(aof_current_size - aof_base_size)/aof_base_size 大于或等于 auto-aof-rewrite-percentage
AOF 重写流程如下:
bgrewriteaof 触发重写,判断是否存在 bgsave 或者 bgrewriteaof 正在执行,存在则等待其执行结束再执行
- 主进程 fork 子进程,防止主进程阻塞无法提供服务,类似 RDB
子进程遍历 Redis 内存快照中数据写入临时 AOF 文件,同时会将新的写指令写入 aof_buf 和 aof_rewrite_buf 两个重写缓冲区,前者是为了写回旧的 AOF 文件,后者是为了后续刷新到临时 AOF 文件中,防止快照内存遍历时新的写入操作丢失
子进程结束临时 AOF 文件写入后,通知主进程
主进程会将上面 3 中的 aof_rewirte_buf 缓冲区中的数据写入到子进程生成的临时 AOF 文件中
- 主进程使用临时 AOF 文件替换旧 AOF 文件,完成整个重写过程。
在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出,重写程序会检查集合元素数量是否超过 REDIS_AOF_REWRITE_ITEMS_PER_CMD 常量的值,如果超过了,则会使用多个命令来记录,而不单单使用一条命令。
Redis 2.9版本中该常量为64,如果一个命令的集合键包含超过了64个元素,重写程序会拆成多个命令。
AOF重写是一个有歧义的名字,该功能是通过直接读取数据库的键值对实现的,程序无需对现有AOF文件进行任何读入、分析或者写入操作。
思考
AOF 与 WAL
Redis 为什么考虑使用 AOF 而不是 WAL 呢?
很多数据库都是采用的 Write Ahead Log(WAL)写前日志,其特点就是先把修改的数据记录到日志中,再进行写数据的提交,可以方便通过日志进行数据恢复。
但是 Redis 采用的却是 AOF(Append Only File)写后日志,特点就是先执行写命令,把数据写入内存中,再记录日志。
如果先讓系統執行指令,只有指令能執行成功,才會被記錄到日誌中。因此,Redis 使用寫後日誌這種形式,可以避免出現記錄錯誤命令的情況。
另外還有一個原因是:AOF 是在指令執行後才記錄日誌,所以不會阻塞目前的寫入操作。
AOF 和 RDB 之間的互動
在版本編號大於等於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 格式的內容。
- 如果包含,那麼伺服器就會先載入開頭的 RDB 數據,然後再載入之後的 AOF 資料。
- 如果 AOF 檔案只包含 AOF 數據,那麼伺服器將直接載入 AOF 資料。
其日誌檔案結構如下:
#總結
最後來總結這兩者,到底用哪個比較好呢?
- 推薦是兩者皆開啟。
- 如果對資料不敏感,可以選單獨用 RDB。
- 如果只是做純記憶體緩存,可以都不用。
推薦學習:Redis影片教學
#以上是Redis持久化策略淺析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Redis集群模式通過分片將Redis實例部署到多個服務器,提高可擴展性和可用性。搭建步驟如下:創建奇數個Redis實例,端口不同;創建3個sentinel實例,監控Redis實例並進行故障轉移;配置sentinel配置文件,添加監控Redis實例信息和故障轉移設置;配置Redis實例配置文件,啟用集群模式並指定集群信息文件路徑;創建nodes.conf文件,包含各Redis實例的信息;啟動集群,執行create命令創建集群並指定副本數量;登錄集群執行CLUSTER INFO命令驗證集群狀態;使

如何清空 Redis 數據:使用 FLUSHALL 命令清除所有鍵值。使用 FLUSHDB 命令清除當前選定數據庫的鍵值。使用 SELECT 切換數據庫,再使用 FLUSHDB 清除多個數據庫。使用 DEL 命令刪除特定鍵。使用 redis-cli 工具清空數據。

要從 Redis 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

在CentOS系統上,您可以通過修改Redis配置文件或使用Redis命令來限制Lua腳本的執行時間,從而防止惡意腳本佔用過多資源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位於/etc/redis/redis.conf。編輯配置文件:使用文本編輯器(例如vi或nano)打開配置文件:sudovi/etc/redis/redis.conf設置Lua腳本執行時間限制:在配置文件中添加或修改以下行,設置Lua腳本的最大執行時間(單位:毫秒)

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

Redis計數器是一種使用Redis鍵值對存儲來實現計數操作的機制,包含以下步驟:創建計數器鍵、增加計數、減少計數、重置計數和獲取計數。 Redis計數器的優勢包括速度快、高並發、持久性和簡單易用。它可用於用戶訪問計數、實時指標跟踪、遊戲分數和排名以及訂單處理計數等場景。

Redis數據過期策略有兩種:定期刪除:定期掃描刪除過期鍵,可通過 expired-time-cap-remove-count、expired-time-cap-remove-delay 參數設置。惰性刪除:僅在讀取或寫入鍵時檢查刪除過期鍵,可通過 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 參數設置。

在Debian系統中,readdir系統調用用於讀取目錄內容。如果其性能表現不佳,可嘗試以下優化策略:精簡目錄文件數量:盡可能將大型目錄拆分成多個小型目錄,降低每次readdir調用處理的項目數量。啟用目錄內容緩存:構建緩存機制,定期或在目錄內容變更時更新緩存,減少對readdir的頻繁調用。內存緩存(如Memcached或Redis)或本地緩存(如文件或數據庫)均可考慮。採用高效數據結構:如果自行實現目錄遍歷,選擇更高效的數據結構(例如哈希表而非線性搜索)存儲和訪問目錄信
