Redis連環(huán)11問
大家好,我是蘇三。
Redis作為如今最火的NoSQL數(shù)據(jù)庫,在大廠面試中出現(xiàn)的頻率越來越高,掌握Redis已成為后端開發(fā)工程師的必備技能。
庫森校招時,Redis就是殺手锏,好多次和面試官聊Redis都超過半小時,為面試超加分!
庫森將連載幾期Redis面試文章,這次帶來的是Redis基礎(chǔ)的面試題,先點(diǎn)贊和收藏再看吧~
老規(guī)矩,先上目錄~

1. Redis是什么?簡述它的優(yōu)缺點(diǎn)?
Redis本質(zhì)上是一個Key-Value類型的內(nèi)存數(shù)據(jù)庫,很像Memcached,整個數(shù)據(jù)庫加載在內(nèi)存當(dāng)中操作,定期通過異步操作把數(shù)據(jù)庫中的數(shù)據(jù)flush到硬盤上進(jìn)行保存。
因?yàn)槭羌儍?nèi)存操作,Redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value 數(shù)據(jù)庫。
優(yōu)點(diǎn):
讀寫性能極高, Redis能讀的速度是110000次/s,寫的速度是81000次/s。 支持?jǐn)?shù)據(jù)持久化,支持AOF和RDB兩種持久化方式。 支持事務(wù), Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個操作是原子性的。多個操作也支持事務(wù),即原子性,通過MULTI和EXEC指令包起來。 數(shù)據(jù)結(jié)構(gòu)豐富,除了支持string類型的value外,還支持hash、set、zset、list等數(shù)據(jù)結(jié)構(gòu)。 支持主從復(fù)制,主機(jī)會自動將數(shù)據(jù)同步到從機(jī),可以進(jìn)行讀寫分離。 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等特性。
缺點(diǎn):
數(shù)據(jù)庫容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。
2. Redis為什么這么快?
內(nèi)存存儲:Redis是使用內(nèi)存(in-memeroy)存儲,沒有磁盤IO上的開銷。數(shù)據(jù)存在內(nèi)存中,類似于 HashMap,HashMap 的優(yōu)勢就是查找和操作的時間復(fù)雜度都是O(1)。
單線程實(shí)現(xiàn)( Redis 6.0以前):Redis使用單個線程處理請求,避免了多個線程之間線程切換和鎖資源爭用的開銷。注意:單線程是指的是在核心網(wǎng)絡(luò)模型中,網(wǎng)絡(luò)請求模塊使用一個線程來處理,即一個線程處理所有網(wǎng)絡(luò)請求。
非阻塞IO:Redis使用多路復(fù)用IO技術(shù),將epoll作為I/O多路復(fù)用技術(shù)的實(shí)現(xiàn),再加上Redis自身的事件處理模型將epoll中的連接、讀寫、關(guān)閉都轉(zhuǎn)換為事件,不在網(wǎng)絡(luò)I/O上浪費(fèi)過多的時間。
優(yōu)化的數(shù)據(jù)結(jié)構(gòu):Redis有諸多可以直接應(yīng)用的優(yōu)化數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),應(yīng)用層可以直接使用原生的數(shù)據(jù)結(jié)構(gòu)提升性能。
使用底層模型不同:Redis直接自己構(gòu)建了 VM (虛擬內(nèi)存)機(jī)制 ,因?yàn)橐话愕南到y(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費(fèi)一定的時間去移動和請求。
Redis的VM(虛擬內(nèi)存)機(jī)制就是暫時把不經(jīng)常訪問的數(shù)據(jù)(冷數(shù)據(jù))從內(nèi)存交換到磁盤中,從而騰出寶貴的內(nèi)存空間用于其它需要訪問的數(shù)據(jù)(熱數(shù)據(jù))。通過VM功能可以實(shí)現(xiàn)冷熱數(shù)據(jù)分離,使熱數(shù)據(jù)仍在內(nèi)存中、冷數(shù)據(jù)保存到磁盤。這樣就可以避免因?yàn)閮?nèi)存不足而造成訪問速度下降的問題。
Redis提高數(shù)據(jù)庫容量的辦法有兩種:一種是可以將數(shù)據(jù)分割到多個RedisServer上;另一種是使用虛擬內(nèi)存把那些不經(jīng)常訪問的數(shù)據(jù)交換到磁盤上。需要特別注意的是Redis并沒有使用OS提供的Swap,而是自己實(shí)現(xiàn)。
3. Redis相比Memcached有哪些優(yōu)勢?
數(shù)據(jù)類型:Memcached所有的值均是簡單的字符串,Redis支持更為豐富的數(shù)據(jù)類型,支持string(字符串),list(列表),Set(集合)、Sorted Set(有序集合)、Hash(哈希)等。
持久化:Redis支持?jǐn)?shù)據(jù)落地持久化存儲,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中,重啟的時候可以再次加載進(jìn)行使用。Memcached不支持?jǐn)?shù)據(jù)持久存儲 。
集群模式:Redis提供主從同步機(jī)制,以及 Cluster集群部署能力,能夠提供高可用服務(wù)。Memcached沒有原生的集群模式,需要依靠客戶端來實(shí)現(xiàn)往集群中分片寫入數(shù)據(jù)
性能對比:Redis的速度比Memcached快很多。
網(wǎng)絡(luò)IO模型:Redis使用單線程的多路 IO 復(fù)用模型,Memcached使用多線程的非阻塞IO模式。
Redis支持服務(wù)器端的數(shù)據(jù)操作:Redis相比Memcached來說,擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作,通常在Memcached里,你需要將數(shù)據(jù)拿到客戶端來進(jìn)行類似的修改再set回去。
這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積。在Redis中,這些復(fù)雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作,那么Redis會是不錯的選擇。
4. Redis的常用場景有哪些?
1、緩存
緩存現(xiàn)在幾乎是所有中大型網(wǎng)站都在用的必殺技,合理的利用緩存不僅能夠提升網(wǎng)站訪問速度,還能大大降低數(shù)據(jù)庫的壓力。Redis提供了鍵過期功能,也提供了靈活的鍵淘汰策略,所以,現(xiàn)在Redis用在緩存的場合非常多。
2、排行榜
很多網(wǎng)站都有排行榜應(yīng)用的,如京東的月度銷量榜單、商品按時間的上新排行榜等。Redis提供的有序集合數(shù)據(jù)類構(gòu)能實(shí)現(xiàn)各種復(fù)雜的排行榜應(yīng)用。
3、計數(shù)器
什么是計數(shù)器,如電商網(wǎng)站商品的瀏覽量、視頻網(wǎng)站視頻的播放數(shù)等。為了保證數(shù)據(jù)實(shí)時效,每次瀏覽都得給+1,并發(fā)量高時如果每次都請求數(shù)據(jù)庫操作無疑是種挑戰(zhàn)和壓力。Redis提供的incr命令來實(shí)現(xiàn)計數(shù)器功能,內(nèi)存操作,性能非常好,非常適用于這些計數(shù)場景。
4、分布式會話
集群模式下,在應(yīng)用不多的情況下一般使用容器自帶的session復(fù)制功能就能滿足,當(dāng)應(yīng)用增多相對復(fù)雜的系統(tǒng)中,一般都會搭建以Redis等內(nèi)存數(shù)據(jù)庫為中心的session服務(wù),session不再由容器管理,而是由session服務(wù)及內(nèi)存數(shù)據(jù)庫管理。
5、分布式鎖
在很多互聯(lián)網(wǎng)公司中都使用了分布式技術(shù),分布式技術(shù)帶來的技術(shù)挑戰(zhàn)是對同一個資源的并發(fā)訪問,如全局ID、減庫存、秒殺等場景,并發(fā)量不大的場景可以使用數(shù)據(jù)庫的悲觀鎖、樂觀鎖來實(shí)現(xiàn),但在并發(fā)量高的場合中,利用數(shù)據(jù)庫鎖來控制資源的并發(fā)訪問是不太理想的,大大影響了數(shù)據(jù)庫的性能。可以利用Redis的setnx功能來編寫分布式的鎖,如果設(shè)置返回1說明獲取鎖成功,否則獲取鎖失敗,實(shí)際應(yīng)用中要考慮的細(xì)節(jié)要更多。
6、 社交網(wǎng)絡(luò)
點(diǎn)贊、踩、關(guān)注/被關(guān)注、共同好友等是社交網(wǎng)站的基本功能,社交網(wǎng)站的訪問量通常來說比較大,而且傳統(tǒng)的關(guān)系數(shù)據(jù)庫類型不適合存儲這種類型的數(shù)據(jù),Redis提供的哈希、集合等數(shù)據(jù)結(jié)構(gòu)能很方便的的實(shí)現(xiàn)這些功能。如在微博中的共同好友,通過Redis的set能夠很方便得出。
7、最新列表
Redis列表結(jié)構(gòu),LPUSH可以在列表頭部插入一個內(nèi)容ID作為關(guān)鍵字,LTRIM可用來限制列表的數(shù)量,這樣列表永遠(yuǎn)為N個ID,無需查詢最新的列表,直接根據(jù)ID去到對應(yīng)的內(nèi)容頁即可。
8、消息系統(tǒng)
消息隊(duì)列是大型網(wǎng)站必用中間件,如ActiveMQ、RabbitMQ、Kafka等流行的消息隊(duì)列中間件,主要用于業(yè)務(wù)解耦、流量削峰及異步處理實(shí)時性低的業(yè)務(wù)。Redis提供了發(fā)布/訂閱及阻塞隊(duì)列功能,能實(shí)現(xiàn)一個簡單的消息隊(duì)列系統(tǒng)。另外,這個不能和專業(yè)的消息中間件相比。
5. Redis的數(shù)據(jù)類型有哪些?
有五種常用數(shù)據(jù)類型:String、Hash、Set、List、SortedSet。以及三種特殊的數(shù)據(jù)類型:Bitmap、HyperLogLog、Geospatial ,其中HyperLogLog、Bitmap的底層都是 String 數(shù)據(jù)類型,Geospatial 的底層是 Sorted Set 數(shù)據(jù)類型。
五種常用的數(shù)據(jù)類型:
1、String:String是最常用的一種數(shù)據(jù)類型,普通的key- value 存儲都可以歸為此類。其中Value既可以是數(shù)字也可以是字符串。使用場景:常規(guī)key-value緩存應(yīng)用。常規(guī)計數(shù): 微博數(shù), 粉絲數(shù)。
2、Hash:Hash 是一個鍵值(key => value)對集合。Redishash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用于存儲對象,并且可以像數(shù)據(jù)庫中update一個屬性一樣只修改某一項(xiàng)屬性值。
3、Set:Set是一個無序的天然去重的集合,即Key-Set。此外還提供了交集、并集等一系列直接操作集合的方法,對于求共同好友、共同關(guān)注什么的功能實(shí)現(xiàn)特別方便。
4、List:List是一個有序可重復(fù)的集合,其遵循FIFO的原則,底層是依賴雙向鏈表實(shí)現(xiàn)的,因此支持正向、反向雙重查找。通過List,我們可以很方面的獲得類似于最新回復(fù)這類的功能實(shí)現(xiàn)。
5、SortedSet:類似于java中的TreeSet,是Set的可排序版。此外還支持優(yōu)先級排序,維護(hù)了一個score的參數(shù)來實(shí)現(xiàn)。適用于排行榜和帶權(quán)重的消息隊(duì)列等場景。
三種特殊的數(shù)據(jù)類型:
1、Bitmap:位圖,Bitmap想象成一個以位為單位數(shù)組,數(shù)組中的每個單元只能存0或者1,數(shù)組的下標(biāo)在Bitmap中叫做偏移量。使用Bitmap實(shí)現(xiàn)統(tǒng)計功能,更省空間。如果只需要統(tǒng)計數(shù)據(jù)的二值狀態(tài),例如商品有沒有、用戶在不在等,就可以使用 Bitmap,因?yàn)樗挥靡粋€ bit 位就能表示 0 或 1。
2、Hyperloglog。HyperLogLog 是一種用于統(tǒng)計基數(shù)的數(shù)據(jù)集合類型,HyperLogLog 的優(yōu)點(diǎn)是,在輸入元素的數(shù)量或者體積非常非常大
時,計算基數(shù)所需的空間總是固定 的、并且是很小的。每個 HyperLogLog 鍵只需要花費(fèi) 12 KB 內(nèi)存,就可以計算接近 2^64 個不同元素的基 數(shù)。
場景:統(tǒng)計網(wǎng)頁的UV(即Unique Visitor,不重復(fù)訪客,一個人訪問某個網(wǎng)站多次,但是還是只計算為一次)。
要注意,HyperLogLog 的統(tǒng)計規(guī)則是基于概率完成的,所以它給出的統(tǒng)計結(jié)果是有一定誤差的,標(biāo)準(zhǔn)誤算率是 0.81%。
3、Geospatial :主要用于存儲地理位置信息,并對存儲的信息進(jìn)行操作,適用場景如朋友的定位、附近的人、打車距離計算等。
6. Redis為何選擇單線程?
在Redisv6.0以前,Redis的核心網(wǎng)絡(luò)模型選擇用單線程來實(shí)現(xiàn)。先來看下官方的回答:
It's not very frequent that CPU becomes your bottleneck with Redis, as usually Redisis either memory or network bound. For instance, using pipelining Redisrunning on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU.
核心意思就是,對于一個 DB 來說,CPU 通常不會是瓶頸,因?yàn)榇蠖鄶?shù)請求不會是 CPU 密集型的,而是 I/O 密集型。
具體到 Redis的話,如果不考慮 RDB/AOF 等持久化方案,Redis是完全的純內(nèi)存操作,執(zhí)行速度是非常快的,因此這部分操作通常不會是性能瓶頸,Redis真正的性能瓶頸在于網(wǎng)絡(luò) I/O,也就是客戶端和服務(wù)端之間的網(wǎng)絡(luò)傳輸延遲,因此 Redis選擇了單線程的 I/O 多路復(fù)用來實(shí)現(xiàn)它的核心網(wǎng)絡(luò)模型。
實(shí)際上更加具體的選擇單線程的原因如下:
避免過多的上下文切換開銷:如果是單線程則可以規(guī)避進(jìn)程內(nèi)頻繁的線程切換開銷,因?yàn)槌绦蚴冀K運(yùn)行在進(jìn)程中單個線程內(nèi),沒有多線程切換的場景。 避免同步機(jī)制的開銷:如果 Redis選擇多線程模型,又因?yàn)?Redis是一個數(shù)據(jù)庫,那么勢必涉及到底層數(shù)據(jù)同步的問題,則必然會引入某些同步機(jī)制,比如鎖,而我們知道 Redis不僅僅提供了簡單的 key-value 數(shù)據(jù)結(jié)構(gòu),還有 list、set 和 hash 等等其他豐富的數(shù)據(jù)結(jié)構(gòu),而不同的數(shù)據(jù)結(jié)構(gòu)對同步訪問的加鎖粒度又不盡相同,可能會導(dǎo)致在操作數(shù)據(jù)過程中帶來很多加鎖解鎖的開銷,增加程序復(fù)雜度的同時還會降低性能。 簡單可維護(hù):如果 Redis使用多線程模式,那么所有的底層數(shù)據(jù)結(jié)構(gòu)都必須實(shí)現(xiàn)成線程安全的,這無疑又使得 Redis的實(shí)現(xiàn)變得更加復(fù)雜。
總而言之,Redis選擇單線程可以說是多方博弈之后的一種權(quán)衡:在保證足夠的性能表現(xiàn)之下,使用單線程保持代碼的簡單和可維護(hù)性。
7. Redis真的是單線程?
討論 這個問題前,先看下 Redis的版本中兩個重要的節(jié)點(diǎn):
Redis 4.0(引入多線程處理異步任務(wù)) Redis 6.0(正式在網(wǎng)絡(luò)模型中實(shí)現(xiàn) I/O 多線程)
所以,網(wǎng)絡(luò)上說的Redis是單線程,通常是指在Redis 6.0之前,其核心網(wǎng)絡(luò)模型使用的是單線程;而Redis的異步任務(wù)使用的仍是多線程。
Redis在 4.0 版本的時候就已經(jīng)引入了的多線程來做一些異步操作,此舉主要針對的是那些非常耗時的命令,通過將這些命令的執(zhí)行進(jìn)行異步化,避免阻塞單線程的事件循環(huán)。
在 Redis 4.0 之后增加了一些的非阻塞命令如
UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC。
8. Redisv6.0為何引入多線程?
很簡單,就是 Redis的網(wǎng)絡(luò) I/O 瓶頸已經(jīng)越來越明顯了。
隨著互聯(lián)網(wǎng)的飛速發(fā)展,互聯(lián)網(wǎng)業(yè)務(wù)系統(tǒng)所要處理的線上流量越來越大,Redis的單線程模式會導(dǎo)致系統(tǒng)消耗很多 CPU 時間在網(wǎng)絡(luò) I/O 上從而降低吞吐量,要提升 Redis的性能有兩個方向:
優(yōu)化網(wǎng)絡(luò) I/O 模塊 提高機(jī)器內(nèi)存讀寫的速度
后者依賴于硬件的發(fā)展,暫時無解。所以只能從前者下手,網(wǎng)絡(luò) I/O 的優(yōu)化又可以分為兩個方向:
零拷貝技術(shù)或者 DPDK 技術(shù) 利用多核優(yōu)勢
零拷貝技術(shù)有其局限性,無法完全適配 Redis這一類復(fù)雜的網(wǎng)絡(luò) I/O 場景,更多網(wǎng)絡(luò) I/O 對 CPU 時間的消耗和 Linux 零拷貝技術(shù)。而 DPDK 技術(shù)通過旁路網(wǎng)卡 I/O 繞過內(nèi)核協(xié)議棧的方式又太過于復(fù)雜以及需要內(nèi)核甚至是硬件的支持。
因此,利用多核優(yōu)勢成為了優(yōu)化網(wǎng)絡(luò) I/O 性價比最高的方案。
9. Redis過期鍵的刪除策略?
Redis的過期刪除策略就是:惰性刪除和定期刪除兩種策略配合使用。
惰性刪除:Redis的惰性刪除策略由db.c/expireIfNeeded函數(shù)實(shí)現(xiàn),所有鍵讀寫命令執(zhí)行之前都會調(diào)用 expireIfNeeded函數(shù)對其進(jìn)行檢查,如果過期,則刪除該鍵,然后執(zhí)行鍵不存在的操作;未過期則不作操作,繼續(xù)執(zhí)行原有的命令。
定期刪除:由Redis.c/activeExpireCycle 函數(shù)實(shí)現(xiàn),函數(shù)以一定的頻率運(yùn)行,每次運(yùn)行時,都從一定數(shù)量的數(shù)據(jù)庫中取出一定數(shù)量的隨機(jī)鍵進(jìn)行檢查,并刪除其中的過期鍵。
附:刪除key常見的三種處理方式。
1、定時刪除
在設(shè)置某個key 的過期時間同時,我們創(chuàng)建一個定時器,讓定時器在該過期時間到來時,立即執(zhí)行對其進(jìn)行刪除的操作。
優(yōu)點(diǎn):定時刪除對內(nèi)存是最友好的,能夠保存內(nèi)存的key一旦過期就能立即從內(nèi)存中刪除。
缺點(diǎn):對CPU最不友好,在過期鍵比較多的時候,刪除過期鍵會占用一部分 CPU 時間,對服務(wù)器的響應(yīng)時間和吞吐量造成影響。
2、惰性刪除
設(shè)置該key 過期時間后,我們不去管它,當(dāng)需要該key時,我們在檢查其是否過期,如果過期,我們就刪掉它,反之返回該key。
優(yōu)點(diǎn):對 CPU友好,我們只會在使用該鍵時才會進(jìn)行過期檢查,對于很多用不到的key不用浪費(fèi)時間進(jìn)行過期檢查。
缺點(diǎn):對內(nèi)存不友好,如果一個鍵已經(jīng)過期,但是一直沒有使用,那么該鍵就會一直存在內(nèi)存中,如果數(shù)據(jù)庫中有很多這種使用不到的過期鍵,這些鍵便永遠(yuǎn)不會被刪除,內(nèi)存永遠(yuǎn)不會釋放。從而造成內(nèi)存泄漏。
3、定期刪除
每隔一段時間,我們就對一些key進(jìn)行檢查,刪除里面過期的key。
優(yōu)點(diǎn):可以通過限制刪除操作執(zhí)行的時長和頻率來減少刪除操作對 CPU 的影響。另外定期刪除,也能有效釋放過期鍵占用的內(nèi)存。
缺點(diǎn):難以確定刪除操作執(zhí)行的時長和頻率。如果執(zhí)行的太頻繁,定期刪除策略變得和定時刪除策略一樣,對CPU不友好。如果執(zhí)行的太少,那又和惰性刪除一樣了,過期鍵占用的內(nèi)存不會及時得到釋放。另外最重要的是,在獲取某個鍵時,如果某個鍵的過期時間已經(jīng)到了,但是還沒執(zhí)行定期刪除,那么就會返回這個鍵的值,這是業(yè)務(wù)不能忍受的錯誤。
10. Redis內(nèi)存淘汰機(jī)制?
當(dāng)現(xiàn)有內(nèi)存大于 maxmemory 時,便會觸發(fā)Redis主動淘汰內(nèi)存方式,有如下幾種淘汰方式:
Redis 4.0前提供 6種數(shù)據(jù)淘汰策略:
volatile-lru:利用LRU算法移除設(shè)置過過期時間的key (LRU:最近使用 Least Recently Used ) allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的key(這個是最常用的) volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰 volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰 allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰 no-eviction:禁止驅(qū)逐數(shù)據(jù),也就是說當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯。這個應(yīng)該沒人使用吧!
Redis 4.0后增加以下兩種:
volatile-lfu:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰(LFU(Least Frequently Used)算法,也就是最頻繁被訪問的數(shù)據(jù)將來最有可能被訪問到) allkeys-lfu:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最不經(jīng)常使用的key。
11. Redis持久化機(jī)制?
為了能夠重用Redis數(shù)據(jù),或者防止系統(tǒng)故障,我們需要將Redis中的數(shù)據(jù)寫入到磁盤空間中,即持久化。Redis提供了兩種不同的持久化方法可以將數(shù)據(jù)存儲在磁盤中,一種叫快照RDB,另一種叫只追加文件AOF。
RDB
在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤(Snapshot),它恢復(fù)時是將快照文件直接讀到內(nèi)存里。
優(yōu)勢:適合大規(guī)模的數(shù)據(jù)恢復(fù);對數(shù)據(jù)完整性和一致性要求不高
劣勢:在一定間隔時間做一次備份,所以如果Redis意外down掉的話,就會丟失最后一次快照后的所有修改。
AOF
以日志的形式來記錄每個寫操作,將Redis執(zhí)行過的所有寫指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,Redis啟動之初會讀取該文件重新構(gòu)建數(shù)據(jù),換言之,Redis重啟的話就根據(jù)日志文件的內(nèi)容將寫指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復(fù)工作。
AOF采用文件追加方式,文件會越來越大,為避免出現(xiàn)此種情況,新增了重寫機(jī)制,當(dāng)AOF文件的大小超過所設(shè)定的閾值時, Redis就會啟動AOF文件的內(nèi)容壓縮,只保留可以恢復(fù)數(shù)據(jù)的最小指令集。
優(yōu)勢
每修改同步: appendfsync always同步持久化,每次發(fā)生數(shù)據(jù)變更會被立即記錄到磁盤,性能較差但數(shù)據(jù)完整性比較好。每秒同步: appendfsync everysec異步操作,每秒記錄,如果一秒內(nèi)宕機(jī),有數(shù)據(jù)丟失。不同步: appendfsync no從不同步。
劣勢
相同數(shù)據(jù)集的數(shù)據(jù)而言 aof文件要遠(yuǎn)大于rdb文件,恢復(fù)速度慢于rdb。aof運(yùn)行效率要慢于rdb,每秒同步策略效率較好,不同步效率和rdb相同。
如何選擇RDB和AOF
如果是數(shù)據(jù)不那么敏感,且可以從其他地方重新生成補(bǔ)回的,那么可以關(guān)閉持久化。 如果是數(shù)據(jù)比較重要,不想再從其他地方獲取,且可以承受數(shù)分鐘的數(shù)據(jù)丟失,比如緩存等,那么可以只使用RDB。 如果是用做內(nèi)存數(shù)據(jù)庫,要使用Redis的持久化,建議是RDB和AOF都開啟,或者定期執(zhí)行bgsave做快照備份,RDB方式更適合做數(shù)據(jù)的備份,AOF可以保證數(shù)據(jù)的不丟失。
Redis4.0 對于持久化機(jī)制的優(yōu)化
Redis4.0相對與3.X版本其中一個比較大的變化是4.0添加了新的混合持久化方式。
簡單的說:新的AOF文件前半段是RDB格式的全量數(shù)據(jù)后半段是AOF格式的增量數(shù)據(jù),如下圖:

優(yōu)勢:混合持久化結(jié)合了RDB持久化 和 AOF 持久化的優(yōu)點(diǎn), 由于絕大部分都是RDB格式,加載速度快,同時結(jié)合AOF,增量的數(shù)據(jù)以AOF方式保存了,數(shù)據(jù)更少的丟失。
劣勢:兼容性差,一旦開啟了混合持久化,在4.0之前版本都不識別該aof文件,同時由于前部分是RDB格式,閱讀性較差
