面試必問(wèn)的 Redis:Memcached VS Redis
前言
老態(tài)龍鐘的 Memcached 似乎已經(jīng)無(wú)力阻擋 Redis 一統(tǒng)江湖了,但是在面試中,關(guān)于兩者的比較還是頻頻出現(xiàn),因此有必要了解下兩者的區(qū)別。
正文
數(shù)據(jù)結(jié)構(gòu)
Memcached:主要支持簡(jiǎn)單的 key-value 數(shù)據(jù)結(jié)構(gòu),類似于 Redis 里的 String。
Redis:總共有9種,常見(jiàn)的5種,高級(jí)的4種:
String:字符串,最基礎(chǔ)的數(shù)據(jù)類型。
List:列表。
Hash:哈希對(duì)象。
Set:集合。
Sorted Set:有序集合,Set 的基礎(chǔ)上加了個(gè)分值。
HyperLogLog:通常用于基數(shù)統(tǒng)計(jì)。使用少量固定大小的內(nèi)存,來(lái)統(tǒng)計(jì)集合中唯一元素的數(shù)量。統(tǒng)計(jì)結(jié)果不是精確值,而是一個(gè)帶有0.81%標(biāo)準(zhǔn)差(standard error)的近似值。所以,HyperLogLog適用于一些對(duì)于統(tǒng)計(jì)結(jié)果精確度要求不是特別高的場(chǎng)景,例如網(wǎng)站的UV統(tǒng)計(jì)。
Geo:redis 3.2 版本的新特性。可以將用戶給定的地理位置信息儲(chǔ)存起來(lái), 并對(duì)這些信息進(jìn)行操作:獲取2個(gè)位置的距離、根據(jù)給定地理位置坐標(biāo)獲取指定范圍內(nèi)的地理位置集合。
Bitmap:位圖。
Stream:主要用于消息隊(duì)列,類似于 kafka,可以認(rèn)為是 pub/sub 的改進(jìn)版。提供了消息的持久化和主備復(fù)制功能,可以讓任何客戶端訪問(wèn)任何時(shí)刻的數(shù)據(jù),并且能記住每一個(gè)客戶端的訪問(wèn)位置,還能保證消息不丟失。
數(shù)據(jù)存儲(chǔ)
Memcached:數(shù)據(jù)全部存在內(nèi)存中,重啟實(shí)例會(huì)導(dǎo)致數(shù)據(jù)全部丟失
Redis:通常全部存在內(nèi)存中,同時(shí)支持持久化到磁盤上
關(guān)于 Redis 的數(shù)據(jù)存儲(chǔ)(內(nèi)存管理),網(wǎng)上經(jīng)常見(jiàn)到一種說(shuō)法:當(dāng)物理內(nèi)存用完時(shí),Redis可以將一些很久沒(méi)用到的 value 交換到磁盤,同時(shí)在內(nèi)存中清除。這種特性使得Redis 可以保持超過(guò)其機(jī)器本身內(nèi)存大小的數(shù)據(jù)。
這個(gè)說(shuō)法用在現(xiàn)在,其實(shí)已經(jīng)不準(zhǔn)確了。上述的這個(gè)說(shuō)法是 Redis 里的虛擬內(nèi)存(Virtual Memory)功能,該功能在 Redis 2.0 被引入,但是在 Redis 2.4 中被默認(rèn)關(guān)閉,并標(biāo)記為廢棄,而在后續(xù)版中被完全移除。也就是說(shuō),大部分人用的版本根本就沒(méi)有這個(gè)功能了。
所以在面試中最好不要提到這個(gè)說(shuō)法,或者需要自行補(bǔ)充說(shuō)明該功能現(xiàn)在已經(jīng)不存在了。
持久化
Memcached:不支持
Redis:AOF、RDB、混合持久化
災(zāi)難恢復(fù)
Memcached:實(shí)例掛掉后,數(shù)據(jù)不可恢復(fù)
Redis:實(shí)例掛掉后可以通過(guò)RDB、AOF恢復(fù)?,但是還是會(huì)有數(shù)據(jù)丟失問(wèn)題
事件處理(事件庫(kù))
Memcached:使用 Libevent 庫(kù)
Redis:自己封裝了簡(jiǎn)易事件庫(kù) AeEvent
過(guò)期鍵刪除策略
常見(jiàn)的有以下三種:
定時(shí)刪除:在設(shè)置鍵的過(guò)期時(shí)間的同時(shí),創(chuàng)建一個(gè)定時(shí)器,讓定時(shí)器在鍵的過(guò)期時(shí)間來(lái)臨時(shí),立即執(zhí)行對(duì)鍵的刪除操作。對(duì)內(nèi)存最友好,對(duì) CPU 時(shí)間最不友好。
惰性刪除:放任鍵過(guò)期不管,但是每次獲取鍵時(shí),都檢査鍵是否過(guò)期,如果過(guò)期的話,就刪除該鍵;如果沒(méi)有過(guò)期,就返回該鍵。對(duì) CPU 時(shí)間最優(yōu)化,對(duì)內(nèi)存最不友好。
定期刪除:每隔一段時(shí)間,默認(rèn)100ms,程序就對(duì)數(shù)據(jù)庫(kù)進(jìn)行一次檢査,刪除里面的過(guò)期鍵。至 于要?jiǎng)h除多少過(guò)期鍵,以及要檢査多少個(gè)數(shù)據(jù)庫(kù),則由算法決定。前兩種策略的折中,對(duì) CPU 時(shí)間和內(nèi)存的友好程度較平衡。
Memcached:惰性刪除
Redis:惰性刪除+定期刪除
內(nèi)存驅(qū)逐(淘汰)策略
當(dāng)內(nèi)存空間已經(jīng)用滿時(shí),服務(wù)實(shí)例將將根據(jù)配置的驅(qū)逐策略,進(jìn)行相應(yīng)的動(dòng)作。
memcached:主要為 LRU 算法
redis:當(dāng)前總共有以下8種:
noeviction:默認(rèn)策略,不淘汰任何 key,直接返回錯(cuò)誤
allkeys-lru:在所有的 key 中,使用?LRU?算法淘汰部分 key
allkeys-lfu:在所有的 key 中,使用 LFU 算法淘汰部分 key
allkeys-random:在所有的 key 中,隨機(jī)淘汰部分 key
volatile-lru:在設(shè)置了過(guò)期時(shí)間的?key?中,使用?LRU?算法淘汰部分 key
volatile-lfu:在設(shè)置了過(guò)期時(shí)間的 key 中,使用 LFU 算法淘汰部分 key
volatile-random:在設(shè)置了過(guò)期時(shí)間的 key 中,隨機(jī)淘汰部分 key
volatile-ttl:在設(shè)置了過(guò)期時(shí)間的 key 中,挑選 TTL(time to live,剩余時(shí)間)短的 key 淘汰
性能
我自己對(duì)“高性能”這個(gè)話題有很強(qiáng)的興趣,我相信也有不少同學(xué)跟我一樣,對(duì)高并發(fā)、高性能有特殊的向往,所以這個(gè)話題會(huì)多講兩句。
首先,影響性能比較的因素有很多,網(wǎng)絡(luò)帶寬、CPU、內(nèi)存等等,所以其實(shí)很多測(cè)試并不能完全說(shuō)明問(wèn)題,可能在這個(gè)條件下 Redis 快,而在另一個(gè)條件下是 Memcached 快。
所以兩者的性能比較其實(shí)可以算一個(gè)比較開(kāi)放的話題,在面試中,你只要能夠自圓其說(shuō),說(shuō)服面試官,那就是OK的。
Redis 作者 antirez 在 12 年左右在 Stack Overflow 上談過(guò)兩者的性能問(wèn)題,他是這么說(shuō)的:由于 Redis 只使用單核,而 Memcached 可以使用多核,所以在比較上:在處理小數(shù)據(jù)時(shí),平均每一個(gè)核上 Redis 比 Memcached 性能更高,而在 100k 左右的大數(shù)據(jù)時(shí), Memcached 性能要高于 Redis。
antirez?畢竟是大牛,所以他的這個(gè)說(shuō)法,大部分人都是認(rèn)同的,所以在面試中這么回答是可以的。
antirez?的這個(gè)說(shuō)法是按“CPU 單核”維度來(lái)比較,但是我們?cè)趯?shí)際的使用中,肯定是按“實(shí)例”維度來(lái)使用,所以接下來(lái)我們探討下對(duì)于兩者在“實(shí)例”維度的比較。
按“實(shí)例”維度進(jìn)行比較時(shí),個(gè)人認(rèn)為由于 Memcached 多線程的特性,在 Redis 6.0 之前,通常情況下 Memcached 性能是要高于 Redis 的,同時(shí)實(shí)例的 CPU 核數(shù)越多,Memcached 的性能優(yōu)勢(shì)越大。
而在 Redis 6.0 支持?I/O 多線程后,當(dāng) Redis 關(guān)閉持久化后,兩者在性能上可能會(huì)比較接近。
技術(shù)選型、如何選擇
看完上面的比較,其實(shí)不難做出選擇,99%的人、場(chǎng)景,或者說(shuō) Redis 能支持的場(chǎng)景,使用 Redis 基本不會(huì)有問(wèn)題。
而且就最近幾年的發(fā)展來(lái)看,Redis 可謂風(fēng)光無(wú)限,而?Memcached 則是已經(jīng)逐漸跟不上 Redis 腳步了,這也側(cè)面反映了當(dāng)前大家的選擇都是趨向于使用 Redis。
而關(guān)于使用 Memcached 的場(chǎng)景,我自己了解到的一些線上真實(shí)使用場(chǎng)景都是對(duì)于性能有非常高的要求。
Redis 6.0 支持的 I/O 階段多線程目前根據(jù)官方說(shuō)法至少能提升性能1倍,隨著 Redis 在性能上的不斷優(yōu)化,可能后續(xù) Memcached 的使用場(chǎng)景會(huì)越來(lái)越少了。
最后
當(dāng)你的才華還撐不起你的野心的時(shí)候,你就應(yīng)該靜下心來(lái)學(xué)習(xí),愿你在我這里能有所收獲。
原創(chuàng)不易,如果你覺(jué)得本文寫的還不錯(cuò),對(duì)你有幫助,請(qǐng)通過(guò)【點(diǎn)贊】讓我知道,支持我寫出更好的文章。
推薦閱讀
面試必問(wèn)的 Redis:RDB、AOF、混合持久化
面試必問(wèn)的 Redis:數(shù)據(jù)結(jié)構(gòu)和基礎(chǔ)概念
兩年Java開(kāi)發(fā)工作經(jīng)驗(yàn)面試總結(jié)
4 年 Java 經(jīng)驗(yàn)面試總結(jié)、心得體會(huì)
字節(jié)、美團(tuán)、快手核心部門面試總結(jié)(真題解析)
