五分鐘學後端技術:如何學習Redis、memcache等常用緩存技術

原創聲明

本文作者:黃小斜

轉載請務必在文章開頭註明出處和作者。

本文思維導圖

在這裏插入圖片描述

什麼是緩存

計算機中的緩存

做後端開發的同學,想必對緩存都不會陌生了,平時我們可能會使用Redis,MemCache這類緩存組件,或者是本地緩存,來實現一些後端的應用。

那麼,嚴格來說,到底什麼纔是緩存呢,先來看看百度百科的定義。

緩存(cache),原始意義是指訪問速度比一般隨機存取存儲器(RAM)快的一種高速存儲器,通常它不像系統主存那樣使用DRAM技術,而使用昂貴但較快速的SRAM技術。緩存的設置是所有現代計算機系統發揮高性能的重要因素之一。

最早,“緩存”一詞是用來指代計算機硬件中的高速緩存,因爲CPU和內存的運算速度差距過大,如果CPU直接和內存交互的話,會浪費掉CPU的大量運算時間,於是有了高速緩存,來爲這兩個速度差距甚遠的組件做中介。

具體的工作原理是,CPU要取數據的時候,先找高速緩存要,由於它們倆的速度差距並不大,所以CPU不會損失掉太多性能,如果數據就在緩存中,那麼就直接在緩存裏取,否則則到內存去取,取完之後還要留在高速緩存中,以便於下次CPU要使用時無需再到內存中去取。

其實,高速緩存還可以分爲一級緩存,二級緩存和三級緩存等,每往下一級,速度也就越慢,價格也越低,畢竟,成本是我們不得不考慮的因素,要不然一切硬件都上頂配,就不需要討論軟件的優化了。

除了高速緩存外,其實還有硬盤緩存、網絡緩存等操作系統自身實現的緩存,目的也是爲了在兩個運算速度不同的組件之間建立一個橋樑,並且,緩存中的數據往往都是局部數據,又稱熱點數據,這部分數據經常被使用,因此更具有被緩存的價值

軟件開發中的緩存

上面講了一些關於計算機中已有的緩存,那麼,我們平時在代碼開發中用的緩存又是什麼東西呢?好像不太一樣啊。

相信大家都聽過Redis,這是業界最流行的緩存組件之一,不妨看看它是如何被定義的。

redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。

在此基礎上,redis支持各種不同方式的排序。與memcached一樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。

根據上文的描述,我們可以看出,Redis是一個K/V的存儲系統,並且它是把數據緩存在內存中的,大家都知道,內存比硬盤的速度要快得多,而我們平時經常使用的數據庫,本質上還是基於硬盤IO來工作的,每次讀寫數據庫都要經過硬盤的IO操作。

所以,讀寫數據庫的耗時要比讀內存要慢得多,剛剛我們說了,CPU讀寫內存和高速緩存的速度差異也很大,所以,這裏Redis和高速緩存扮演了同一個角色,只不過一個是硬件,一個是軟件,一個連接的是內存和CPU,另一個連接的是磁盤和內存。

除了Redis以外,還有很多緩存組件比如memcache也是基於這種方式來實現的,通過緩存數據庫的熱點數據,來提高應用的訪問速率,在後端開發中是非常常見的一種技術應用。

如何學習緩存技術

作爲一個後端開發工程師,不懂緩存是不行的,即使你天天做的是CRUD,至少也要會使用本地緩存吧。

另外,面試的時候經常也會有緩存方面的問題,簡單點的,可能就讓你說一說Redis的基礎和實現原理,複雜點的,會結合場景,問你緩存可能引發的一些問題,又或者,分佈式場景下的緩存如何設計。

從會使用到了解原理,再到學習進階的用法,學習緩存和學習其他技術一樣,需要先易後難,現在就讓我們一起來看看,如何搞定緩存這個難纏的小妖精吧。

本地緩存chm

第一次接觸緩存,其實是我在學習hashmap的時候,hashmap本身就是一個KV的鍵值對對象,和咱們剛剛說的Redis似乎有點像,那麼,如何讓hashmap真正變成一個緩存呢,其實也不難。

實際上,很多本地緩存就是直接用concurrenthashmap來實現的,注意,這裏用的是支持併發的concurrenthashmap,這因爲啊,緩存對象是可以支持多個線程同時訪問的,如果出現同時put好的情況,就有可能出現異常,於是,使用concurrenthashmap就可以避免這種問題。

爲了方便起見,後面對於concurrenthashmap簡稱chm。chm不僅可以保證對其訪問是線程安全的,而且比直接用synchronized等關鍵字要更加高效靈活。

那麼,chm實現緩存的原理是什麼呢?首先,在應用中,緩存的本質就是把一些經常出現的數據存在內存中,而Java的內存又可以分爲堆內存和棧內存,緩存對象自然是要放在堆內存中了。

所以它是一個類裏的一個成員變量,比如這樣。

private Map<String, CacheObj> CACHE_OBJECT_MAP = new ConcurrentHashMap<>();

但是這樣使用緩存有一個問題,這個成員變量屬於實例,如果實例沒有初始化或者是被回收,那麼這個緩存對象也就跟着消失了,那肯定是不行的,畢竟緩存的生命週期應該和應用本身一樣長,另外,這個緩存對象還可能被修改,比如我可以在代碼裏隨便操作一下,讓它 = null,或者是重新初始化一下,那一樣也是不被允許的。

所以,標準的chm本地緩存應該是這樣被初始化的。

private static final Map<String, CacheObj> CACHE_OBJECT_MAP = new ConcurrentHashMap<>();

靜態變量保證它一直存在於堆內存中,而final關鍵字修飾可以讓它不會被重新初始化或者指向其他對象。

接下來的事情就簡單了,你只要使用get和put方法就可以了。
當然,這只是最基礎的本地緩存實現,還可以實現成LRU緩存,搞各種騷操作,這裏我們不再具體討論,網上有很多demo,可以自行去參考。

常用緩存組件實戰

除了本地緩存之外,我們還應該去了解一些常用的緩存技術,比如Redis、memcache這類緩存組件,還有類似Ecache這類的Java緩存框架。

這類成熟的緩存技術,更加值得我們學習和使用,它們一般都能提供各個場景下的先進解決方案,比如如何處理熱點數據,如何進行分佈式部署,實現高可用,如何進行數據同步,主從複製,以及實現分佈式鎖、分佈式ID生成器等各個場景的應用。

有一個面試題相信大家都遇到過,那就是問你redis和memcache的區別,我們不妨通過這個面試題來了解一下,到底它們都有些什麼特點。

Redis不僅支持簡單的k/v類型的數據,同時還支持list、set、zset(sorted set)、hash等數據結構的存儲,使得它擁有更廣闊的應用場景。

而Memcached唯一支持的數據類型是字符串string,非常適合緩存只讀數據,因爲字符串不需要額外的處理。

Redis最大的亮點是支持數據持久化,它在運行的時候可以將數據備份在磁盤中,斷電或重啓後,緩存數據可以再次加載到內存中,只要Redis配置的合理,基本上不會丟失數據。

這一點很要命,memcache不持久話數據,萬一斷電了就裂開。

Memcache在併發場景下,能用cas保證一致性,而Redis事務支持比較弱,只能保證事務中的每個操作連續執行。

雖然Redis支持事務而memcache不支持,但是memcache對並非的支持不亞於Redis。

性能方面,Redis在讀操作和寫操作上是略領先Memcached的。
Memcached的內存管理不像Redis那麼複雜,元數據metadata更小,相對來說額外開銷就很少。

對於制度數據來說,即使沒有數據備份也沒什麼關係,但是如果存在讀寫,那麼顯然memcache是不合適的,整體來看,Redis還是略勝一籌。

Redis這類緩存組件其實是通過C/S方式部署服務的,而另一種緩存組件ecache,則是直接集成,緩存的數據就放在JVM裏,有點類似於我們的本地緩存,其實ecache還應用在hibernate中,所以很多時候我們都是在不知情的情況下就已經使用了cache。

當然了,ecache這類緩存的數據放在JVM,要共享起來的話就比較麻煩了,特別是需要應用在分佈式場景的時候,實現起來是比較複雜的。

緩存的實現原理

相信你在看了本地緩存那一部分的時候,會覺得緩存實現起來也沒什麼難度啊,一個hashmap就搞定了。

實際上,緩存的實現要考慮的問題還很多,就拿Redis來說,使用什麼樣的數據結構來存儲數據就是很重要的一個問題,我們當然希望用盡量小的空間來存儘量多的數據,同時還要提升緩存CRUD的效率。

Redis中支持多種數據結構,比如字符串、數組、字典(map)以及列表、set、有序set等,別看這些數據結構很簡單,但是作者實現起來都花了不少功夫。

往往一個結構有多種底層實現,目的就是爲了壓縮空間,提高效率。有興趣的朋友可以看下這篇文章
Redis數據結構的底層實現https://blog.csdn.net/Future_LL/article/details/88525004

除了數據結構之外,Redis本身的實現也耐人尋味,比如,Redis的服務端和客戶端是怎麼設計的,另外,Redis是單線程工作的,爲什麼要這麼設計,還有Redis的事務是如何實現的,這些內容都值得我們一一去學習瞭解。

另外還有一些進階的內容,比如Redis的部署方案,通常包括主從部署、集羣方案、HA方案等等,Redis官方也有Redis-cluster的高可用集羣方案。Redis也常常用於分佈式鎖,分佈式ID生成器,而這些技術的背後,其實都有很多值得我們深挖的點。

時間關係,我們今天就講到這裏,對於緩存和Redis的學習,就從這篇文章開始吧。

博客

Java技術倉庫《Java程序員複習指南》

https://github.com/h2pl/Java-Tutorial

整合全網優質Java學習內容,幫助你從基礎到進階系統化複習Java

面試指南

全網最熱的Java面試指南,共200多頁,非常實用,不管是用於複習還是準備面試都是不錯的。
在公衆號【Java技術江湖】回覆“PDF”即可免費領取。

寫在最後

如果覺得本文對你有幫助的話,請你也不要吝嗇你的“好看”哈,轉發朋友圈就是對我最大的支持啦,你們的支持是對我最大的鼓勵。

對本系列文章有什麼建議和意見,也歡迎留言告訴我,期待你的回饋。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章