引言
緩存是分布式系統中的重要組件,主要解決高并發,大數據場景下,熱點數據訪問的性能問題。提供高性能的數據快速訪問。
本文是緩存在分布式應用第一篇文章,介紹緩存的原理,緩存的分類,緩存的設計,CDN緩存(原理,架構參考和技術實踐),反向代理緩存(原理,Squid架構實踐和常用代理緩存之間的比較)等。
1. 緩存系統概述
緩存是分布式系統中的重要組件,主要解決高并發,大數據場景下,熱點數據訪問的性能問題。提供高性能的數據快速訪問。
1.1 什么是緩存
緩存是一種用于存儲數據臨時副本的技術或設備,其目的是在后續對相同數據的訪問中,能夠更快地獲取數據,從而加速數據訪問過程。例如,在瀏覽器中,當用戶瀏覽網頁后,瀏覽器會將一些網頁內容(如圖片、樣式表等)存儲在本地緩存中。當用戶再次訪問相同網頁時,瀏覽器可以直接從緩存中讀取這些內容,而不用每次都從網絡上下載,大大提高了網頁的加載速度。
1.1 緩存原理
- 數據存儲位置 : 緩存通常位于數據源(如磁盤、數據庫等)和數據消費者(如應用程序、用戶等)之間。它比數據源訪問速度更快,因為它是存儲在內存(如計算機的內存)中的臨時存儲區域,內存的讀寫速度遠遠快于磁盤等存儲設備。
- 數據存儲策略 : 緩存會根據一定的策略來存儲數據。例如,采用最近最少使用(LRU)策略,當緩存空間已滿且需要添加新數據時,會將最近一段時間內最少被訪問的數據從緩存中移除,以騰出空間存儲新數據。
- 數據訪問流程 : 當應用程序請求數據時,首先會在緩存中查找。如果數據在緩存中存在(稱為緩存命中),就直接從緩存中讀取數據并返回給應用程序,這個過程比從原始數據源讀取數據要快得多。如果數據不在緩存中(稱為緩存未命中),則會從數據源讀取數據,在返回給應用程序的同時,還會將數據存儲到緩存中,以便下次訪問時可以快速獲取。
1.2 緩存分類
緩存的分類方式有很多種,以下是一些常見的分類:
(1). 按存儲層次分類
- 前端緩存(Browser Cache)
- 原理:瀏覽器緩存是存儲在用戶本地瀏覽器中的緩存機制。當用戶訪問一個網頁時,瀏覽器會將該網頁的資源(如 HTML 文件、圖片、CSS 文件、JavaScript 文件等)存儲在本地緩存中。下次用戶訪問相同網頁時,瀏覽器會先檢查緩存中的資源是否有效,如果有效則直接從緩存中讀取,避免再次從網絡上下載,從而提高網頁加載速度。
- 應用場景:用于加速網頁的訪問,減少網絡請求,提升用戶體驗。例如,用戶在短時間內多次訪問同一個新聞網站,瀏覽器緩存可以快速加載該網站的公共資源,如網站的 logo 圖片、樣式文件等。
- 后端緩存(Backend Cache)
- 原理:后端緩存通常位于服務器端,用于緩存應用程序的數據。它可以減輕數據庫的負擔,提高應用程序的性能。例如,使用 Redis 或 Memcached 作為后端緩存系統,將頻繁訪問的數據庫查詢結果緩存起來。當應用程序再次請求相同的數據時,可以直接從緩存中獲取,而不是重新查詢數據庫。
- 應用場景:適用于需要頻繁讀取數據但數據更新不頻繁的場景。比如電商網站中商品的詳細信息查詢,這些信息在短時間內不會頻繁更改,通過后端緩存可以快速響應用戶的請求。
- 分布式緩存(Distributed Cache)
- 原理:分布式緩存是一種跨多個服務器節點的緩存系統。它允許多個應用程序實例或服務器共享同一個緩存數據集。分布式緩存系統(如 Redis 集群、Memcached 集群)通過網絡將緩存數據分布在多個服務器上,每個節點負責存儲一部分數據。數據的訪問通過特定的路由算法(如一致性哈希算法)來確定數據所在的節點。
- 應用場景:在大型分布式系統和高并發應用場景中非常有用。例如,大型電商平臺在促銷活動期間,需要處理海量的用戶請求,分布式緩存可以提供快速的數據訪問能力,避免數據庫因高并發訪問而崩潰。
(2). 按數據存儲方式分類
- 內存緩存(In - Memory Cache)
- 原理:內存緩存將數據存儲在計算機的內存中。由于內存的讀寫速度非常快,內存緩存能夠提供極低延遲的數據訪問。常見的內存緩存系統有 Redis 和 Memcached。這些系統將數據以鍵值對的形式存儲在內存中,支持多種數據結構(如 Redis 支持字符串、哈希、列表、集合等)。
- 應用場景:適用于對數據訪問速度要求極高的場景。例如,緩存熱點數據(如熱門視頻網站的視頻推薦列表)、會話信息(如用戶登錄狀態)等。
- 磁盤緩存(Disk Cache)
- 原理:磁盤緩存是利用磁盤存儲空間來緩存數據。它通常作為內存緩存的補充,用于存儲那些不經常訪問或者對訪問速度要求不是極高的數據。磁盤緩存的讀寫速度比內存緩存慢,但存儲容量更大。操作系統通常會利用磁盤緩存來提高文件讀寫效率。
- 應用場景:用于存儲一些不經常訪問但又不想頻繁從原始數據源加載的數據。例如,緩存一些歷史數據(如氣象數據的歷史記錄)、備份數據等。
(3). 按緩存數據的結構分類
- 鍵值緩存(Key - Value Cache)
- 原理:鍵值緩存是最簡單的緩存形式,它以鍵值對的形式存儲數據。每個數據項都有一個唯一的鍵,通過鍵可以快速檢索對應的值。Memcached 和 Redis 都支持鍵值緩存,且 Redis 還支持對鍵值設置過期時間、持久化等高級功能。
- 應用場景:適用于存儲簡單的數據結構,如用戶的個人信息(鍵為用戶 ID,值為用戶的基本信息對象)、配置項(鍵為配置名稱,值為配置值)等。
- 文檔緩存(Document Cache)
- 原理:文檔緩存將數據存儲為文檔的形式,通常用于存儲半結構化數據(如 JSON 或 XML 格式的數據)。文檔緩存系統(如 Couchbase)允許對文檔中的字段進行索引和查詢,提供更靈活的數據訪問方式。
- 應用場景:適用于存儲復雜的數據對象,如內容管理系統中的文章(包含標題、內容、作者、發布時間等字段)、用戶生成的內容(如評論、帖子等)。
- 對象緩存(Object Cache)
- 原理:對象緩存是將應用程序中的對象進行序列化后存儲在緩存系統中。當需要使用該對象時,再從緩存中讀取并進行反序列化。這種方式可以減少對象的創建和銷毀開銷,提高應用程序的性能。
- 應用場景:在面向對象的編程語言開發的應用程序中比較常用。例如,緩存復雜的業務對象(如訂單對象,包含訂單詳情、用戶信息、商品信息等)。
(4). 按緩存的使用場景分類
- 內容緩存(Content Cache)
- 原理:內容緩存主要用于緩存靜態內容,如網頁、圖片、視頻等。內容分發網絡(CDN)是一種典型的內容緩存系統,它通過在全球范圍內部署多個緩存節點,將內容緩存到離用戶最近的節點上,以提高內容的訪問速度。
- 應用場景:廣泛應用于網站加速、流媒體內容分發等場景。例如,大型視頻網站(如 Netflix)通過 CDN 緩存視頻內容,使用戶可以快速訪問視頻資源。
- 數據緩存(Data Cache)
- 原理:數據緩存用于緩存應用程序中經常訪問的數據,這些數據通常來自數據庫。數據緩存系統會定期或根據一定的策略從數據庫中加載數據,應用程序可以直接從緩存中讀取數據,減少數據庫的訪問次數。
- 應用場景:適用于數據密集型的應用程序,如電商網站的商品庫存信息、社交網絡中的用戶關系數據等。
- 計算結果緩存(Computation Cache)
- 原理:計算結果緩存用于存儲計算密集型操作的結果。當相同的計算請求再次發生時,可以直接從緩存中獲取結果,而不需要重新進行計算。例如,在一些科學計算或數據分析的應用程序中,緩存復雜的數學模型計算結果。
- 應用場景:適用于需要頻繁進行復雜計算的場景,如金融風險模型計算、天氣預測模型計算等。
1.3 緩存與數據庫的區別
緩存和數據庫主要有以下區別:
特性 | 緩存 | 數據庫 |
---|---|---|
數據存儲位置和介質 | 通常存儲在內存中 | 一般存儲在硬盤或磁帶等非易失性存儲介質中 |
數據持久性 | 大多不是持久化存儲,數據可能因緩存滿、過期或系統重啟而丟失 | 持久化存儲,即使系統重啟或故障,數據仍可保存 |
數據訪問速度 | 訪問速度極快,通常在微秒級別 | 訪問速度相對較慢,通常在毫秒級別 |
數據容量 | 受內存容量限制,容量相對較小 | 可存儲海量數據,通常配備大容量磁盤陣列 |
數據一致性要求 | 一般不要求強一致性,允許一定時間內與數據庫數據存在差異 | 必須保證數據的一致性和準確性 |
數據結構和復雜操作性 | 數據結構相對簡單,以鍵值對形式存儲,操作較簡單 | 數據結構復雜多樣,支持復雜查詢、事務操作等 |
應用場景 | 用于快速獲取頻繁訪問的數據,如網頁緩存、熱點數據緩存等 | 用于長期穩定存儲數據,如企業業務數據、財務數據等 |
1.4 常見緩存中間件
以下是一些常見的緩存中間件:
(1). 本地緩存中間件
- Ehcache:純Java的進程內緩存框架,易于集成到Java環境中,可作為Hibernate等ORM框架的二級緩存,提供數據持久化功能。
- Guava Cache:基于Java的本地緩存庫,使用簡單,通過
CacheBuilder
可方便地設置緩存的容量、過期時間等策略。 - Caffeine:高性能的本地緩存庫,是Guava Cache的升級版,具有更好的性能和更低的內存占用。
(2). 分布式緩存中間件
- Redis:開源的高性能鍵值對緩存和存儲系統,支持多種數據結構,如字符串、哈希、列表、集合、有序集合等,還支持主從復制、持久化、自動分區等高級功能,適用于多種復雜場景。
- Memcached:廣泛使用的高性能分布式內存緩存系統,設計簡潔,易于部署和擴展,適合快速讀取大量簡單鍵值對數據的場景,但不支持數據持久化和復雜數據結構。
- NCache:功能強大的分布式緩存解決方案,支持多種緩存機制,如本地緩存、客戶端緩存、分布式緩存等,具備數據自動分片、自動復制、故障轉移等特性,適用于.NET分布式緩存場景。
(3). Web緩存中間件
- Varnish:高效的HTTP加速器,主要用于緩存HTTP請求,通過緩存網頁來降低后端服務器的負擔,提供快速的內容交付服務,可通過VCL語言進行高度定制。
- Nginx: 用于緩存HTTP請求, Nginx 通過
proxy_cache
模塊實現反向代理緩存,可設置緩存路徑、緩存鍵等參數。適用于高并發場景,可緩存靜態資源,減輕后端服務器負擔。 - SQUID: 用于緩存HTTP請求, Squid 可作為正向代理和反向代理,通過配置實現反向代理緩存。支持豐富的訪問控制、緩存管理、內容過濾。用于企業內部網絡,緩存外部 Web 內容,提高訪問效率。
以下是常見緩存中間件的對比表格:
中間件名稱 | 支持的數據結構 | 持久化支持 | 分布式支持 | 性能表現 |
---|---|---|---|---|
Redis | 多種(字符串、哈希、列表、集合、有序集合等) | 支持 | 支持(分片和復制) | 高 |
Memcached | 簡單鍵值對 | 不支持 | 支持(需第三方工具或客戶端庫) | 高 |
NCache | 多種 | 支持 | 支持 | 高 |
Ehcache | 支持對象 | 支持 | 支持 | 中等 |
Varnish | HTTP請求 | 不適用 | 支持 | 高 |
Nginx | HTTP請求 | 不適用 | 支持 | 高 |
在選擇緩存中間件時,需綜合考慮應用需求、性能要求、持久化需求等因素,以實現最佳的系統性能和可維護性。
1.5 緩存設計
緩存設計需要解決以下幾個問題:
(1). 哪些數據需要緩存?
在實際應用中,并非所有數據都適合緩存,通常需要根據數據的特點和業務需求來決定哪些數據需要緩存。以下是一些常見的需要緩存的數據類型或場景:
A.頻繁訪問的數據
- 靜態資源:如圖片、CSS、JavaScript 等網頁資源。這些資源在短時間內不會發生變化,且被用戶頻繁訪問。通過緩存這些靜態資源,可以大大減少從服務器獲取資源的次數,提高網頁加載速度。
- 熱點數據:如電商網站的熱門商品信息、新聞網站的頭條新聞等。這些數據是用戶訪問頻率極高的,緩存這些數據可以減輕后端數據庫的負擔,提高系統的響應速度。
- 用戶會話信息:如用戶的登錄狀態、購物車內容等。在用戶頻繁操作過程中,這些信息需要不斷讀取,將其緩存可以快速獲取,提升用戶體驗。
B. 計算成本高的數據
- 復雜查詢結果:一些需要進行大量計算、關聯查詢或數據處理才能得到的結果,如數據分析報表、推薦系統的推薦結果等。這些結果的生成往往耗時較長,將其緩存可以避免重復計算,提高系統的性能。
- 機器學習模型預測結果:對于一些實時性要求不高的機器學習模型預測結果,如用戶畫像、信用評分等,可以緩存起來,供后續請求直接使用。
C.數據變化不頻繁的數據
- 配置信息:如系統配置、應用配置等。這些數據通常在系統啟動時加載,只有在系統配置發生變化時才會更新,適合緩存。
- 字典數據:如城市列表、商品分類等。這些數據相對穩定,更新頻率低,緩存后可以減少對數據庫的訪問。
D. 實時性要求不高的數據
- 天氣預報:天氣預報數據通常有一定的更新周期,如每小時更新一次。在兩次更新之間,可以將天氣預報數據緩存起來,供用戶查詢。
- 新聞資訊:對于一些非實時的新聞資訊,如科技新聞、文化新聞等,在一定時間內(如半小時或一小時)更新一次即可,中間可以緩存數據。
E. 數據量較大的數據
- 歷史記錄數據:如用戶的瀏覽歷史、訂單歷史等。這些數據量可能較大,且查詢時對實時性要求不高,可以緩存部分歷史記錄數據,提高查詢效率。
- 日志數據:對于一些不需要實時處理的日志數據,可以緩存后批量寫入數據庫或日志存儲系統。
F. 數據的約束條件
- 數據一致性要求較低的數據:對于一些對數據一致性要求不是特別高的場景,如新聞資訊的瀏覽量、商品的推薦順序等,可以緩存數據。即使緩存中的數據與數據庫中的數據存在一定的時間差,也不會對業務產生重大影響。
- 數據更新頻率可預測的數據:如果數據的更新頻率可以預測,如每天凌晨更新一次統計數據,則可以在數據更新后及時更新緩存,保證緩存數據的時效性。
(2). 緩存的位置?
- 前端緩存:CDN緩存,反向代理緩存等
- 后端緩存:分布式緩存服務器(Redis集群服務器、Memcached服務器)
- 本地緩存:本機(內存,硬盤)
(3). 如何緩存的問題?
-
設置緩存過期策略
- 固定時間:比如指定緩存的時間是30分鐘;
- 相對時間:比如最近10分鐘內沒有訪問的數據;
-
緩存同步機制
- 實時寫入(PUSH)
- 異步刷新(PUSH & PULL)
2. 前端緩存
2.1 CDN緩存
CDN主要解決將數據緩存到離用戶最近的位置,一般緩存靜態資源文件(頁面,腳本,圖片,視頻,文件等)。國內網絡異常復雜,跨運營商的網絡訪問會很慢。為了解決跨運營商或各地用戶訪問問題,可以在重要的城市,部署CDN應用。使用戶就近獲取所需內容,降低網絡擁塞,提高用戶訪問響應速度和命中率。
2.1.1 CDN原理
CDN的基本原理是廣泛采用各種緩存服務器,將這些緩存服務器分布到用戶訪問相對集中的地區或網絡中,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的工作正常的緩存服務器上,由緩存服務器直接響應用戶請求。
1. 未部署CDN應用前
網絡路徑:
- 請求:本機網絡(局域網)–> 運營商網絡 --> 應用服務器機房
- 響應:應用服務器機房 --> 運營商網絡 --> 本機網絡(局域網)
在不考慮復雜網絡的情況下,從請求到響應需要經過3個節點,6個步驟完成一次用戶訪問操作。
2. 部署CDN應用后
網絡路徑:
- 請求:本機網絡(局域網)–> 運營商網絡
- 響應:運營商網絡 --> 本機網絡(局域網)
在不考慮復雜網絡的情況下,從請求到響應需要經過2個節點,2個步驟完成一次用戶訪問操作。與不部署CDN服務相比,減少了1個節點,4個步驟的訪問。極大的提高的系統的響應速度。
2.1.2 CDN優缺點
1. 優點
- 本地Cache加速:提升訪問速度,尤其含有大量圖片和靜態頁面站點;
- 鏡像服務:消除了不同運營商之間互聯的瓶頸造成的影響,實現了跨運營商的網絡加速,保證不同網絡中的用戶都能得到良好的訪問質量;
- 遠程加速:遠程訪問用戶根據DNS負載均衡技術智能自動選擇Cache服務器,選擇最快的Cache服務器,加快遠程訪問的速度;
- 帶寬優化:自動生成服務器的遠程Mirror(鏡像)cache服務器,遠程用戶訪問時從cache服務器上讀取數據,減少遠程訪問的帶寬、分擔網絡流量、減輕原站點WEB服務器負載等功能。
- 集群抗攻擊:廣泛分布的CDN節點加上節點之間的智能冗余機制,可以有效地預防黑客入侵以及降低各種D.D.o.S攻擊對網站的影響,同時保證較好的服務質量。
2. 缺點
- 動態資源緩存,需要注意實時性;
解決辦法:主要緩存靜態資源,動態資源建立多級緩存或準實時同步等。
- 如何保證數據的一致性和實時性需要權衡考慮。
解決辦法:設置緩存失效時間;數據版本號等。
2.1.3 CDN架構參考
2.1.4 CDN技術實踐
目前,中小型互聯網公司,綜合成本考慮,一般租用第三方CDN服務,大型互聯網公司,采用自建或第三方結合的方式。比如淘寶剛開始使用第三方的,當流量很大后,第三方公司無法支撐其CDN流量,淘寶最后采用自建CDN的方式實現。
例如阿里云的CDN架構,如下圖所示:
阿里云的CDN架構主要由調度系統、鏈路質量系統、緩存系統和支撐系統這四大系統組成。
-
鏈路質量系統
鏈路質量探測系統會實時監測緩存系統中的所有節點和鏈路的實時負載以及健康狀況,并將結果反饋給調度系統,調度系統根據用戶請求中攜帶的IP地址解析用戶的運營商和區域歸屬,然后綜合鏈路質量信息為用戶分配一個最佳接入節點。
-
調度系統
支持策略中心、DNS、HTTPDNS和302調度模式。當終端用戶發起訪問請求時,用戶的訪問請求會先進行域名DNS解析,然后通過阿里云CDN的調度系統處理用戶的解析請求。
-
CDN緩存系統
用戶通過收到的最佳接入節點訪問對應的緩存節點,如果節點已經緩存了用戶請求的資源,會直接將資源返回給用戶;如果L1(邊緣節點)和L2(匯聚節點)節點都沒有緩存用戶請求的資源,此時會返回源站去獲取資源并緩存到緩存系統,供后續用戶訪問,避免重復回源。分級緩存的部署架構可提高內容分發效率、降低回源帶寬以及提升用戶體驗。
-
支撐服務系統
支撐服務系統包括天眼、數據智能和配置管理系統,分別具備了資源監測、數據分析和配置管理能力。
- 資源監測:天眼可以對緩存系統上用戶業務運行的狀態進行監測。例如對CDN加速域名的QPS、帶寬、HTTP狀態碼等常見指標的監控。
- 數據分析:用戶可以分析CDN加速域名的TOP URL、PV、UV等數據。
- 配置管理:通過配置管理系統,用戶可以配置緩存文件類型、緩存時去參數緩存等緩存規則,以提升緩存系統的運作效率。
2.2. 反向代理緩存
反向代理是指在網站服務器機房部署代理服務器,實現負載均衡,數據緩存,安全控制等功能。反向代理緩存是一種性能優化技術,通過在反向代理服務器上緩存經常請求的內容,避免每次請求都向后端服務器獲取數據,從而提高響應速度和降低后端負載。
2.2.1 反射代理緩存原理
反向代理位于應用服務器機房,處理所有對WEB服務器的請求。如果用戶請求的頁面在代理服務器上有緩沖的話,代理服務器直接將緩沖內容發送給用戶。如果沒有緩沖則先向WEB服務器發出請求,取回數據,本地緩存后再發送給用戶。通過降低向WEB服務器的請求數,從而降低了WEB服務器的負載。
反向代理一般緩存靜態資源,動態資源轉發到應用服務器處理。常用的緩存應用服務器有Varnish,Ngnix,Squid。
2.2.2 SQUID反向代理示例
Squid 反向代理一般只緩存靜態資源,動態程序默認不緩存。根據從 WEB 服務器返回的 HTTP 頭標記來緩沖靜態頁面。有四個最重要 HTTP 頭標記:
- Last-Modified: 告訴反向代理頁面什么時間被修改
- Expires: 告訴反向代理頁面什么時間應該從緩沖區中刪除
- Cache-Control: 告訴反向代理頁面是否應該被緩沖
- Pragma: 用來包含實現特定的指令,最常用的是 Pragma:no-cache
Squid 反向代理加速網站實例
- 通過DNS的輪詢技術,將客戶端的請求分發給其中一臺 Squid 反向代理服務器處理;
- 如果這臺 Squid 緩存了用戶的請求資源,則將請求的資源直接返回給用戶;
- 否則這臺 Squid 將沒有緩存的請求根據配置的規則發送給鄰居 Squid 和后臺的 WEB 服務器處理;
- 這樣既減輕后臺 WEB 服務器的負載,又提高整個網站的性能和安全性。
2.2.3 代理緩存比較
常用的代理緩存有Varnish,Squid,Ngnix,簡單比較如下:
(1)varnish和squid是專業的cache服務,nginx需要第三方模塊支持;
(2)Varnish采用內存型緩存,避免了頻繁在內存、磁盤中交換文件,性能比Squid高;
(3)Varnish由于是內存cache,所以對小文件如css,js,小圖片啥的支持很棒,后端的持久化緩存可以采用的是Squid或ATS;
(4)Squid功能全而大,適合于各種靜態的文件緩存,一般會在前端掛一個HAProxy或nginx做負載均衡跑多個實例;
(5)Nginx采用第三方模塊ncache做的緩沖,性能基本達到varnish,一般作為反向代理使用,可以實現簡單的緩存。
3. 分布式緩存
CDN緩存、反向代理緩存,主要用于解決前端靜態文件或用戶請求資源的緩存,數據源一般為靜態文件或動態生成的文件(有緩存頭標識)。而分布式緩存主要指緩存用戶經常訪問數據的緩存,數據源為數據庫。一般起到熱點數據訪問和減輕數據庫壓力的作用。
目前分布式緩存設計,在大型網站架構中是必備的架構要素。常用的中間件有Memcached、Redis等。
3.1 Memcached緩存
Memcache是一個高性能,分布式內存對象緩存系統,通過在內存里維護一個統一的巨大的hash表,它能夠用來存儲各種格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。簡單的說就是將數據調用到內存中,然后從內存中讀取,從而大大提高讀取速度。
Memcache特性:
- 物理緩存:使用物理內存作為緩存區,可獨立運行在服務器上。每個進程最大2G,如果想緩存更多的數據,可以開辟更多的memcache進程(不同端口)或者使用分布式memcache進行緩存,將數據緩存到不同的物理機或者虛擬機上。
- 鍵值對存儲:使用key-value的方式來存儲數據,這是一種單索引的結構化數據組織形式,可使數據項查詢時間復雜度為O(1)。
- 協議簡單:基于文本行的協議,直接通過telnet在memcached服務器上可進行存取操作,簡單,方便多種緩存參考此協議;
- 基于libevent高性能通信:Libevent是一套利用C開發的程序庫,它將BSD系統的kqueue,Linux系統的epoll等事件處理功能封裝成一個接口,與傳統的select相比,提高了性能。
- 內置的內存管理方式:所有數據都保存在內存中,存取數據比硬盤快,當內存滿后,通過LRU算法自動刪除不使用的緩存,但沒有考慮數據的容災問題,重啟服務,所有數據會丟失。
- 分布式支持:各個memcached服務器之間互不通信,各自獨立存取數據,不共享任何信息。服務器并不具有分布式功能,分布式部署取決于memcache客戶端。
- 緩存策略:Memcached的緩存策略是LRU(最近最少使用)到期失效策略。在memcached內存儲數據項時,可以指定它在緩存的失效時間,默認為永久。當memcached服務器用完分配的內時,失效的數據被首先替換,然后也是最近未使用的數據。在LRU中,memcached使用的是一種Lazy Expiration策略,自己不會監控存入的key/vlue對是否過期,而是在獲取key值時查看記錄的時間戳,檢查key/value對空間是否過期,這樣可減輕服務器的負載。
3.1.1 Memcached原理
MemCached的工作流程如下:
(1)先檢查客戶端的請求數據是否在Memcached中,如有,直接把請求數據返回,不再對數據庫進行任何操作;
(2)如果請求的數據不在Memcached中,就去查數據庫,把從數據庫中獲取的數據返回給客戶端,同時把數據緩存一份到memcached中(Memcached客戶端不負責,需要程序實現);
(3)每次更新數據庫的同時更新Memcached中的數據,保證一致性;
(4)當分配給Memcached內存空間用完之后,會使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效數據首先被替換,然后再替換掉最近未使用的數據。
3.1.2 Memcached集群
Memcached 雖然稱為 “ 分布式 ” 緩存服務器,但服務器端并沒有 “ 分布式 ” 功能。每個服務器都是完全獨立和隔離的服務。 memcached 的分布式,是由客戶端程序實現的。
當向Memcached集群存入/取出key value時,memcached客戶端程序根據一定的算法計算存入哪臺服務器,然后再把key value值存到此服務器中。
因此,存取數據分二步走:
第一步,選擇服務器;
第二步,存取數據。
分布式算法
選擇服務器算法有兩種,一種是根據余數來計算分布,另一種是根據散列算法來計算分布。
-
余數算法:
- 先求得鍵的整數散列值,再除以服務器臺數,根據余數確定存取服務器。
- 優點:計算簡單,高效;
- 缺點:在memcached服務器增加或減少時,幾乎所有的緩存都會失效。
-
散列算法(一致性Hash):
- 先算出memcached服務器的散列值,并將其分布到0到2的32次方的圓上,然后用同樣的方法算出存儲數據的鍵的散列值并映射至圓上,最后從數據映射到的位置開始順時針查找,將數據保存到查找到的第一個服務器上,如果超過2的32次方,依然找不到服務器,就將數據保存到第一臺memcached服務器上。
如果添加了一臺memcached服務器,只在圓上增加服務器的逆時針方向的第一臺服務器上的鍵會受到影響。
一致性Hash算法:解決了余數算法增加節點命中大幅額度降低的問題,理論上,插入一個實體節點,平均會影響到:虛擬節點數/2 的節點數據的命中。
3.2 Redis緩存
Redis 是一個開源(BSD許可)的,基于內存的,多數據結構存儲系統。可以用作數據庫、緩存和消息中間件。 支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與范圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。
內置了復制(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁盤持久化(persistence), 并通過 Redis哨兵(Sentinel)和自動分區(Cluster)提供高可用性(high availability)。
3.2.1 Redis常用數據類型
1. String類型
- 常用命令:set,get,decr,incr,mget
- 應用場景:String是最常用的一種數據類型,與Memcache的key value存儲方式類似。
- 實現方式:String在redis內部存儲默認就是一個字符串,被redisObject所引用,當遇到incr,decr等操作時會轉成數值型進行計算,此時redisObject的encoding字段為int。
2. Hash類型
- 常用命令:hget,hset,hgetall
- 應用場景:以存儲一個用戶信息對象數據為例:
- 實現方式:Hash類型對應的Value,內部實際就是一個HashMap,實際這里會有2種不同實現。
- Hash的成員比較少時Redis為了節省內存會采用類似一維數 組的方式來緊湊存儲,而不會采用真正的HashMap結構,對應的value redisObject的encoding為zipmap;
- 當成員數量增大時會自動轉成真正的HashMap,此時encoding為ht。
3. List類型
- 常用命令:lpush,rpush,lpop,rpop,lrange
- 應用場景:List類型的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現。
- 實現方式:List的實現為一個雙向鏈表,可以支持反向查找和遍歷,方便操作。不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。
4. Set類型
- 常用命令:sadd,spop,smembers,sunion
- 應用場景:Set類型對外提供的功能與list類似是一個列表的功能,特殊之處在于set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set 是一個很好的選擇,并且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的。
- 實現方式:Set類型的內部實現是一個value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。
5. Sorted Set類型
- 常用命令:zadd,zrange,zrem,zcard;
- 使用場景:Sorted Set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,并且是插入有序的,即自動排序。當你需要一個有序的并且不重復的集合列表,可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。
- 實現方式:Sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap里放的是成員到score的映射,而跳躍表里存放的 是所有的成員,排序依據是HashMap里存的score,使用跳躍表的結構可以獲得比較高的查找效率,并且在實現上比較簡單。
3.2.2 Redis集群
1. 通過KeepAlived實現的高可用方案
-
切換流程:
- 當Master掛了后,VIP漂移到Slave;Slave 上keepalived 通知redis 執行:slave of no one, 開始提供業務
- 當Master起來后,VIP 地址不變,Master的keepalived通知redis執行slave of slave IP host,開始作為從同步數據
- 依次類推
-
主從同時宕機情況:
- 非計劃性,不做考慮,一般也不會存在這種問題
- 計劃性重啟,重啟之前通過運維手段SAVE DUMP 主庫數據;需要注意順序:
1). 關閉其中一臺機器上所有redis,是得master全部切到另外一臺機器(多實例部署,單機上既有主又有從的情況);并關閉機器
2). 依次dump主上redis服務
3). 關閉主庫
4). 啟動主庫,并等待數據load完畢
5). 啟動從庫
6). 刪除DUMP文件(避免重啟加載慢)
2. 使用Twemproxy實現集群方案
Twemproxy由Twitter公司開源的c版本proxy,同時支持memcached和redis,Twitter用它主要減少前端與緩存服務間網絡連接數。
- Twemproxy方案的特點:快速、輕量級、減少后端Cache Server連接數、易配置、支持ketama、modula、random、常用hash分片算法等。
注:圖中使用Keepalived實現高可用主備方案,解決proxy單點問題。
-
Twemproxy方案的優點:
- 對于客戶端而言,redis集群是透明的,客戶端簡單,遍于動態擴容
- Proxy為單點、處理一致性hash時,集群節點可用性檢測不存在腦裂問題
- 高性能,CPU密集型,而redis節點集群多CPU資源冗余,可部署在redis節點集群上,不需要額外設備
3.3 Memcached與Redis的比較
在選擇緩存系統時,如果需要簡單的緩存功能且對數據丟失不敏感,Memcached 是一個高效的選擇;如果需要復雜的數據結構支持、數據持久化和高可用性保障,Redis 更為合適。
特性 | Memcached | Redis |
---|---|---|
數據結構 | 僅支持鍵值對(字符串) | 支持多種數據結構,如字符串、哈希、列表、集合、有序集合、位圖等 |
持久化 | 不支持 | 支持 RDB 快照和 AOF 日志 |
線程模型 | 多線程,高并發讀寫性能好 | 單線程,順序執行避免鎖競爭 |
內存管理 | 預分配固定內存,基于 LRU 淘汰機制 | 動態內存分配,支持多種內存淘汰策略 |
集群模式 | 依賴客戶端分片(如 Twemproxy) | 支持原生 Cluster 模式 |
適用場景 | 簡單鍵值緩存,如會話、HTML 片段緩存 | 緩存、消息隊列、實時統計等復雜場景 |
性能 | 在簡單的鍵值操作和高并發讀寫場景中表現更好 | 在復雜數據操作和高并發場景中性能優異 |
4. 本地緩存
本地緩存是指應用內部的緩存,標準的分布式系統,一般有多級緩存構成。本地緩存是離應用最近的緩存,一般可以將數據緩存到硬盤或內存。
- 硬盤緩存
將數據緩存到硬盤到,讀取時從硬盤讀取。原理是直接讀取本機文件,減少了網絡傳輸消耗,比通過網絡讀取數據庫速度更快。可以應用在對速度要求不是很高,但需要大量緩存存儲的場景。
- 內存緩存
直接將數據存儲到本機內存中,通過程序直接維護緩存對象,是訪問速度最快的方式。
5. 緩存架構示例
1. 職責劃分:
- CDN:存放HTML,CSS,JS等靜態資源;
- 反向代理:動靜分離,只緩存用戶請求的靜態資源;
- 分布式緩存:緩存數據庫中的熱點數據;
- 本地緩存:緩存應用字典等常用數據;
2. 請求過程:
- 瀏覽器向客戶端發起請求,如果CDN有緩存則直接返回;
- 如果CDN無緩存,則訪問反向代理服務器;
- 如果反向代理服務器有緩存則直接返回;
- 如果反向代理服務器無緩存或動態請求,則訪問應用服務器;
- 應用服務器訪問本地緩存;如果有緩存,則返回代理服務器,并緩存數據;(動態請求不緩存)
- 如果本地緩存無數據,則讀取分布式緩存;并返回應用服務器;應用服務器將數據緩存到本地緩存(部分);
- 如果分布式緩存無數據,則應用程序讀取數據庫數據,并放入分布式緩存。