前言: 目前比較流行的緩存技術無疑是Memcached和Redis,兩套緩存技術有著諸多的相似之處,但又具備大量的顯著差異,作為新生的方案,Redis被視為首選,但是有些場景Memcached發揮的作用是不容忽視的。 相似點: 1. Memcached和Redis都屬於In-Memory、Key-V ...
前言:
目前比較流行的緩存技術無疑是Memcached和Redis,兩套緩存技術有著諸多的相似之處,但又具備大量的顯著差異,作為新生的方案,Redis被視為首選,但是有些場景Memcached發揮的作用是不容忽視的。
相似點:
1. Memcached和Redis都屬於In-Memory、Key-Value數據存儲方案,同屬於NoSQL家族,都選擇將全部數據存儲在記憶體中。
2. 都是成熟的開源項目,Memcached由Brad Fitzpatrick 2003年開發而成,Redis則由Salvatore Sanfilippo於2009創建。
3. 簡單易用,只需幾分鐘就可以完成安裝工作。
不同之處:
1. Redis支持伺服器端的數據操作: Redis相對Memcached擁有更多的數據結構,支持豐富的數據操作。
2. 記憶體使用率:Memcached簡單的key-value存儲,記憶體利用率更高,而如果Redis採用hash結構來做Key-value存儲,由於組合式的壓縮,記憶體利用率更高。
3.性能對比:Redis單核,Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還有些差距。
結合以上特性下麵從兩者的事件模型,記憶體管理,數據類型、集群管理、持久化詳細講解一下
一、事件模型
相同之處:都是用epol來做事件迴圈
不同之處:redis是單線程伺服器(這裡的單線程是指除了主線程以外其他線程沒有event loop),redis事件模型只有一個event loop,是最簡單的reactor的實現。redis事件模型中有一個亮點,redis裡面的fd(詳細請百度)就是伺服器與客戶端連接socket的fd,通常根據fd找到具體的客戶端信息,通常的處理方式就是用紅黑樹將fd與客戶端信息保存起來,通過fd查找,效率是lgn,不過redis比較特殊,redis客戶端的數量上限可以設置,即同一時刻知道redis打開的fd的上限,且進程的fd在同一時刻是不會重覆的,所以redis使用一個數據,將fd作為數組的下標,數組的元素就是客戶端的信息,這樣通過fd就能訂位客戶端信息,查找效率是O(1),省去了紅黑樹的實現。
Memcached是多線程的,使用Master-Worker的方式,其中主線程負責接收連接,然後將連接分給各個worker線程,在各個worker線程中完成命令的接收,處理和返回結果。
二、記憶體管理
1. Memcached使用預先分配,預先分配一大塊記憶體,然後接下來就從記憶體池中分配,這樣可以減少記憶體的分配次數,提高效率。Memcached的採用Slab Allocation,記憶體的結構決定了Value值的大小最大隻能為1MB。
Slab Allocation的原理:將分配的記憶體分割成各種尺寸的塊(chunk),並把尺寸相同的塊分成組,每一組被稱為slab。Memcached的記憶體分配以Page為單位,Page預設值為1M,可以在啟動時通過-I參數來指定。Slab是由多個Page組成的,Page按照指定大小切割成多個chunk。memcached在啟動時通過-f選項可以指定 Growth Factor因數。該值控制slab之間的差異,chunk大小的差異。預設值為1.25。其結構圖如下:
優缺點:Slab Allocation可以有效的解決記憶體碎片的問題,但是也會造成記憶體的浪費
1.每個slab的chunk大小是固定的,當item的占用空間實際小於chunk大小時,會出現記憶體浪費
2.每個slab的大小是固定的(因為page是固定的),當slab不能被他所擁有的chunk整除時,會出現記憶體浪費
3.按照Growth Factor因數生成指定大小的slab,而某slab id根本未被使用時,會出現記憶體浪費
2. Redis使用動態分配,由於C語言沒有自帶的GC,所以Redis的實現中封裝了C的malloc,calloc,realloc和free函數來對自己的記憶體進行管理,這些實現都在zmalloc.h和zmalloc.c中。在Redis中,並不是所有的數據一直存儲在記憶體中。當物理記憶體用完時,Redis可以將一些很久沒用的Value交換到磁碟。Redis只會緩存所有的key,當Redis發現記憶體的使用量超過了一個閥值,將觸發Swap操作,Redis根據“swappability = age*log(size_in_memory)”計算出哪些key對應的value需要swap到磁碟。然後再將這些key對應的value持久化到磁碟中,同時在記憶體中清除。這種特性使得Redis可以保持超過其機器本身記憶體大小的數據。當然,機器本身的記憶體必須要能夠保持所有的key,畢竟這些數據是不會進行swap操作的。同時由於Redis將記憶體中的數據swap到磁碟中的時候,提供服務的主線程和進行swap操作的子線程會共用這部分記憶體,所以如果更新需要swap的數據,Redis將阻塞這個操作,直到子線程完成swap操作後才可以進行修改。當從Redis中讀取數據的時候,如果讀取的key對應的value不在記憶體中,那麼Redis就需要從swap文件中載入相應數據,然後再返回給請求方。 這裡就存在一個I/O線程池的問題。在預設的情況下,Redis會出現阻塞,即完成所有的swap文件載入後才會相應。這種策略在客戶端的數量較小,進行批量操作的時候比較合適。但是如果將Redis應用在一個大型的網站應用程式中,這顯然是無法滿足大併發的情況的。所以Redis運行我們設置I/O線程池的大小,對需要從swap文件中載入相應數據的讀取請求進行併發操作,減少阻塞的時間。
三、數據類型
Memcached僅支持簡單的key-value結構的數據,Redis支持的數據類型要豐富得多。常用的由五種:String、Hash、List、Set和Sorted Set。Redis內部使用一個redisObject對象來表示所有的key和value。
四:集群管理
Memcached本身並不支持分散式,只能在客戶端通過一致性hash這樣的分散式演算法來實現Memcached的分散式存儲。 Redis更偏向服務端構建分散式存儲,Redis Cluster是一個實現了分散式且允許單點故障的Redis高級版本,去中心化,具有線性可伸縮的功能。節點與節點之間通過二進位協議進行通信,節點與客戶端之間通過ascii協議進行通信。在數據的放置策略上,Redis Cluster將整個key的數值域分成4096個哈希槽,每個節點上可以存儲一個或多個哈希槽,也就是說當前Redis Cluster支持的最大節點數就是4096。Redis Cluster使用的分散式演算法也很簡單:crc16( key ) % HASH_SLOTS_NUMBER。
五:數據持久化
Memcached不支持數據持久化。Redis支持兩種數據持久化RDB快照和AOF日誌。
Redis Cluster引入了master-slave模式,每一個master都對應兩個slave節點。
整體上說,兩者的性能都很好,不必為哪個性能更高而糾結。不過,redis提供的持久化和數據同步機制,這些都是memcached沒有的,所以如果你想要持久化,就只能用redis了。另外,memcached足以應付簡單的鍵值存儲,不過你要是想用更高級的數據結構,比如hash,list,set,zset之類的,redis提供了這些類型,用著更方便。