昨天說的十點裡面,有八條我的文章里都有,至於第二條,面向對象編程,沒有對象編個毛程,開個玩笑哈,我文章裡面也有,我也沒對象,調侃下。

今天來說下分散式緩存:

分散式緩存的定義是什麼?

緩存這種能夠提升指令和數據讀取速度的特性,隨著本地計算機系統向分散式系統的擴展,在分散式計算領域中得到了廣泛的應用,稱為分散式緩存。

分散式緩存能夠處理大量的動態數據,因此比較適合應用在Web 2.0時代中的社交網站等需要由用戶生成內容的場景。

從本地緩存擴展到分散式緩存後,關注重點從CPU、內存、緩存之間的數據傳輸速度差異也擴展到了業務系統、資料庫、分散式緩存之間的數據傳輸速度差異。

它的特點:

分散式緩存由一個服務端實現管理和控制,有多個客戶端節點存儲數據,可以進一步提高數據的讀取速率。那麼我們要讀取某個數據的時候,應該選擇哪個節點呢?

如果挨個節點找,那效率就太低了。

因此需要根據一致性哈希演算法確定數據的存儲和讀取節點。

以數據D,節點總個數N為基礎,通過一致性哈希演算法計算出數據D對應的哈希值(相當於門牌號),根據這個哈希值就可以找到對應的節點了。

一致哈希演算法的好處在於節點個數發生變化(減少或增加)時無需重新計算哈希值,保證數據儲存或讀取時可以正確、快速地找到對應的節點。

分散式緩存能夠高性能地讀取數據、能夠動態地擴展緩存節點、能夠自動發現和切換故障節點、能夠自動均衡數據分區,而且能夠為使用者提供圖形化的管理界面,部署和維護都十分方便。

分散式緩存已經在分散式領域、雲計算領域得到了廣泛的應用。

而之前的說的Redis也是分散式緩存裡面的一員。

那該怎麼去選擇呢。

個人建議是Redis。

常見的分散式緩存:

常用的分散式緩存包括Redis、Memcached和阿里巴巴的Tair,因為Redis提供的數據結構比較豐富且簡單易用,所以Redis的使用廣泛。

1.數據類型

Redis一共支持5種數據類型,每種數據類型對應不同的數據結構,有簡單的String類型、壓縮串、字典、跳躍表等。跳躍表是比較新型的數據結構,常用於高性能的查找,可以達到log2N的查詢速度,而且跳躍表相對於紅黑樹,在更新時變更的節點較少,更易於實現並發操作。

Memcache只支持對鍵值對的存儲,並不支持其它數據結構。

2.線程模型

Redis使用單線程實現,Memcache等使用多線程實現,因此我們不推薦在Redis中存儲太大的內容,否則會阻塞其它請求。

因為緩存操作都是內存操作,只有很少的計算操作,所以在單線程下性能很好。Redis實現的單線程的非阻塞網路I/O模型,適合快速地操作邏輯,有複雜的長邏輯時會影響性能。對於長邏輯應該配置多個實例來提高多核CPU的利用率,也就是說,可以使用單機器多埠來配置多個實例,官方的推薦是一台機器使用8個實例。

它實現的非阻塞I/O模型基於Libevent庫中關於Epoll的兩個文件加上自己簡單實現的事件通知模型,簡單小巧,作者的思想就是保持實現簡單、減少依賴。由於在伺服器中只有一個線程,因此提供了管道來合併請求和批量執行,縮短了通信消耗的時間。

Memcache也使用了非阻塞I/O模型,但是使用了多線程,可以應用於多種場景,請求的邏輯可大可小、可長可短,不會出現一個邏輯複雜的請求阻塞對其它請求的響應的場景。它直接依賴Libevent庫實現,依賴比較複雜,損失了在一些特定環境下的高性能。

3.持久機制

Redis提供了兩種持久機制,包括RDB和AOF,前者是定時的持久機制,但在出現宕機時可能會出現數據丟失,後者是基於操作日誌的持久機制。

Memcahe並不提供持久機制,因為Memache的設計理念就是設計一個單純的緩存,緩存的數據都是臨時的,不應該是持久的,也不應該是一個大數據的資料庫,緩存未命中時回源查詢資料庫是天經地義的,但可以通過第三方庫MemcacheDB來支持它的持久性。

4.客戶端

常見的Redis Java客戶端Jedis使用阻塞I/O,但可以配置連接池,並提供了一致性哈希分片的邏輯,也可以使用開源的客戶端分片框架Redic。

Memecache的客戶端包括Memcache Java Client、Spy Client、XMemcache等,Memcache Java Client使用阻塞I/O,而Spy Client/XMemcache使用非阻塞I/O。

我們知道,阻塞I/O不需要額外的線程,非阻塞I/O會開啟額外的請求線程(在Boss線程池裡)監聽埠,一個請求在處理後就釋放工作者線程(在Worker線程池中),請求線程在監聽到有返回結果時,一旦有I/O返回結果就被喚醒,然後開始處理響應數據並寫回網路Socket連接,所以從理論上來講,非阻塞I/O的吞吐量和響應能力會更高。

5.高可用

Redis支持主從節點複製配置,從節點可使用RDB和緩存的AOF命令進行同步和恢復。Redis還支持Sentinel和Cluster(從3.0版本開始)等高可用集群方案。

Memecache不支持高可用模型,可使用第三方Megagent代理,當一個實例宕機時,可以連接另外一個實例來實現。

6.對隊列的支持

Redis本身支持lpush/brpop、publish/subscribe/psubscribe等隊列和訂閱模式。

Memcache不支持隊列,可通過第三方MemcachQ來實現。

7.事務

Redis提供了一些在一定程度上支持線程安全和事務的命令,例如:multi/exec、watch、inc等。由於Redis伺服器是單線程的,任何單一請求的伺服器操作命令都是原子的,但跨客戶端的操作並不保證原子性,所以對於同一個連接的多個操作序列也不保證事務。

Memcached的單個命令也是線程安全的,單個連接的多個命令序列不是線程安全的,它也提供了inc等線程安全的自加命令,並提供了gets/cas保證線程安全。

8.數據淘汰策略

Redis提供了豐富的淘汰策略,包括maxmemory、maxmemory-policy、volatile-lru、allkeys-lru、volatile-random、allkeys-random、volatile-ttl、noeviction(return error)等。

Memecache在容量達到指定值後,就基於LRU(Least Recently Used)演算法自動刪除不使用的緩存。在某些情況下LRU機制反倒會帶來麻煩,會將不期待的數據從內存中清除,在這種情況下啟動Memcache時,可以通過「M」參數禁止LRU演算法。

9.內存分配

Redis為了屏蔽不同平台之間的差異及統計內存佔用量等,對內存分配函數進行了一層封裝,在程序中統一使用zmalloc、zfree系列函數,這些函數位於zmalloc.h/zmalloc.c文件中。封裝就是為了屏蔽底層平台的差異,同時方便自己實現相關的統計函數。具體的實現方式如下:

  • 若系統中存在Google的TC_MALLOC庫,則使用tc_malloc一族的函數代替原本的malloc一族的函數。
  • 若當前系統是Mac系統,則使用系統的內存分配函數。
  • 對於其它情況,在每一段分配好的空間前面同時多分配一個定長的欄位,用來記錄分配的空間大小,通過這種方式來實現簡單有效的內存分配。

Memcache採用slab table的方式分配內存,首先把可得的內存按照不同的大小來分類,在使用時根據需求找到最接近於需求大小的塊分配,來減少內存碎片,但是這需要進行合理配置才能達到效果。

從上面的對比可以看到,Redis在實現和使用上更簡單,但是功能更強大,效率更高,應用也更廣泛。下面將對Redis進行初步介紹,給初學者一個初體驗式的學習引導。


推薦閱讀:
相关文章