天天看點

Redis 怎麼防止資料丢失?

Redis 怎麼防止資料丢失?
Redis要想實作高可用,主要有以下方面來保證:

  • 資料持久化
  • 主從複制
  • 自動故障恢複
  • 叢集化

這篇文章我們先介紹Redis的高可用保障的基礎:資料持久化。

因為Redis的主從複制和自動故障恢複,都需要依賴Redis持久化相關的東西。同時,Redis的資料持久化也可以用來做資料備份,用來保障資料的安全性。

Redis是一個記憶體資料庫,它的資料都儲存在記憶體中,如果執行個體當機,那麼資料則全部丢失。如何保證資料的完整性和安全性也是提高服務高可用的重要機制之一。

Redis提供了完善的持久化機制,可以把記憶體中的資料持久化到磁盤上,友善我們進行備份資料和快速恢複資料。

這篇文章我們就來分析Redis的資料持久化是如何實作的?我們經常聽的RDB和AOF有什麼差別?以及它們不同的使用場景。

持久化方式

Redis提供的資料持久化方式主要有2種:

  • RDB:産生一個資料快照檔案
  • AOF:實時追加指令的日志檔案

它們分别對應了不同的使用場景,下面我們就來依次分析。

RDB

介紹

RDB全稱Redis Database Backup file(Redis資料備份檔案),也被叫做Redis資料快照。

我們可以通過執行save或bgsave指令讓Redis在本地生成RDB快照檔案,這個RDB檔案包含了整個執行個體接近完整的資料内容。

Redis 怎麼防止資料丢失?

它的優點如下:

  • RDB檔案資料是被壓縮寫入的,是以RDB檔案的體積要比整個執行個體記憶體要小
  • 當執行個體當機恢複時,加載RDB檔案的速度很快,能夠在很短時間内迅速恢複檔案中的資料

它的缺點也很明顯:

  • 由于是某一時刻的資料快照,是以它的資料并不全
  • 生成RDB檔案的代價是比較大的,它會消耗大量的CPU和記憶體資源

是以RDB比較适用于以下場景:

  • 主從全量同步資料
  • 資料庫備份
  • 對于丢失資料不敏感的業務場景,執行個體當機後快速恢複資料

Redis主從全量同步資料就是使用RDB檔案進行的,我們會在後面的文章詳細講到,關注公衆号Java技術棧第一時間推送。

由此可以看出,RDB非常适合做資料備份,我們可以定時讓Redis生成RDB檔案,然後備份這個快照檔案即可。

定時生成RDB

Redis也提供了定時觸發生成RDB檔案的配置項:

# 最近15分鐘内 至少産生1次寫入  
save 900 1  
# 最近5分鐘内 至少産生10次寫入  
save 300 10  
# 最近1分鐘内 至少産生10000次寫入  
save 60 10000        

如果達到以上任意條件,則Redis會自動生成新的RDB檔案,降低RDB資料内容與執行個體資料的差異。

Copy On Write

在Redis上執行save和bgsave指令都可以生成RDB檔案,但前者是在前台執行的,也就是說在生成RDB檔案時,會阻塞整個執行個體,在RDB未生成之前,任何請求都是無法處理的,對于記憶體很大的執行個體,生成RDB檔案非常耗時,顯然這是我們不能接受的。

是以通常我們會選擇執行bgsave讓Redis在背景生成RDB檔案,這樣Redis依舊可以處理用戶端請求,不會阻塞整個執行個體。

但不是說背景生成RDB就是沒有代價的,Redis為了實作背景把記憶體資料的快照寫入檔案,采用了作業系統提供的Copy On Write技術,也就是我們熟知的fork系統調用。

fork系統調用會産生一個子程序,它與父程序共享相同的記憶體位址空間,這樣子程序在這一時刻就能擁有與父程序的相同的記憶體資料。

雖然子程序與父程序共享同一塊記憶體位址空間,但在fork子程序時,作業系統需要拷貝父程序的記憶體頁表給子程序,如果整個Redis執行個體記憶體占用很大,那麼它的記憶體頁表也會很大,在拷貝時就會比較耗時,同時這個過程會消耗大量的CPU資源。在完成拷貝之前父程序也處于阻塞狀态,無法處理用戶端請求。

fork執行完之後,子程序就可以掃描自身所有的記憶體資料,然後把全部資料寫入到RDB檔案中。

之後父程序依舊處理用戶端的請求,當在處理寫指令時,父程序會重新配置設定新的記憶體位址空間,從作業系統申請新的記憶體使用,不再與子程序共享,這個過程就是Copy On Write(寫實複制)名字的由來。這樣父子程序的記憶體就會逐漸分離,父程序申請新的記憶體空間并更改記憶體資料,子程序的記憶體資料不受影響。

由此可以看出,在生成RDB檔案時,不僅消耗CPU資源,還有需要占用最多一倍的記憶體空間。《Redis 開發陷阱及避坑指南》這篇推薦看下。

我們在Redis執行info指令,可以看到fork子程序的耗時,可以通過這個耗時來評估fork時間是否符合預期。同時我們應該保證Redis機器擁有足夠的CPU和記憶體資源,并合理設定生成RDB的時機。另外,關注公衆号Java技術棧回複redis可以擷取系列Redis教程。

AOF

AOF全稱為Append Only File(追加日志檔案)。它與RDB不同的是,AOF中記錄的是每一個指令的詳細資訊,包括完整的指令類型、參數等。隻要産生寫指令,就會實時寫入到AOF檔案中。

Redis 怎麼防止資料丢失?

我們可以通過配置檔案開啟AOF:

# 開啟AOF  
appendonly yes  
  
# AOF檔案名  
appendfilename "appendonly.aof"  
  
# 檔案刷盤方式  
appendfsync everysec        

刷盤方式

開啟AOF後,Redis會把每個寫操作的指令記錄到檔案并持久化到磁盤中,為了保證資料檔案的安全性,Redis還提供了檔案刷盤的時機:

  • appendfsync always:每次寫入都刷盤,對性能影響最大,占用磁盤IO比較高,資料安全性最高
  • appendfsync everysec:1秒刷一次盤,對性能影響相對較小,節點當機時最多丢失1秒的資料
  • appendfsync no:按照作業系統的機制刷盤,對性能影響最小,資料安全性低,節點當機丢失資料取決于作業系統刷盤機制

以上可以看出AOF相對于RDB的優點是,AOF資料檔案更新比較及時,比RDB儲存更完整的資料,這樣在資料恢複時能夠恢複盡量完整的資料,降低丢失資料的風險。

如果同時存在RDB檔案和AOF檔案,Redis會優先使用AOF檔案進行資料恢複。

但它的缺點也很易見:

  • 随着時間增長,AOF檔案會越來越大
  • AOF檔案刷盤會增加磁盤IO的負擔,可能影響Redis的性能(開啟每秒刷盤時)

AOF重寫

針對第一種情況,Redis提供了AOF瘦身的功能,可以設定在AOF檔案很大時,自動觸發AOF重寫,Redis會掃描整個執行個體的資料,重新生成一個AOF檔案達成瘦身的效果。但這個重寫過程也需要消耗大量的CPU資源。

# AOF檔案距離上次檔案增長超過多少百分比則觸發重寫  
auto-aof-rewrite-percentage 100  
# AOF檔案體積最小多大以上才觸發重寫  
auto-aof-rewrite-min-size 64mb        

由于AOF可以最大可能降低丢失資料的風險,是以它一般适用于對丢失資料很敏感的業務場景,例如涉及金錢交易的業務。

性能影響

如果AOF的刷盤時機設定為每次寫入都刷盤,那麼會大大降低Redis的寫入性能,因為每次寫指令都需要寫入檔案并刷到磁盤中才會傳回,當寫入量很大時,會增加磁盤IO的負擔。

性能與資料安全不能兼得,雖然Redis提供了實時刷盤的機制,但是在真正場景中使用的不多。

通常我們會選擇每秒刷盤這種方式,既能保證良好的寫入性能,在執行個體當機時最多丢失1秒的資料,做到性能和安全的平衡。

總結

我們對RDB和AOF的總結如下表。

Redis 怎麼防止資料丢失?

繼續閱讀