Redis 中 bgsave 方式持久化的細節問題


文章目錄
1.RDB的基本概念
2.RDB的觸發方式
2-1、配置文件
2-2、手工觸發
2-3、其他觸發方式
3.bgsave的工作流程
3-1、什么是cow
3-2、Redis面臨的問題
3-3、Redis的cow

因為有小伙伴問Redis的bgsave命令里面,cow(copy on write)到底是如何實現的,所以順便復習一下RDB相關的知識點。


1.RDB的基本概念
Redis有兩種數據持久化的方式:AOF和RDB。

簡單來說,AOF是記錄數據增量的方式,將每次對服務器寫的操作存入日志(類似MySQL的binlog);而RDB是記錄全量數據,根據指定的時間間隔對數據進行快照存儲,以二進制格式文件(后綴RDB)保存在硬盤當中。

 

2.RDB的觸發方式
2-1、配置文件
最常見的使用RDB進行持久化的方式,是在配置文件中配置Redis進行快照保存的時機:

save [seconds] [changes]

意為在[seconds]秒內如果發生了[changes]次數據修改,則進行一次RDB快照保存,例如

save 60 100

可以配置多條save指令,讓Redis執行多級的快照保存策略。

Redis默認開啟RDB快照,默認的RDB策略如下:

save 900 1
save 300 10
save 60 10000

 


2-2、手工觸發
也可以直接使用手工命令的方式觸發RDB生成快照文件。

一種是 save 命令

redis> save
OK

save 命令是同步方式生成快照,會造成Redis阻塞,所有后續到達的命令要等待save完成以后才能執行。

 

另一種是 bgsave 命令

redis> bgsave
Background saving started

bgsave 命令采用異步方式生成快照,Redis會fork出一個子進程進行RDB文件的生成。

Redis只有在fork子進程時被阻塞,子進程完成快照生成的同時,Redis可以正常工作。

 

 

2-3、其他觸發方式

  • 主從復制時,自動生成RDB文件
  • Redis中的debug reload提供debug級別的重啟(不清空內存),此時自動生成RDB文件
  • shutdown會自動生成RDB文件

 


3.bgsave的工作流程
重點說一下 bgsave 是如何使用異步方式生成快照的。

一般資料提到這里的時候都是一句話帶過,說Redis創建子進程以后,利用cow方式完成快照文件的生成。這沒有錯,但是大多數都沒說清楚這個cow是如何工作的。

我甚至在一些博客上看到“fork消耗額外內存”、“fork時對內存的消耗比較大”這樣的說法。

這其實是沒有理解清楚Redis fork出來的子進程是如何工作的。

 

 

3-1、什么是cow
cow = copy on write

這是一種簡單的讀寫分離思想,適用於讀多寫少的並發場景。比如黑白名單,熱點文章等等。

正常情況下我們說cow,指的是修改共享資源時,將共享資源copy一份,加鎖后修改,再將原容器的引用指向新的容器。

對於java來說,是有線程的cow容器的,比如CopyOnWriteArrayList。

另外就是cow保證的是最終一致性而不是強一致。

 

 

3-2、Redis面臨的問題
在Redis生成快照這個問題上,顯然不能直接使用標准的cow流程來操作。

很簡單,這會導致Redis的可用內存容量就直接減半。

cow的第一步是要將Redis在內存中的內容copy一份副本;然后主進程操作原數據,進行正常的讀寫操作,子進程利用副本專心寫盤,寫完以后銷毀子進程。

真的直接copy一份副本的話,多少內存夠用啊?這不是簡單的copy一個java容器那么簡單。

 

 

3-3、Redis的cow

  1. Redis創建子進程以后,根本不進行數據的copy,主進程與子線程是共享數據的。主進程繼續對外提供讀寫服務。
  2. 雖然不copy數據,但是kernel會把主進程中的所有內存頁的權限都設為read-only,主進程和子進程訪問數據的指針都指向同一內存地址。
  3. 主進程發生寫操作時,因為權限已經設置為read-only了,所以會觸發頁異常中斷(page-fault)。在中斷處理中,需要被寫入的內存頁面會復制一份,復制出來的舊數據交給子進程使用,然后主進程該干啥就干啥。

也就是說,在進行IO操作寫盤的過程中(on write),對於沒有改變的數據,主進程和子進程資源共享;只有在出現了需要變更的數據時(寫臟的數據),才進行copy操作。

在最理想的情況下,也就是生成RDB文件的過程中,一直沒有寫操作的話,就根本不會發生內存的額外占用。

當然,仍然需要合理配置Linux的內存分配策略。避免在寫操作過於集中時,發生因為物理內存不足導致fork失敗的情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM