天天看點

為什麼 Redis 要比 Memcached 更火?

為什麼現在看Redis要比Memcached更火一些?

這篇文章,我們就從各個方面來對比這兩個記憶體資料庫的差異,友善你在使用時,做出最符合業務需要的選擇。

要分析它們的差別,主要從以下幾個方面對比:

線程模型

資料結構

淘汰政策

管道與事務

持久化

高可用

叢集化

要說性能,必須要分析它們的服務模型。

Memcached處理請求采用多線程模型,并且基于IO多路複用技術,主線程接收到請求後,分發給子線程處理。

這樣做好的好處是,當某個請求處理比較耗時,不會影響到其他請求的處理。

當然,缺點是CPU的多線程切換必然存在性能損耗,同時,多線程在通路共享資源時必然要加鎖,也會在一定程度上降低性能。

Redis同樣采用IO多路複用技術,但它處理請求采用是單線程模型,從接收請求到處理資料都在一個線程中完成。推薦看一下這篇《Redis 到底是單線程還是多線程?》。

這意味着使用Redis,一旦某個請求處理耗時比較長,那麼整個Redis就會阻塞住,直到這個請求處理完成後傳回,才能處理下一個請求,使用Redis時一定要避免複雜的耗時操作。

單線程的好處是,少了CPU的上下文切換損耗,沒有了多線程通路資源的鎖競争,但缺點是無法利用CPU多核的性能。

由于Redis是記憶體資料庫,它的通路速度非常地快,是以它的性能瓶頸不在于CPU,而在于記憶體和網絡帶寬,這也是作者采用單線程模型的主要原因。同時,單線程對于程式開發非常友好,調試起來也很友善。開發多線程程式必然會增加一定的調試難度。

是以,當我們的業務使用key的資料比較大時,Memcached的通路性能要比Redis好一些。如果key的資料比較小,兩者差别并不大。

嚴格來說,Redis的單線程指的是處理請求的線程,它本身還有其他線程在工作,例如有其他線程用來異步處理耗時的任務。

Redis6.0又進一步完善了多線程,在接收請求和發送請求時使用多線,進一步提高了處理性能。

Memcached支援的資料結構很單一,僅支援string類型的操作。并且對于value的大小限制必須在1MB以下,過期時間不能超過30天。

而Redis支援的資料結構非常豐富,除了常用的資料類型string、list、hash、set、zset之外,還可以使用geo、hyperLogLog資料類型。

使用Memcached時,我們隻能把資料序列化後寫入到Memcached中。然後再從Memcached中讀取資料,再反序列化為我們需要的格式,隻能“整存整取”。

而Redis對于不同的資料結構可以采用不同的操作方法,非常靈活。

list:可以友善的建構一個連結清單,或者當作隊列使用

hash:靈活地操作我們需要的字段,進行“整存零取”、“零存整取”以及“零存零取”

set:建構一個不重複的集合,并友善地進行差集、并集運算

zset:建構一個排行榜,或帶有權重的清單

geo:用于地圖相關的業務,辨別兩個地點的坐标,以及計算它們的距離

hyperLogLog:使用非常少的記憶體計算UV

總之,Redis正是因為提供了這麼豐富的資料結構,近幾年在記憶體資料庫領域大放異彩,為我們的業務開發提供了極大的便利。關注公衆号Java技術棧擷取更多資料類型的詳細使用教程。

Memcached必須設定整個執行個體的記憶體上限,資料達到上限後觸發LRU淘汰機制,優先淘汰不常用使用的資料。

但它的資料淘汰機制存在一些問題:剛寫入的資料可能會被優先淘汰掉,這個問題主要是它本身記憶體管理設計機制導緻的。

Redis沒有限制必須設定記憶體上限,如果記憶體足夠使用,Redis可以使用足夠大的記憶體。推薦看下《Redis 記憶體滿了怎麼辦》

同時Redis提供了多種淘汰政策:

volatile-lru:從過期key中按LRU機制淘汰

allkeys-lru:在所有key中按LRU機制淘汰

volatile-random:在過期key中随機淘汰key

allkeys-random:在所有key中随機淘汰key

volatile-ttl:優先淘汰最近要過期的key

volatile-lfu:在所有key中按LFU機制淘汰

allkeys-lfu:在過期key中按LFU機制淘汰

我們可以針對業務場景,使用不同的資料淘汰政策。

Redis還支援管道功能,用戶端一次性打包發送多條指令到服務端,服務端依次處理用戶端發來的指令。這樣可以減少來回往來的網絡IO次數,提供高通路性能。

另外它還支援事務,這裡所說的事務并不是MySQL那樣嚴格的事務模型,這種事務模型是Redis特有的。

一般事務會配合管道一塊使用,用戶端一次性打包發送多條指令到服務端,并且辨別這些指令必須嚴格按順序執行,不能被其他用戶端打斷。同時執行事務之前,用戶端可以告訴服務端某個key稍後會進行相關操作,如果這個用戶端在操作這個key之前,有其他用戶端對這個key進行更改,那麼目前用戶端在執行這些指令時會放棄整個事務操作,保證一緻性。

Memcached不支援資料的持久化,如果Memcached服務當機,那麼這個節點的資料将全部丢失。

Redis支援将資料持久化磁盤上,提供RDB和AOF兩種方式:

RDB:将整個執行個體中的資料快照到磁盤上,全量持久化

AOF:把每一個寫指令持久到磁盤,增量持久化

Redis使用這兩種方式互相配合,完成資料完整性保障,最大程度降低服務當機導緻的資料丢失問題。

Memcached沒有主從複制架構,隻能單節點部署,如果節點當機,那麼該節點資料全部丢失。業務需要對這種情況做相容處理,當某個節點不可用時,把資料寫入到其他節點以降低對業務的影響。

Redis擁有主從複制架構,兩個節點組成主從架構,從可以實時同步主的資料,提高整個Redis服務的可用性。

同時Redis還提供了哨兵節點,在主節點當機時,主動把從節點提升為主節點,繼續提供服務。Redis哨兵如何與Spring Boot內建等系列教程可以關注公衆号Java技術棧搜尋閱讀。

主從兩個節點還可以提供讀寫分離功能,進一步提高程式通路的性能。

Memcached和Redis都是由多個節點組成叢集對外提供服務,但他們的機制也有所不同。

Memcached的叢集化是在用戶端采用一緻性雜湊演算法向指定節點發送資料,當一個節點當機時,其他節點會分擔這個節點的請求。

而Redis叢集化采用的是每個節點維護一部分虛拟槽位,通過key的哈希計算,将key映射到具體的虛拟槽位上,這個槽位再映射到具體的Redis節點。

同時每個Redis節點都包含至少一個從節點,組成主從架構,進一步提高每個節點的高可用能力。

當增加或下線節點時,需要手動觸發資料遷移,重新進行哈希槽位映射。

Redis官方的叢集化解決方案為Redis cluster,它采用無中心化的設計。另外也有第三方的采用中心化設計proxy方式的叢集化解決方案,例如Codis、Twemproxy。

總結

從以上幾個方面進行對比分析,總結如下表。

整體來說,Redis提供了非常豐富的功能,而且性能基本上與Memcached相差無幾,這也是它最近這幾年占領記憶體資料庫鳌頭的原因。

如果你的業務需要各種資料結構給予支撐,同時要求資料的高可用保障,那麼選擇Redis是比較合适的。

如果你的業務非常簡單,隻是簡單的set/get,并且對于記憶體使用并不高,那麼使用簡單的Memcached足夠。

如果此文章能給您帶來小小的工作效率提升,不妨在看、轉發一下,以鼓勵我寫出更好的文章!

————————————————

版權聲明:本文為CSDN部落客「Java技術棧」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:

https://blog.csdn.net/youanyyou/article/details/108526701