面試常問道:Redis持久化之AOF

2021-01-20 一線IT民工

業精於勤,荒於嬉。——韓愈

引導語

AOF是Redis的另外一種持久化方式。簡單來說,AOF就是將Redis服務端執行過的每一條命令都保存到一個文件,這樣當Redis重啟時只要按順序回放這些命令就會恢復到原始狀態。那麼,既然已經有了RDB為什麼還需要AOF呢?

1 AOF持久化方式

我們還是從RDB和AOF的實現方式考慮:RDB保存的是一個時間點的快照,那麼如果Redis出現了故障,丟失的就是從最後一次RDB執行的時間點到故障發生的時間間隔之內產生的數據。如果Redis數據量很大,QPS很高,那麼執行一次RDB需要的時間會相應增加,發生故障時丟失的數據也會增多。

而AOF保存的是一條條命令,理論上可以做到發生故障時只丟失一條命令。但由於作業系統中執行寫文件操作代價很大,Redis提供了配置參數,通過對安全性和性能的折中,我們可以設置不同的策略。

既然AOF數據安全性更高,是否可以只使用AOF呢?為什麼Redis推薦RDB和AOF同時開啟呢?

我們再深入考量一下這兩種實現方式:RDB保存的是最終的數據,是一個最終狀態,而AOF保存的是達到這個最終狀態的過程。很明顯,如果Redis有大量的修改操作,RDB中一個數據的最終態可能會需要大量的命令才能達到,這會造成AOF文件過大並且加載時速度過慢(Redis提供了一種AOF重寫的策略來解決上述問題,後文會詳細描述其實現原理)。

再來考慮一下AOF和RDB文件的加載過程。RDB只需要把相應數據加載到內存並生成相應的數據結構(有些結構如intset、ziplist,保存時直接按字符串保存,所以加載時速度會更快),而AOF文件的加載需要先創建一個偽客戶端,然後把命令一條條發送給Redis服務端,服務端再完整執行一遍相應的命令。根據Redis作者做的測試,RDB 10s~20s能加載1GB的文件,AOF的速度是RDB速度的一半(如果做了AOF重寫會加快)。

因為AOF和RDB各有優缺點,因此Redis一般會同時開啟AOF和RDB。

但假設線上同時配置了RDB和AOF,那麼會帶來如下的兩難選擇:重啟時如果優先加載RDB,加載速度更快,但是數據不是很全;如果優先加載AOF,加載速度會變慢,但是數據會比RDB中的要完整。

能不能結合這兩者的優點呢?答案是AOF和RDB的混合持久化方案。

2 AOF持久化的實現

AOF持久化功能的實現可以分為命令追加(append)、文件寫入、文件同步(sync)三個步驟。

a. 命令追加

當AOF持久化功能處於打開狀態時,伺服器在執行完一個寫命令之後,會以協議格式將被執行的寫命令追加到伺服器狀態的aof_buf緩衝區的末尾:

struct redisServer {

// ...

// AOF緩衝區

sds aof_buf;

// ...

};

b. AOF文件的寫入與同步

因為伺服器在處理文件事件時可能會執行寫命令,使得一些內容被追加到aof_buf緩衝區裡面,所以在伺服器每次結束一個事件循環之前,它都會調用flushAppendOnlyFile函數,考慮是否需要將aof_buf緩衝區中的內容寫入和保存到AOF文件裡面。

flushAppendOnlyFile函數的行為由伺服器配置的appendfsync選項的值來決定,各個不同值產生的行為如表11-1所示。

不同appendfsync值產生不同的持久化行

如果用戶沒有主動為appendfsync選項設置值,那麼appendfsync選項的默認值為everysec。

3 AOF持久化的效率和安全性

伺服器配置appendfsync選項的值直接決定AOF持久化功能的效率和安全性。

· 當appendfsync的值為always時,伺服器在每個事件循環都要將aof_buf緩衝區中的所有內容寫入到AOF文件,並且同步AOF文件,所以always的效率是appendfsync選項三個值當中最慢的一個,但從安全性來說,always也是最安全的,因為即使出現故障停機,AOF持久化也只會丟失一個事件循環中所產生的命令數據。

· 當appendfsync的值為everysec時,伺服器在每個事件循環都要將aof_buf緩衝區中的所有內容寫入到AOF文件,並且每隔一秒就要在子線程中對AOF文件進行一次同步。從效率上來講,everysec模式足夠快,並且就算出現故障停機,資料庫也只丟失一秒鐘的命令數據。

· 當appendfsync的值為no時,伺服器在每個事件循環都要將aof_buf緩衝區中的所有內容寫入到AOF文件,至於何時對AOF文件進行同步,則由作業系統控制。因為處於no模式下的flushAppendOnlyFile調用無須執行同步操作,所以該模式下的AOF文件寫入速度總是最快的,不過因為這種模式會在系統緩存中積累一段時間的寫入數據,所以該模式的單次同步時長通常是三種模式中時間最長的。從平攤操作的角度來看,no模式和everysec模式的效率類似,當出現故障停機時,使用no模式的伺服器將丟失上次同步AOF文件之後的所有寫命令數據。

4 AOF文件的載入和數據還原

a. 創建一個不帶網絡連接的偽客戶端(fake client):因為Redis的命令只能在客戶端上下文中執行,而載入AOF文件時所使用的命令直接來源於AOF文件而不是網絡連接,所以伺服器使用了一個沒有網絡連接的偽客戶端來執行AOF文件保存的寫命令,偽客戶端執行命令的效果和帶網絡連接的客戶端執行命令的效果完全一樣。

b. 從AOF文件中分析並讀取出一條寫命令。

c. 使用偽客戶端執行被讀出的寫命令。

d. 一直執行步驟2和步驟3,直到AOF文件中的所有寫命令都被處理完畢為止。

AOF文件載入過程

5 AOF重寫

因為AOF持久化是通過保存被執行的寫命令來記錄資料庫狀態的,所以隨著伺服器運行時間的流逝,AOF文件中的內容會越來越多,文件的體積也會越來越大,如果不加以控制的話,體積過大的AOF文件很可能對Redis伺服器、甚至整個宿主計算機造成影響,並且AOF文件的體積越大,使用AOF文件來進行數據還原所需的時間就越多。

為了解決AOF文件體積膨脹的問題,Redis提供了AOF文件重寫(rewrite)功能。通過該功能,Redis伺服器可以創建一個新的AOF文件來替代現有的AOF文件,新舊兩個AOF文件所保存的資料庫狀態相同,但新AOF文件不會包含任何浪費空間的冗餘命令,所以新AOF文件的體積通常會比舊AOF文件的體積要小得多。

雖然Redis將生成新AOF文件替換舊AOF文件的功能命名為「AOF文件重寫」,但實際上,AOF文件重寫並不需要對現有的AOF文件進行任何讀取、分析或者寫入操作,這個功能是通過讀取伺服器當前的資料庫狀態來實現的。

在實際中,為了避免在執行命令時造成客戶端輸入緩衝區溢出,重寫程序在處理列表、哈希表、集合、有序集合這四種可能會帶有多個元素的鍵時,會先檢查鍵所包含的元素數量,如果元素的數量超過了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那麼重寫程序將使用多條命令來記錄鍵的值,而不單單使用一條命令。

作為一種輔佐性的維護手段,Redis不希望AOF重寫造成伺服器無法處理請求,所以Redis決定將AOF重寫程序放到子進程裡執行,這樣做可以同時達到兩個目的:

a. 子進程進行AOF重寫期間,伺服器進程(父進程)可以繼續處理命令請求。

b. 子進程帶有伺服器進程的數據副本,使用子進程而不是線程,可以在避免使用鎖的情況下,保證數據的安全性。

重寫時數據一致性問題

使用子進程也有一個問題需要解決,因為子進程在進行AOF重寫期間,伺服器進程還需要繼續處理命令請求,而新的命令可能會對現有的資料庫狀態進行修改,從而使得伺服器當前的資料庫狀態和重寫後的AOF文件所保存的資料庫狀態不一致。

為了解決這種數據不一致問題,Redis伺服器設置了一個AOF重寫緩衝區,這個緩衝區在伺服器創建子進程之後開始使用,當Redis伺服器執行完一個寫命令之後,它會同時將這個寫命令發送給AOF緩衝區和AOF重寫緩衝區,如圖:

伺服器同時將命令發送給AOF文件和AOF重

6 AOF對過期鍵的處理

當伺服器以AOF持久化模式運行時,如果資料庫中的某個鍵已經過期,但它還沒有被惰性刪除或者定期刪除,那麼AOF文件不會因為這個過期鍵而產生任何影響。

當過期鍵被惰性刪除或者定期刪除之後,程序會向AOF文件追加(append)一條DEL命令,來顯式地記錄該鍵已被刪除。

和生成RDB文件時類似,在執行AOF重寫的過程中,程序會對資料庫中的鍵進行檢查,已過期的鍵不會被保存到重寫後的AOF文件中。

擴展:複製

當伺服器運行在複製模式下時,從伺服器的過期鍵刪除動作由主伺服器控制:

· 主伺服器在刪除一個過期鍵之後,會顯式地向所有從伺服器發送一個DEL命令,告知從伺服器刪除這個過期鍵。

· 從伺服器在執行客戶端發送的讀命令時,即使碰到過期鍵也不會將過期鍵刪除,而是繼續像處理未過期的鍵一樣來處理過期鍵。

· 從伺服器只有在接到主伺服器發來的DEL命令之後,才會刪除過期鍵。

通過由主伺服器來控制從伺服器統一地刪除過期鍵,可以保證主從伺服器數據的一致性,也正是因為這個原因,當一個過期鍵仍然存在於主伺服器的資料庫時,這個過期鍵在從伺服器裡的複製品也會繼續存在。

相關焦點

  • redis - aof持久化介紹
    AOF簡介redis持久化存儲的方式有rdb序列化存儲和aof(append only file)。aof就是將操作和數據以格式化指令的方式追加到操作日誌的尾部,在append操作返回後,才進行實際的數據變更。
  • 面試必問的 Redis:RDB、AOF、混合持久化
    慢工出細活吧,本文還是有很多非常細節的內容的,如果能掌握,讓大廠面試官眼前一亮還是問題不大的。  AOF、混合持久化(redis4.0引入)  RDB的實現原理、優缺點  描述:類似於快照。默認是 everysec,在這種配置下,redis 仍然可以保持良好的性能,並且就算發生故障停機,也最多只會丟失一秒鐘的數據。  2)AOF文件是一個純追加的日誌文件。即使日誌因為某些原因而包含了未寫入完整的命令(比如寫入時磁碟已滿,寫入中途停機等等), 我們也可以使用 redis-check-aof 工具也可以輕易地修復這種問題。
  • Redis RDB與AOF模式下的持久化原理
    前言:在此之前,如果還不了解Redis的,或者不知道怎麼使用Redis,可以參考官網網站:https://redis.io/documentation自行學習,本文主要針對Redis的核心點之一:RDB和AOF持久化模式進行展開。
  • 大數據必學:redis深入了解 Redis 的持久化機制(RDB、AOF)
    因為 redis是一個內存資料庫,所有數據都存儲在內存中,而且內存中的數據非常容易丟失,所以 redis的數據持久化就變得非常重要, redis提供了兩種數據持久化方法,分別用於 RDB和 AOF,而 redis默認用於 RDB的數據持久化方法。
  • 詳解Redis中兩種持久化機制RDB和AOF(面試常問,工作常用)
    redis是一個內存資料庫,數據保存在內存中,但是我們都知道內存的數據變化是很快的,也容易發生丟失。幸好Redis還為我們提供了持久化的機制,分別是RDB(Redis DataBase)和AOF(Append Only File)。在這裡假設你已經了解了redis的基礎語法,某字母網站都有很好的教程,可以去看。基本使用的文章就不寫了,都是一些常用的命令。
  • 詳解Redis持久化(RDB和AOF)
    日誌文件默認為appendonly.aof,Redis以Redis協議格式將命令保存至aof日誌文件末尾,aof文件還會被重寫,使aof文件的體積不會大於保存數據集狀態所需要的實際大小默認情況下,aof沒有被開啟。
  • Redis教程:Redis持久化方式
    使用 Redis 附帶的 redis-check-aof 程序,對原來的 AOF 文件進行修復: redis-check-aof –x(可選)使用 di -u 對比修復後的 AOF 文件和原始 AOF 文件的備份,查看兩個文件之間的不同之處。重啟 Redis 伺服器,等待伺服器載入修復後的 AOF 文件,並進行數據恢復。
  • Redis持久化和備份
    Redis與其他key-value存儲庫的不同之一是Redis運行在內存中但是可以持久化到磁碟,我們來看看Redis 持久化的相關方式。Redis 持久化在了解Redis持久化前,我們先來看看數據損壞的概念來幫助我們更好的理解後續的問題。
  • 面試官:說下 Redis 是如何保證在宕機後數據不丟失的
    首先我們說下什麼是持久化,持久化是將程序數據在持久狀態和瞬時狀態間轉換的機制。  RDB 和 AOF   前面說了什麼是持久化,現在說說 Redis 的持久化,眾所周知 Redis 的持久化有兩種方式,一種是快照形式 RDB,另一種是增量文件 AOF。
  • Redis中的過期鍵以及如何刪除的?
    1 伺服器中的資料庫Redis伺服器將所有資料庫都保存在伺服器狀態redis.h/redisServer結構的db數組中,db數組的每個項都是一個redis.h/redisDb結構,每個redisDb結構代表一個資料庫:struct redisServer {//一個數組,保存著伺服器中的所有資料庫redisDb *db;
  • 機率大的 Redis 面試題(含答案)|內存|key|原子性|哈希|redis_網易...
    來源:CSDN-_睶_blog.csdn.net/Butterfly_resting/article/details/89668661  本文的面試題如下:  Redis 持久化機制緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級等問題熱點數據和冷數據是什麼Memcache與Redis
  • Redis 2.4:後臺線程如何解決aof缺陷?
    ② 主線程裡backgroundRewriteDoneHandler函數在處理bgrewriteaof後臺進程退出的時候存在一個rename new-aof-file old-aof-file,然後再close old-aof-file的操作, close是一個unlink的操作(最後的引用計數), unlink消耗的時間取決於文件的大小,是個容易阻塞的系統調用.
  • Redis的批量操作是什麼?怎麼實現的延時隊列?以及訂閱模式、LRU
    前言這次的內容是我自己為了總結Redis知識而擴充的,上一篇其實已經總結了幾點知識了,但是Redis的強大,以及適用範圍之廣可不是單單一篇博文就能總結清的。所以這次準備繼續總結,因為第一個問題,Redis的批量操作,是我在面試過程中被真實問到的,當時沒答上來,也是因為確實沒了解過Redis的批量操作。
  • 985碩,秋招面試30家企業,怒斬阿里、字節、美團offer
    以上資料均免費和大家分享,只需要幫忙轉發一下,私信【學習】或【資料】即可獲取常考的有:1、Redis為什麼要作為緩存?高性能和高並發2、redis和memcached的區別3、redis常用數據結構、以及數據結構底層,常考到跳表的結構4、定期刪除、惰性刪除5、內存淘汰機制6、持久化機制7、緩存雪崩、緩存穿透、緩存擊穿8、並發競爭key問題9、緩存和資料庫雙寫時的數據一致性10、為什麼單線程還那麼快
  • redis cluster 之master 選舉過程
    在redis 3.0版本後,官方推出了redis cluster 分布式解決方案,當一個redis節點掛了可以快速地切換到另一個節點。當遇到單機內存、並發等瓶頸時,可以採用分布式方案要解決問題.redis-cluster架構中,被設計成共有16384(2的14次方)個hash slot。每個master分得一部分slot,其算法為:hash_slot = crc16(key) mod 16384 ,這就找到對應slot。群集至少需要3主3從,且每個實例使用不同的配置文件。
  • Redis如何存儲和計算一億用戶的活躍度
    01前段時間,在網上看到一道面試題:如何用redis存儲統計1億用戶一年的登陸情況,並快速檢索任意時間窗口內的活躍用戶數量。覺得很有意思,就仔細想了下 。並做了一系列實驗,自己模擬了下 。還是有點收穫的,現整理下來。
  • redis cluster 集群管理工具
    前言在redis源碼編譯的時候,在src目錄下會有一個redis-trib.rb的腳本,這個腳本是ruby寫的,用於管理redis cluster。安裝系統依賴包yum -y install epel-release yum -y install ruby rubygem-redis redis-trib.rb/opt/redis/bin/redis-trib.rb
  • Redis 3.0.0 RC4 發布,無 Redis Cluster 修復
    此版本包括關於 redis-cli 方面的新特性,一個使用 xterm 256 顏色的延遲光譜可視化工具。Reids 團隊計劃兩周後發布一個 RC 版本或者是 3.0.0 穩定版本。Reids 3.0.0.RC4 常規改進:* [FIX] redis-cli CSV output NIL spurious newline removed.
  • Python使用redis存儲對象
    Python總的對象存儲到redis中默認為字符串,那麼如何存儲對象呢?下面就看看如何直接將Python中對象存儲到redis中先寫個測試redis是否正常連接上import rediscache = redis.StrictRedis('172.20.0.227',6379)
  • Python 爬蟲面試題 170 道
    最近在刷面試題,所以需要看大量的 Python 相關的面試題,從大量的題目中總結了很多的知識,同時也對一些題目進行拓展了,但是在看了網上的大部分面試題都有這幾個問題:有些部分還是 Python2 的代碼回答的很簡單,關鍵的題目沒有點出為什麼