(轉)緩存

不管是CDN緩存加速,仍是CPU的三級緩存,又或者是在現在互聯網時代流量紅利所帶來的高併發結構客戶端,而不得不使用緩存架構。緩存,對於技術人來講,是一個必須直面的名詞。 然而,如何清晰明瞭的選擇緩存服務以及如何在設計架構時使用緩存去優化業務,對於咱們不少人來講,一直以來都比較迷惑,本文從這一點出發,簡單介紹了緩存概念和分佈式緩存服務的一些應用場景。css

 

 

 

緩存的必要性redis

 

通常而言,互聯網的典型架構能夠分爲三層模式,客戶端層,站點層,數據層。而架構分層的本質是一個「數據移動」的過程,而後「被處理」和「被呈現」的過程。用戶請求從界面(瀏覽器或App界面)到網絡轉發、應用服務再到存儲(數據庫或文件系統),而後返回到界面呈現內容。 sql

 

而隨着互聯網的普及與發展,伴隨而來的是內容信息類型日益複雜。同時,因爲移動互聯網的流量紅利所帶來的用戶數和訪問量,更是造就了最高10億DAU的「微信神話」。數據庫

所以,近幾年爆炸式的互聯網發展也後端架構提出了新的挑戰——如何去平衡應用服務器和數據庫服務器成本和性能之間的矛盾。 後端

資源每每是有限的,同時,關係型數據庫的讀寫能力也受限於磁盤,每秒可以接收的請求次數也是有限的,如何可以有效利用有限的資源來提供儘量大的吞吐量?瀏覽器

引入緩存層,是實現資源的高效利用和下降用戶交互延時的不二法則。緩存

 

緩存的影響因素和分類

 

2.1 介質因素

瞭解緩存在架構設計中的應用,首先咱們來看下緩存的分類。最基礎的如CPU緩存,CPU緩存定義爲CPU與內存之間的臨時數據交換器,爲解決CPU運行處理速度與內存讀寫速度不匹配的矛盾而誕生,通常直接集成在CPU芯片上,這裏就不展開細講了。另外就是本地緩存和分佈式緩存,聊到這二者時,咱們先來了解下存儲介質。服務器

從硬件介質角度而言,存儲介質廣義上能夠分爲內存和硬盤,其中內存(RAM)做爲「指令中轉器」,只負責臨時性存儲。磁盤做爲「外存」,能夠持久化存儲。微信

• 內存:將緩存存儲於內存中是最快的選擇,無需額外的I/O開銷,可是內存的缺點是沒有持久化落地物理磁盤,一旦應用異常break down而從新啓動,數據很難或者沒法復原。網絡

• 硬盤:通常來講,不少緩存框架會結合使用內存和硬盤,在內存分配空間滿了或是在異常的狀況下,能夠被動或主動的將內存空間數據持久化到硬盤中,達到釋放空間或備份數據的目的。

 因爲馮諾依曼式自身模型緣由,就數據傳輸速度而言,CPU緩存 > 內存 > 硬盤。

 

上圖是一個典型數據「被處理」過程,而咱們常說的存儲,依託於硬盤介質,而緩存,更可能是須要內存 + 硬盤結合。

2.2 緩存分類

瞭解了基本的存儲介質知識後,咱們接下來認識緩存分類,根據應用架構中的耦合度,分爲local cache(本地緩存)和 remote cache(分佈式緩存)。

• 本地緩存:也叫進程內緩存,顧名思義,指應用中的緩存組件,優勢是應用和緩存在同一進程內部,進程內緩存省去了網絡開銷,因此一來節省了內網帶寬,二來響應時延會更低。缺點就是多個應用沒法共享緩存,且難以保持進程緩存的一致性。

• 分佈式緩存:也叫進程外緩存,指的是與應用分離的緩存組件或服務,其最大的優勢是自身就是一個獨立的應用,與本地應用隔離,多個應用可直接的共享緩存。如咱們常見的memcache和Redis數據庫。

而在分層架構設計中,有一條準則:即站點層、服務層需達到無狀態無數據。 

其目的是爲了當業務須要時,可以任意的增長節點水平擴展。因此數據和狀態儘可能存儲到後端的數據存儲服務,例如數據庫服務或者緩存服務。固然,若是業務處於「極其高併發且業務必定程度容許不一致」的場景,也能夠考慮使用本地緩存,其它通常不推薦使用。

 

主流分佈式緩存分析

 

在對比以前,咱們先來了解下分佈式緩存數據庫在分層架構中的位置,這樣有助於咱們明確的認識到緩存所起到的做用。

見上圖,按照經典互聯網架構三層模式,簡單畫出了站點層和數據層的交互邏輯。加入了緩存服務後,這裏也定義它爲緩存服務層,其處於站點層和數據層的中間,同時依賴於二者提供雙向的「數據移動」。既然如此,當咱們想要加入分佈式緩存服務時,那麼圖中緩存服務層中的Redis和memcache二者又該如何去選擇呢?

3.1 使用率分析

Redis和memcache都是互聯網分層架構中,最經常使用的KV緩存服務。儘管memcache首發(2003年)比Redis首發(2009年)早的多,二者也都是使用C語言編寫,可是當Redis一經發布,迅速就成爲了架構師手中設計分層架構時的優先選擇。

這裏只找到一張截止到17年時的使用率對比分析,不難看出Redis使用率一直呈現上升趨勢,到目前更是遠遠的甩下了memcahce。

3.2 功能分析

在對比前,先來了解Redis和memcahce數據庫分別究竟是什麼以及它們的基本概念。

• Redis:一個開源的、Key-Value型、基於內存運行並支持持久化的NoSQL數據庫;

• memcached:一款徹底開源、高性能的、分佈式的內存系統;

關鍵詞:內存、持久化。 

其實關鍵詞已經爲咱們涵蓋了Redis和memcahce二者的核心做用。Redis的持久化+緩存,memcache的緩存。若是把二者好比成學生,那麼「memcache」就像是一名特長生,專項發展。而「Redis」則是一名三好學生,「德智育」全面發展。

接下來咱們從不一樣維度詳細分析下Redis和memcahce數據庫二者的區別,以便於你們可以更好的區別並選擇適合本身的緩存數據庫。

一表勝千言,這是來自「特長生」和「三好學生」的較量。根據上圖,下面咱們來分析下二者在什麼場景下更加適用。

3.3 應用場景分析

3.3.1 何時傾向於適用Redis?

業務需求決定技術選型,當業務有這樣一些特色的時候,選擇Redis會更加適合。

a 存在複雜數據結構

Redis支持5種存儲類型,包含字符串、哈希、列表、集合、有序集合等,而Menmcache只支持KV。

假設當緩存數據類型比較複雜時,推薦使用Redis,這種場景多見於用戶訂單列表,用戶消息,帖子評論列表等。

b 當須要考慮緩存持久化時

Redis支持固化功能,當數據庫崩潰後重啓,內存能夠迅速的恢復熱數據。無需主動或被動的預熱,減小因Redis瞬間壓力過大致使的後端數據庫雪崩風險。 Redis的固化模式分爲兩種模式,一種是RDB快照模式,另一種是AOF持久化模式。二者的用途不一樣,請看下圖。 

這裏須要注意的是,RDB按期快照不能保證萬無一失,且AOF會下降Redis的效率。 同時,也別看着Redis有持久化功能,就跟打了雞血同樣想省下Mysql數據庫的錢,記住,讓專業的工具作專業的事情。

ps:若是是雲數據庫Redis(阿里雲、七牛雲)是默認開啓固化的,因此是內存+硬盤形式。

c 當須要高可用時

Redis自然支持集羣功能,能夠實現主動複製,讀寫分離。Redis在擴展和穩定高可用性能方面都是比較成熟的。

Redis官方也提供了sentinel集羣管理工具,可以實現主從服務監控,故障自動轉移,最重要的是,這些對於客戶端都是透明的,無需程序改動,也無需人工介入。

而Memcache自己並不支持集羣,全部的集羣形式都是經過客戶端實現。要想要實現高可用,須要進行二次開發,須要例如客戶端的雙讀雙寫或者服務端的集羣同步等。

若是業務當有緩存高可用場景需求時,那麼使用Redis比memcahce簡便的多。例如在即時通信業務中,用戶的在線狀態,就有高可用需求。

d 當Vlaue值很大時

前文也說了,Redis和Memcache都是以KV形式存儲,那麼除了數據類型因素,選擇Redis,還有什麼因素影響呢?

答案是Value值的大小。

在Redis官網的文檔中,咱們能夠查閱到,Redis支持多種複雜數據結構,也所以,支持Key和Value值大小最大能夠到512M。而Memcache的key和Value值大小都被限制在1M之內。

因此,當咱們若是有key-value值很是大的緩存服務應用場景時,那麼也只能使用Redis了。

3.3.2 何時傾向於適用Memcache?

說了這麼多關於Redis的好,甚至有種memcahe就是Redis子集的錯覺,而memcache有的功能,彷佛Redis都有了。非也,做爲「特長生」,當你面臨如下場景時,那麼選擇memcache緩存服務,比Redis可能更好一些。

a 數據量大,併發量大的業務

這裏的前提是緩存數據類型支持,即純KV場景。若是業務存在數據量大,併發量大的需求,那麼使用memcache或許更適合。 這個也和memcache的底層實現原理有關。

如上圖,當在內存分配、線程模型和網絡模型維度考慮時,若是當你的業務符合是數據量大,併發量大的緩存業務場景時,使用memcache比redis能達到訪問更快,同時,延時更低。這個時候,選擇memcache就再恰當不過了。

 

探討

 

4.1 保持緩存一致性的方式

前面咱們已經分析了Redis和memcache的功能對比以及其衍生出來的場景描述,最後千言萬語不如一句話:業務需求決定技術選型。選擇適合業務的緩存服務最爲重要。

既然是緩存服務,咱們都知道,用戶訪問到時,站點層先看緩存服務層是否能hit數據,若是miss,則會到後端數據庫拿到數據再原路返回給用戶,同時緩存服務層set。

假設,當緩存服務層存在數據,可是這時候,恰好用戶也在發送寫請求,那麼這個用戶hit,則會返回舊數據。出現這種狀況,歸根結底仍是由於數據庫和緩存主從延時致使。 如何保持緩存一致性,這是個值得深思的問題。也引伸出了當用戶發出寫請求時,應該先寫緩存仍是數據庫這個疑問。 Cache Aside Pattern:簡稱旁路緩存方案。基本原理就是數據庫有主數據庫(用於寫)、從數據庫(用於讀),另有緩存用於提高讀寫效率;

• 讀請求:標準的用戶訪問模式。站點層-緩存服務層-數據庫層

• 寫請求:先寫主數據庫,再淘汰緩存。

而目前,主流如微軟、臉書等公司都是使用都是Cache-Aside pattern(旁路緩存方案),針對寫請求,即先寫數據庫,而後再淘汰緩存。若是先操做緩存,在讀寫併發時,可能出現數據不一致狀況(數據庫主從未同步中的間隔時間)。

這種旁路緩存方案,也是爲了保障最終數據庫是正確的,而對於緩存的不一致,有限時間內的不一致是容許的(參考CAP原則和Base理論)。固然,這裏也有一個隱藏的坑點,假設當寫入數據庫已經成功的,可是以後淘汰緩存失敗了,針對這種狀況,這裏也提供一個簡單的思路。

流程以下圖所示:

(1)更新數據庫數據

(2)數據庫會將操做信息寫入binlog日誌當中

(3)訂閱程序(DTS或者cannal)提取出所須要的數據以及key

(4)另起一段非業務代碼,得到該信息

(5)嘗試刪除緩存操做,發現刪除失敗

(6)將這些信息發送至消息隊列

(7)從新從消息隊列中得到該數據,重試操做。

4.2 使用緩存服務的幾點誤區

a 使用緩存,不考慮雪崩

咱們先來認識下什麼是緩存雪崩。

• 緩存雪崩:當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時間段內,站點層會給後端系統(好比DB)帶來很大壓力。甚至直接壓垮數據庫,直接致使系統總體不可用。通常來講,在分層架構中,緩存服務最高能幫數據庫層抗住90%的壓力,若是當緩存數據庫出現崩潰時,若是事先未作好規劃,將直接致使雪崩。

爲了預防上述狀況,首先要作好容量預估,同時,使用採用高可用緩存集羣,最好災備方案,當一個緩存服務器服務掛掉時,可以作到自動切換服務。

ps:這也是爲啥雲數據庫受歡迎的緣由,簡單,省心。

b 將緩存服務層當作傳遞數據媒介

簡單來講,將緩存服務層當作MQ(消息隊列)使用,經過緩存傳遞數據,從而實現兩個服務通訊的目的,以下圖。

先不說專業工具作專業的事情,就一點,若是使用緩存傳遞數據的話,會直接致使服務耦合。 而MQ,做爲互聯網架構解耦神器,自然支持集羣高可用,並且支持數據落存儲。

ps:使用MQ後,上游不知道彼此存在,也不須要關注哪些下游訂閱了消息,這樣直接達到服務解耦的效果。

相關文章
相關標籤/搜索