1.項目中緩存是如何使用的?為什么要用緩存?緩存使用不當(dāng)會造成什么后果?
面試題剖析
為什么要用緩存?
用緩存,主要有兩個用途:高性能、高并發(fā)。
高性能
假設(shè)這么個場景,你有個操作,一個請求過來,吭哧吭哧你各種亂七八糟操作 mysql,半天查出來一個結(jié)果,耗時 600ms。但是這個結(jié)果可能接下來幾個小時都不會變了,或者變了也可以不用立即反饋給用戶。那么此時咋辦?
緩存啊,折騰 600ms 查出來的結(jié)果,扔緩存里,一個 key 對應(yīng)一個 value,下次再有人查,別走 mysql 折騰 600ms 了,直接從緩存里,通過一個 key 查出來一個 value,2ms 搞定。性能提升 300 倍。
就是說對于一些需要復(fù)雜操作耗時查出來的結(jié)果,且確定后面不怎么變化,但是有很多讀請求,那么直接將查詢出來的結(jié)果放在緩存中,后面直接讀緩存就好。
高并發(fā)
mysql 這么重的數(shù)據(jù)庫,壓根兒設(shè)計不是讓你玩兒高并發(fā)的,雖然也可以玩兒,但是天然支持不好。mysql 單機支撐到 2000QPS
也開始容易報警了。
所以要是你有個系統(tǒng),高峰期一秒鐘過來的請求有 1萬,那一個 mysql 單機絕對會死掉。你這個時候就只能上緩存,把很多數(shù)據(jù)放緩存,別放 mysql。緩存功能簡單,說白了就是 key-value
式操作,單機支撐的并發(fā)量輕松一秒幾萬十幾萬,支撐高并發(fā) so easy。單機承載并發(fā)量是 mysql 單機的幾十倍。
緩存是走內(nèi)存的,內(nèi)存天然就支撐高并發(fā)。
2.redis 和 memcached 有什么區(qū)別?redis 的線程模型是什么?為什么 redis 單線程卻能支撐高并發(fā)?
考點分析
這個是問 redis 的時候,最基本的問題吧,redis 最基本的一個內(nèi)部原理和特點,就是 redis 實際上是個單線程工作模型,你要是這個都不知道,那后面玩兒 redis 的時候,出了問題豈不是什么都不知道?
還有可能面試官會問問你 redis 和 memcached 的區(qū)別,但是 memcached 是早些年各大互聯(lián)網(wǎng)公司常用的緩存方案,但是現(xiàn)在近幾年基本都是 redis,沒什么公司用 memcached 了。
面試題剖析
redis 和 memcached 有啥區(qū)別?
redis 支持復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
redis 相比 memcached 來說,擁有更多的數(shù)據(jù)結(jié)構(gòu),能支持更豐富的數(shù)據(jù)操作。如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作, redis 會是不錯的選擇。
redis 原生支持集群模式
在 redis3.x 版本中,便能支持 cluster 模式,而 memcached 沒有原生的集群模式,需要依靠客戶端來實現(xiàn)往集群中分片寫入數(shù)據(jù)。
性能對比
由于 redis 只使用單核,而 memcached 可以使用多核,所以平均每一個核上 redis 在存儲小數(shù)據(jù)時比 memcached 性能更高。而在 100k 以上的數(shù)據(jù)中,memcached 性能要高于 redis,雖然 redis 最近也在存儲大數(shù)據(jù)的性能上進行優(yōu)化,但是比起 memcached,還是稍有遜色。
redis 的線程模型
redis 內(nèi)部使用文件事件處理器 file event handler
,這個文件事件處理器是單線程的,所以 redis 才叫做單線程的模型。它采用 IO 多路復(fù)用機制同時監(jiān)聽多個 socket,根據(jù) socket 上的事件來選擇對應(yīng)的事件處理器進行處理。
文件事件處理器的結(jié)構(gòu)包含 4 個部分:
- 多個 socket
- IO 多路復(fù)用程序
- 文件事件分派器
- 事件處理器(連接應(yīng)答處理器、命令請求處理器、命令回復(fù)處理器)
多個 socket 可能會并發(fā)產(chǎn)生不同的操作,每個操作對應(yīng)不同的文件事件,但是 IO 多路復(fù)用程序會監(jiān)聽多個 socket,會將 socket 產(chǎn)生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應(yīng)的事件處理器進行處理。
來看客戶端與 redis 的一次通信過程:
客戶端 socket01 向 redis 的 server socket 請求建立連接,此時 server socket 會產(chǎn)生一個 AE_READABLE
事件,IO 多路復(fù)用程序監(jiān)聽到 server socket 產(chǎn)生的事件后,將該事件壓入隊列中。文件事件分派器從隊列中獲取該事件,交給連接應(yīng)答處理器。連接應(yīng)答處理器會創(chuàng)建一個能與客戶端通信的 socket01,并將該 socket01 的 AE_READABLE
事件與命令請求處理器關(guān)聯(lián)。
假設(shè)此時客戶端發(fā)送了一個 set key value
請求,此時 redis 中的 socket01 會產(chǎn)生 AE_READABLE
事件,IO 多路復(fù)用程序?qū)⑹录喝腙犃校藭r事件分派器從隊列中獲取到該事件,由于前面 socket01 的 AE_READABLE
事件已經(jīng)與命令請求處理器關(guān)聯(lián),因此事件分派器將事件交給命令請求處理器來處理。命令請求處理器讀取 socket01 的 key value
并在自己內(nèi)存中完成 key value
的設(shè)置。操作完成后,它會將 socket01 的 AE_WRITABLE
事件與命令回復(fù)處理器關(guān)聯(lián)。
如果此時客戶端準備好接收返回結(jié)果了,那么 redis 中的 socket01 會產(chǎn)生一個 AE_WRITABLE
事件,同樣壓入隊列中,事件分派器找到相關(guān)聯(lián)的命令回復(fù)處理器,由命令回復(fù)處理器對 socket01 輸入本次操作的一個結(jié)果,比如 ok
,之后解除 socket01 的 AE_WRITABLE
事件與命令回復(fù)處理器的關(guān)聯(lián)。
這樣便完成了一次通信。
為啥 redis 單線程模型也能效率這么高?
- 純內(nèi)存操作
- 核心是基于非阻塞的 IO 多路復(fù)用機制
- 單線程反而避免了多線程的頻繁上下文切換問題
3.redis 都有哪些數(shù)據(jù)類型?分別在哪些場景下使用比較合適?
面試題剖析
redis 主要有以下幾種數(shù)據(jù)類型:
- string
- hash
- list
- set
- sorted set
string
這是最簡單的類型,就是普通的 set 和 get,做簡單的 KV 緩存。
set college szu
hash
這個是類似 map 的一種結(jié)構(gòu),這個一般就是可以將結(jié)構(gòu)化的數(shù)據(jù),比如一個對象(前提是這個對象沒嵌套其他的對象)給緩存在 redis 里,然后每次讀寫緩存的時候,可以就操作 hash 里的某個字段。
hset person name bingo
hset person age 20
hset person id 1
hget person name
person = {
"name": "bingo",
"age": 20,
"id": 1
}
list
list 是有序列表,這個可以玩兒出很多花樣。
比如可以通過 list 存儲一些列表型的數(shù)據(jù)結(jié)構(gòu),類似粉絲列表、文章的評論列表之類的東西。
比如可以通過 lrange 命令,讀取某個閉區(qū)間內(nèi)的元素,可以基于 list 實現(xiàn)分頁查詢,這個是很棒的一個功能,基于 redis 實現(xiàn)簡單的高性能分頁,可以做類似微博那種下拉不斷分頁的東西,性能高,就一頁一頁走。
# 0開始位置,-1結(jié)束位置,結(jié)束位置為-1時,表示列表的最后一個位置,即查看所有。
lrange mylist 0 -1
比如可以搞個簡單的消息隊列,從 list 頭懟進去,從 list 尾巴那里弄出來。
lpush mylist 1
lpush mylist 2
lpush mylist 3 4 5
# 1
rpop mylist
set
set 是無序集合,自動去重。
直接基于 set 將系統(tǒng)里需要去重的數(shù)據(jù)扔進去,自動就給去重了,如果你需要對一些數(shù)據(jù)進行快速的全局去重,你當(dāng)然也可以基于 jvm 內(nèi)存里的 HashSet 進行去重,但是如果你的某個系統(tǒng)部署在多臺機器上呢?得基于 redis 進行全局的 set 去重。
可以基于 set 玩兒交集、并集、差集的操作,比如交集吧,可以把兩個人的粉絲列表整一個交集,看看倆人的共同好友是誰?對吧。
把兩個大 V 的粉絲都放在兩個 set 中,對兩個 set 做交集。
#-------操作一個set-------
# 添加元素
sadd mySet 1
# 查看全部元素
smembers mySet
# 判斷是否包含某個值
sismember mySet 3
# 刪除某個/些元素
srem mySet 1
srem mySet 2 4
# 查看元素個數(shù)
scard mySet
# 隨機刪除一個元素
spop mySet
#-------操作多個set-------
# 將一個set的元素移動到另外一個set
smove yourSet mySet 2
# 求兩set的交集
sinter yourSet mySet
# 求兩set的并集
sunion yourSet mySet
# 求在yourSet中而不在mySet中的元素
sdiff yourSet mySet
sorted set
sorted set 是排序的 set,去重但可以排序,寫進去的時候給一個分數(shù),自動根據(jù)分數(shù)排序。
zadd board 85 zhangsan
zadd board 72 lisi
zadd board 96 wangwu
zadd board 63 zhaoliu
# 獲取排名前三的用戶(默認是升序,所以需要 rev 改為降序)
zrevrange board 0 3
# 獲取某用戶的排名
zrank board zhaoliu
4.redis 的過期策略都有哪些?內(nèi)存淘汰機制都有哪些?手寫一下 LRU 代碼實現(xiàn)?
考點分析
如果你連這個問題都不知道,上來就懵了,回答不出來,那線上你寫代碼的時候,想當(dāng)然的認為寫進 redis 的數(shù)據(jù)就一定會存在,后面導(dǎo)致系統(tǒng)各種 bug,誰來負責(zé)?
常見的有兩個問題:
- 往 redis 寫入的數(shù)據(jù)怎么沒了?
可能有同學(xué)會遇到,在生產(chǎn)環(huán)境的 redis 經(jīng)常會丟掉一些數(shù)據(jù),寫進去了,過一會兒可能就沒了。我的天,同學(xué),你問這個問題就說明 redis 你就沒用對啊。redis 是緩存,你給當(dāng)存儲了是吧?
啥叫緩存?用內(nèi)存當(dāng)緩存。內(nèi)存是無限的嗎,內(nèi)存是很寶貴而且是有限的,磁盤是廉價而且是大量的。可能一臺機器就幾十個 G 的內(nèi)存,但是可以有幾個 T 的硬盤空間。redis 主要是基于內(nèi)存來進行高性能、高并發(fā)的讀寫操作的。
那既然內(nèi)存是有限的,比如 redis 就只能用 10G,你要是往里面寫了 20G 的數(shù)據(jù),會咋辦?當(dāng)然會干掉 10G 的數(shù)據(jù),然后就保留 10G 的數(shù)據(jù)了。那干掉哪些數(shù)據(jù)?保留哪些數(shù)據(jù)?當(dāng)然是干掉不常用的數(shù)據(jù),保留常用的數(shù)據(jù)了。
- 數(shù)據(jù)明明過期了,怎么還占用著內(nèi)存?
這是由 redis 的過期策略來決定。
面試題剖析
redis 過期策略
redis 過期策略是:定期刪除+惰性刪除。
所謂定期刪除,指的是 redis 默認是每隔 100ms 就隨機抽取一些設(shè)置了過期時間的 key,檢查其是否過期,如果過期就刪除。
假設(shè) redis 里放了 10w 個 key,都設(shè)置了過期時間,你每隔幾百毫秒,就檢查 10w 個 key,那 redis 基本上就死了,cpu 負載會很高的,消耗在你的檢查過期 key 上了。注意,這里可不是每隔 100ms 就遍歷所有的設(shè)置過期時間的 key,那樣就是一場性能上的災(zāi)難。實際上 redis 是每隔 100ms 隨機抽取一些 key 來檢查和刪除的。
但是問題是,定期刪除可能會導(dǎo)致很多過期 key 到了時間并沒有被刪除掉,那咋整呢?所以就是惰性刪除了。這就是說,在你獲取某個 key 的時候,redis 會檢查一下 ,這個 key 如果設(shè)置了過期時間那么是否過期了?如果過期了此時就會刪除,不會給你返回任何東西。
獲取 key 的時候,如果此時 key 已經(jīng)過期,就刪除,不會返回任何東西。
但是實際上這還是有問題的,如果定期刪除漏掉了很多過期 key,然后你也沒及時去查,也就沒走惰性刪除,此時會怎么樣?如果大量過期 key 堆積在內(nèi)存里,導(dǎo)致 redis 內(nèi)存塊耗盡了,咋整?
答案是:走內(nèi)存淘汰機制。
內(nèi)存淘汰機制
redis 內(nèi)存淘汰機制有以下幾個:
- noeviction: 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯,這個一般沒人用吧,實在是太惡心了。
- allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)。
- allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,隨機移除某個 key,這個一般沒人用吧,為啥要隨機,肯定是把最近最少使用的 key 給干掉啊。
- volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,移除最近最少使用的 key(這個一般不太合適)。
- volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,隨機移除某個 key。
- volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,有更早過期時間的 key 優(yōu)先移除。
手寫一個 LRU 算法
你可以現(xiàn)場手寫最原始的 LRU 算法,那個代碼量太大了,似乎不太現(xiàn)實。
不求自己純手工從底層開始打造出自己的 LRU,但是起碼要知道如何利用已有的 JDK 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)一個 Java 版的 LRU。
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int CACHE_SIZE;
/**
* 傳遞進來最多能緩存多少數(shù)據(jù)
*
* @param cacheSize 緩存大小
*/
public LRUCache(int cacheSize) {
// true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// 當(dāng) map中的數(shù)據(jù)量大于指定的緩存?zhèn)€數(shù)的時候,就自動刪除最老的數(shù)據(jù)。
return size() > CACHE_SIZE;
}
}
5.如何保證 redis 的高并發(fā)和高可用?redis 的主從復(fù)制原理能介紹一下么?redis 的哨兵原理能介紹一下么?
考點分析
其實問這個問題,主要是考考你,redis 單機能承載多高并發(fā)?如果單機扛不住如何擴容扛更多的并發(fā)?redis 會不會掛?既然 redis 會掛那怎么保證 redis 是高可用的?
其實針對的都是項目中你肯定要考慮的一些問題,如果你沒考慮過,那確實你對生產(chǎn)系統(tǒng)中的問題思考太少。
面試題剖析
如果你用 redis 緩存技術(shù)的話,肯定要考慮如何用 redis 來加多臺機器,保證 redis 是高并發(fā)的,還有就是如何讓 redis 保證自己不是掛掉以后就直接死掉了,即 redis 高可用。
redis 實現(xiàn)高并發(fā)主要依靠主從架構(gòu),一主多從,一般來說,很多項目其實就足夠了,單主用來寫入數(shù)據(jù),單機幾萬 QPS,多從用來查詢數(shù)據(jù),多個從實例可以提供每秒 10w 的 QPS。
如果想要在實現(xiàn)高并發(fā)的同時,容納大量的數(shù)據(jù),那么就需要 redis 集群,使用 redis 集群之后,可以提供每秒幾十萬的讀寫并發(fā)。
redis 高可用,如果是做主從架構(gòu)部署,那么加上哨兵就可以了,就可以實現(xiàn),任何一個實例宕機,可以進行主備切換。
6.redis 的持久化有哪幾種方式?不同的持久化機制都有什么優(yōu)缺點?持久化機制具體底層是如何實現(xiàn)的?
考點分析
redis 如果僅僅只是將數(shù)據(jù)緩存在內(nèi)存里面,如果 redis 宕機了再重啟,內(nèi)存里的數(shù)據(jù)就全部都弄丟了啊。你必須得用 redis 的持久化機制,將數(shù)據(jù)寫入內(nèi)存的同時,異步的慢慢的將數(shù)據(jù)寫入磁盤文件里,進行持久化。
如果 redis 宕機重啟,自動從磁盤上加載之前持久化的一些數(shù)據(jù)就可以了,也許會丟失少許數(shù)據(jù),但是至少不會將所有數(shù)據(jù)都弄丟。
這個其實一樣,針對的都是 redis 的生產(chǎn)環(huán)境可能遇到的一些問題,就是 redis 要是掛了再重啟,內(nèi)存里的數(shù)據(jù)不就全丟了?能不能重啟的時候把數(shù)據(jù)給恢復(fù)了?
面試題剖析
持久化主要是做災(zāi)難恢復(fù)、數(shù)據(jù)恢復(fù),也可以歸類到高可用的一個環(huán)節(jié)中去,比如你 redis 整個掛了,然后 redis 就不可用了,你要做的事情就是讓 redis 變得可用,盡快變得可用。
重啟 redis,盡快讓它堆外提供服務(wù),如果沒做數(shù)據(jù)備份,這時候 redis 啟動了,也不可用啊,數(shù)據(jù)都沒了。
很可能說,大量的請求過來,緩存全部無法命中,在 redis 里根本找不到數(shù)據(jù),這個時候就死定了,出現(xiàn)緩存雪崩問題。所有請求沒有在 redis 命中,就會去 mysql 數(shù)據(jù)庫這種數(shù)據(jù)源頭中去找,一下子 mysql 承接高并發(fā),然后就掛了...
如果你把 redis 持久化做好,備份和恢復(fù)方案做到企業(yè)級的程度,那么即使你的 redis 故障了,也可以通過備份數(shù)據(jù),快速恢復(fù),一旦恢復(fù)立即對外提供服務(wù)。
redis 持久化的兩種方式
- RDB:RDB 持久化機制,是對 redis 中的數(shù)據(jù)執(zhí)行周期性的持久化。
- AOF:AOF 機制對每條寫入命令作為日志,以
append-only
的模式寫入一個日志文件中,在 redis 重啟的時候,可以通過回放 AOF 日志中的寫入指令來重新構(gòu)建整個數(shù)據(jù)集。
通過 RDB 或 AOF,都可以將 redis 內(nèi)存中的數(shù)據(jù)給持久化到磁盤上面來,然后可以將這些數(shù)據(jù)備份到別的地方去,比如說阿里云等云服務(wù)。
如果 redis 掛了,服務(wù)器上的內(nèi)存和磁盤上的數(shù)據(jù)都丟了,可以從云服務(wù)上拷貝回來之前的數(shù)據(jù),放到指定的目錄中,然后重新啟動 redis,redis 就會自動根據(jù)持久化數(shù)據(jù)文件中的數(shù)據(jù),去恢復(fù)內(nèi)存中的數(shù)據(jù),繼續(xù)對外提供服務(wù)。
如果同時使用 RDB 和 AOF 兩種持久化機制,那么在 redis 重啟的時候,會使用 AOF 來重新構(gòu)建數(shù)據(jù),因為 AOF 中的數(shù)據(jù)更加完整。
RDB 優(yōu)缺點
RDB會生成多個數(shù)據(jù)文件,每個數(shù)據(jù)文件都代表了某一個時刻中 redis 的數(shù)據(jù),這種多個數(shù)據(jù)文件的方式,非常適合做冷備,可以將這種完整的數(shù)據(jù)文件發(fā)送到一些遠程的安全存儲上去,比如說 Amazon 的 S3 云服務(wù)上去,在國內(nèi)可以是阿里云的 ODPS 分布式存儲上,以預(yù)定好的備份策略來定期備份redis中的數(shù)據(jù)。
RDB 對 redis 對外提供的讀寫服務(wù),影響非常小,可以讓 redis 保持高性能,因為 redis 主進程只需要 fork 一個子進程,讓子進程執(zhí)行磁盤 IO 操作來進行 RDB 持久化即可。
相對于 AOF 持久化機制來說,直接基于 RDB 數(shù)據(jù)文件來重啟和恢復(fù) redis 進程,更加快速。
如果想要在 redis 故障時,盡可能少的丟失數(shù)據(jù),那么 RDB 沒有 AOF 好。一般來說,RDB 數(shù)據(jù)快照文件,都是每隔 5 分鐘,或者更長時間生成一次,這個時候就得接受一旦 redis 進程宕機,那么會丟失最近 5 分鐘的數(shù)據(jù)。
RDB 每次在 fork 子進程來執(zhí)行 RDB 快照數(shù)據(jù)文件生成的時候,如果數(shù)據(jù)文件特別大,可能會導(dǎo)致對客戶端提供的服務(wù)暫停數(shù)毫秒,或者甚至數(shù)秒。
AOF 優(yōu)缺點
- AOF 可以更好的保護數(shù)據(jù)不丟失,一般 AOF 會每隔 1 秒,通過一個后臺線程執(zhí)行一次
fsync
操作,最多丟失 1 秒鐘的數(shù)據(jù)。 - AOF 日志文件以
append-only
模式寫入,所以沒有任何磁盤尋址的開銷,寫入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復(fù)。 - AOF 日志文件即使過大的時候,出現(xiàn)后臺重寫操作,也不會影響客戶端的讀寫。因為在
rewrite
log 的時候,會對其中的指導(dǎo)進行壓縮,創(chuàng)建出一份需要恢復(fù)數(shù)據(jù)的最小日志出來。再創(chuàng)建新日志文件的時候,老的日志文件還是照常寫入。當(dāng)新的 merge 后的日志文件 ready 的時候,再交換新老日志文件即可。 - AOF 日志文件的命令通過非常可讀的方式進行記錄,這個特性非常適合做災(zāi)難性的誤刪除的緊急恢復(fù)。比如某人不小心用
flushall
命令清空了所有數(shù)據(jù),只要這個時候后臺rewrite
還沒有發(fā)生,那么就可以立即拷貝 AOF 文件,將最后一條flushall
命令給刪了,然后再將該AOF
文件放回去,就可以通過恢復(fù)機制,自動恢復(fù)所有數(shù)據(jù)。 - 對于同一份數(shù)據(jù)來說,AOF 日志文件通常比 RDB 數(shù)據(jù)快照文件更大。
- AOF 開啟后,支持的寫 QPS 會比 RDB 支持的寫 QPS 低,因為 AOF 一般會配置成每秒
fsync
一次日志文件,當(dāng)然,每秒一次fsync
,性能也還是很高的。(如果實時寫入,那么 QPS 會大降,redis 性能會大大降低) - 以前 AOF 發(fā)生過 bug,就是通過 AOF 記錄的日志,進行數(shù)據(jù)恢復(fù)的時候,沒有恢復(fù)一模一樣的數(shù)據(jù)出來。所以說,類似 AOF 這種較為復(fù)雜的基于命令日志/merge/回放的方式,比基于 RDB 每次持久化一份完整的數(shù)據(jù)快照文件的方式,更加脆弱一些,容易有 bug。不過 AOF 就是為了避免 rewrite 過程導(dǎo)致的 bug,因此每次 rewrite 并不是基于舊的指令日志進行 merge 的,而是基于當(dāng)時內(nèi)存中的數(shù)據(jù)進行指令的重新構(gòu)建,這樣健壯性會好很多。
RDB和AOF到底該如何選擇
- 不要僅僅使用 RDB,因為那樣會導(dǎo)致你丟失很多數(shù)據(jù);
- 也不要僅僅使用 AOF,因為那樣有兩個問題:第一,你通過 AOF 做冷備,沒有 RDB 做冷備來的恢復(fù)速度更快;第二,RDB 每次簡單粗暴生成數(shù)據(jù)快照,更加健壯,可以避免 AOF 這種復(fù)雜的備份和恢復(fù)機制的 bug;
- redis 支持同時開啟開啟兩種持久化方式,我們可以綜合使用 AOF 和 RDB 兩種持久化機制,用 AOF 來保證數(shù)據(jù)不丟失,作為數(shù)據(jù)恢復(fù)的第一選擇; 用 RDB 來做不同程度的冷備,在 AOF 文件都丟失或損壞不可用的時候,還可以使用 RDB 來進行快速的數(shù)據(jù)恢復(fù)。