歡迎關注公衆號:「碼農富哥」,致力於分享後端技術 (高併發架構,分佈式集羣系統,消息隊列中間件,網絡,微服務,Linux, TCP/IP, HTTP, MySQL, Redis), Python 等 原創乾貨 和 面試指南!
免費視頻福利推薦:web
在介紹Redis高可用以前,先說明一下在Redis的語境中高可用的含義。redis
咱們知道,在web服務器中,高可用是指服務器能夠正常訪問的時間,衡量的標準是在多長時間內能夠提供正常服務(99.9%、99.99%、99.999% 等等)。可是在Redis語境中,高可用的含義彷佛要寬泛一些,除了保證提供正常服務(如主從分離、快速容災技術),還須要考慮數據容量的擴展、數據安全不會丟失等。數據庫
在Redis中,實現高可用的技術主要包括持久化、複製、哨兵和集羣,下面分別說明它們的做用,以及解決了什麼樣的問題。編程
Redis 的數據所有在內存裏,若是忽然宕機,數據就會所有丟失,所以必須有一種機制來保證 Redis 的數據不會由於故障而丟失,這種機制就是 Redis 的持久化機制。後端
Redis爲持久化提供了兩種方式:緩存
因爲AOF持久化的實時性更好,即當進程意外退出時丟失的數據更少,所以AOF是目前主流的持久化方式,不過RDB持久化仍然有其用武之地。安全
下面依次介紹RDB持久化和AOF持久化;服務器
RDB是默認的持久化方式,按照必定的策略週期性的將內存中的數據生成快照保存到磁盤。網絡
每次快照持久化都是將內存數據完整寫入到磁盤一次,並非增量的只同步髒數據。若是數據量大的話,並且寫操做比較多,必然會引發大量的磁盤io操做,可能會嚴重影響性能。
RDB觸發持久化分爲手動觸發和自動觸發
當客戶端向Redis server發送save命令請求進行持久化時,因爲Redis是用一個主線程來處理全部,save命令會阻塞Redis server處理其餘客戶端的請求,直到數據同步完成。save命令會阻塞Redis服務器進程,直到RDB文件建立完畢爲止,在Redis服務器阻塞期間,服務器不能處理任何命令請求,所以線上環境不推薦使用
與save命令不一樣,bgsave是異步執行的,當執行bgsave命令以後,Redis主進程會fork 一個子進程將數據保存到rdb文件中,同步完數據以後,對原有文件進行替換,而後通知主進程表示同步完成。
除了手動觸發RDB持久化,Redis內部還存在自動觸發機制,
在配置中集中配置 save m n 的方式,表示 m秒內數據集存在n次修改時,系統自動觸發bgsave 操做。
# 時間策略 save 900 1 save 300 10 save 60 10000 # 文件名稱 dbfilename dump.rdb # 文件保存路徑 dir /etc/redis/data/ # 若是持久化出錯,主進程是否中止寫入 stop-writes-on-bgsave-error yes # 是否壓縮 rdbcompression yes # 導入時是否檢查 rdbchecksum yes rdb持久化策略比較簡單,下面解釋一下:
save 900 1
表示900s內若是有1條是寫入命令,就觸發產生一次快照,能夠理解爲就進行一次備份save 300 10
表示300s內有10條寫入,就產生快照
下面的相似,那麼爲何須要配置這麼多條規則呢?由於Redis每一個時段的讀寫請求確定不是均衡的,爲了平衡性能與數據安全,咱們能夠自由定製什麼狀況下觸發備份。因此這裏就是根據自身Redis寫入狀況來進行合理配置。
stop-writes-on-bgsave-error yes
這個配置也是很是重要的一項配置,這是當備份進程出錯時,主進程就中止接受新的寫入操做,是爲了保護持久化的數據一致性問題。若是本身的業務有完善的監控系統,能夠禁止此項配置, 不然請開啓。
rdbcompression yes
用於配置是否壓縮RDB文件,建議沒有必要開啓,畢竟Redis自己就屬於CPU密集型服務器,再開啓壓縮會帶來更多的CPU消耗,相比硬盤成本,CPU更值錢。
rdbchecksum yes
是否開啓RDB文件的校驗,在寫入文件和讀取文件時都起做用;關閉checksum在寫入文件和啓動文件時大約能帶來10%的性能提高,可是數據損壞時沒法發現
dbfilename dump.rdb
RDB文件名
dir ./
RDB文件和AOF文件所在目錄
固然若是你想要禁用RDB配置,也是很是容易的,只須要在save的最後一行寫上:save ""
1) Redis父進程首先判斷:當前是否在執行save,或bgsave/bgrewriteaof(後面會詳細介紹該命令)的子進程,若是在執行則bgsave命令直接返回。bgsave/bgrewriteaof 的子進程不能同時執行,主要是基於性能方面的考慮:兩個併發的子進程同時執行大量的磁盤寫操做,可能引發嚴重的性能問題。
2) 父進程執行fork操做建立子進程,這個過程當中父進程是阻塞的,Redis不能執行來自客戶端的任何命令
3) 父進程fork後,bgsave命令返回」Background saving started」信息並再也不阻塞父進程,並能夠響應其餘命令
4) 子進程建立RDB文件,根據父進程內存快照生成臨時快照文件,完成後對原有文件進行原子替換
5) 子進程發送信號給父進程表示完成,父進程更新統計信息
RDB文件的載入工做是在服務器啓動時自動執行的,並無專門的命令。可是因爲AOF的優先級更高,所以當AOF開啓時,Redis會優先載入AOF文件來恢復數據;
只有當AOF關閉時,纔會在Redis服務器啓動時檢測RDB文件,並自動載入。服務器載入RDB文件期間處於阻塞狀態,直到載入完成爲止。
因此Redis的內存數據若是很大,會致使數據恢復時間比較長,所以線上實踐更傾向於限制單個Redis的內存不能太大,同時結合Redis Cluster集羣使用多節點部署
Redis啓動日誌中能夠看到自動載入的執行:
Redis載入RDB文件時,會對RDB文件進行校驗,若是文件損壞,則日誌中會打印錯誤,Redis啓動失敗。
你們若是更系統瞭解Redis 高可用集羣架構知識,能夠關注公衆號【碼農富哥】後回覆【Redis】獲取 Redis高可用集羣架構視頻
RDB快照並非很可靠。若是你的電腦忽然宕機了,或者電源斷了,又或者不當心殺掉了進程,那麼最新的數據就會丟失。而AOF文件則提供了一種更爲可靠的持久化方式。每當Redis接受到會修改數據集的命令時,就會把命令追加到AOF文件裏,當你重啓Redis時,AOF裏的命令會被從新執行一次,重建數據。
因爲須要記錄Redis的每條寫命令,所以AOF不須要觸發, AOF的執行流程包括:
# 是否開啓aof appendonly yes # 文件名稱 appendfilename "appendonly.aof" # 同步方式 appendfsync everysec # aof重寫期間是否同步 no-appendfsync-on-rewrite no # 重寫觸發配置 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 加載aof時若是有錯如何處理 aof-load-truncated yes # 文件重寫策略 aof-rewrite-incremental-fsync yes
同步步驟分爲兩步:
Redis寫命令寫入磁盤的命令是經過appendfsync來配置的。
appendfsync 三個取值表明三種落盤策略:
always
:命令寫入aof緩衝區後當即調用系統fsync操做同步到AOF文件,fsync完成後線程返回。這種狀況下,每次有寫命令都要同步到AOF文件,硬盤IO成爲性能瓶頸。no
:命令寫入aof緩衝區後調用系統write操做,不對AOF文件作fsync同步;同步由操做系統負責,一般同步週期爲30秒。這種狀況下,文件同步的時間不可控,且緩衝區中堆積的數據會不少,數據安全性沒法保證。everysec
:命令寫入aof緩衝區後調用系統write操做,write完成後線程返回;fsync同步文件操做由專門的線程每秒調用一次。everysec是前述兩種策略的折中,是性能和數據安全性的平衡,所以是Redis的默認配置,也是咱們推薦的配置。隨着寫操做的不斷增長,AOF文件會愈來愈大。例如你遞增一個計數器100次,那麼最終結果就是數據集裏的計數器的值爲最終的遞增結果,可是AOF文件裏卻會把這100次操做完整的記錄下來。而事實上要恢復這個記錄,只須要1個命令就好了,也就是說AOF文件裏那100條命令其實能夠精簡爲1條。因此Redis支持這樣一個功能:在不中斷服務的狀況下在後臺重建AOF文件。
關於文件重寫的流程,有兩點須要特別注意:
(1)重寫由父進程fork子進程進行;
(2)重寫期間Redis執行的寫命令,須要追加到新的AOF文件中,爲此Redis引入了aof_rewrite_buf緩存。
對照上圖,文件重寫的流程以下:
1) Redis父進程首先判斷當前是否存在正在執行 bgsave/bgrewriteaof的子進程,若是存在則bgrewriteaof命令直接返回,若是存在bgsave命令則等bgsave執行完成後再執行。前面曾介紹過,這個主要是基於性能方面的考慮。
2) 父進程執行fork操做建立子進程,這個過程當中父進程是阻塞的。
3.1) 父進程fork後,bgrewriteaof命令返回」Background append only file rewrite started」信息並再也不阻塞父進程,並能夠響應其餘命令。Redis的全部寫命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬盤,保證原有AOF機制的正確。
3.2) 因爲fork操做使用寫時複製技術,子進程只能共享fork操做時的內存數據。因爲父進程依然在響應命令,所以Redis使用AOF重寫緩衝區(圖中的aof_rewrite_buf)保存這部分數據,防止新AOF文件生成期間丟失這部分數據。也就是說,bgrewriteaof執行期間,Redis的寫命令同時追加到aof_buf和aof_rewirte_buf兩個緩衝區。
4) 子進程根據內存快照,按照命令合併規則寫入到新的AOF文件。
5.1) 子進程寫完新的AOF文件後,向父進程發信號,父進程更新統計信息,具體能夠經過info persistence查看。
5.2) 父進程把AOF重寫緩衝區的數據寫入到新的AOF文件,這樣就保證了新AOF文件所保存的數據庫狀態和服務器當前狀態一致。
5.3) 使用新的AOF文件替換老文件,完成AOF重寫。
auto-aof-rewrite-percentage
和 auto-aof-rewrite-min-size
來完成auto-aof-rewrite-percentage 100
:Redis會記住自從上一次重寫後AOF文件的大小(若是自Redis啓動後還沒重寫過,則記住啓動時使用的AOF文件的大小)。若是當前的文件大小比起記住的那個大小超過指定的百分比,則會觸配置發重寫。
auto-aof-rewrite-min-size 64mb
:同時須要設置一個文件大小最小值,只有大於這個值文件纔會重寫,以防文件很小,可是已經達到百分比的狀況。
要禁用自動的日誌重寫功能,咱們能夠把百分比設置爲0:
auto-aof-rewrite-percentage 0
: 禁用日誌重寫功能
前面提到過,當AOF開啓時,Redis啓動時會優先載入AOF文件來恢復數據;
只有當AOF關閉時,纔會載入RDB文件恢復數據。
當AOF開啓,且AOF文件存在時,Redis啓動日誌:
RDB和AOF各有優缺點:
RDB持久化
AOF持久化
經過上面的分析,咱們都知道RDB的快照、AOF的重寫都須要fork,這是一個重量級操做,會對Redis形成阻塞。所以爲了避免影響Redis主進程響應,咱們須要儘量下降阻塞。
在線上咱們到底該怎麼作?我提供一些本身的實踐經驗。
Redis的高可用系列:持久化就已經講完了,持久化主要有RDB和AOF兩種技術,你們按照上面所介紹的原理和流程,根據線上具體需求選擇適合本身的持久化方案。
另外,寫原創技術文章不易,要花費好多時間和精力,但願你們看到文章也能有所收穫!大家的點贊和收藏就能成爲我繼續堅持輸出原創文章的動力!你們也能夠關注個人公衆號,訂閱更多個人文章!
歡迎關注公衆號:「碼農富哥
」,致力於分享後端技術 (高併發架構,分佈式集羣系統,消息隊列中間件,網絡,微服務,Linux, TCP/IP, HTTP, MySQL, Redis), Python 等 原創乾貨 和 面試指南!
關注公衆號後回覆【資源
】免費獲取 2T 編程視頻和電子書,回覆【Redis
】獲取 Redis高可用集羣架構視頻