架构师的 36 项修炼第02讲:架构核心技术之分布式缓存(上)
本課時的主題是分布式緩存。
?
緩存是架構設計中一個重要的手段。緩存的主要特點是技術比較簡單,同時對性能提升的效果又很顯著,所以緩存在很多地方都會被用到。使用緩存需要注意幾個關鍵指標:緩存鍵集合大小、緩存空間的大小以及緩存的使用壽命。這三個指標決定了緩存的有效性、緩存的使用效率、緩存實現的效果。緩存的類型主要有代理緩存、反向代理緩存、 CDN 緩存和對象緩存幾種。緩存知識圖譜如下圖所示。
不是所有的數據都適合使用緩存,使用緩存的時候需要注意以下幾點。
數據頻繁修改,這類數據使用緩存效果比較差。
數據沒有熱點,這類數據緩存的命中率比較差。
數據不一致,因為緩存的數據和數據庫的數據是不同步的,可能存在數據不一致的情況,如果業務場景對數據一致性要求非常高,這個時候使用緩存也要注意。
緩存雪崩,當緩存崩潰的時候,可能會導致整個系統的崩潰,這也是使用緩存中要注意的一個事項。
在架構中使用最多的,也是關注最多的是分布式緩存。分布式緩存最重要的幾個技術點是:分布式對象緩存的架構、分布式對象緩存的訪問模型,以及分布式緩存中一個重要的算法——一致性哈希算法。
緩存的特點
緩存的主要特點:
技術簡單
性能提升顯著
應用場景多
緩存可以被很容易地添加到現有的應用中,不需要復雜的架構技術。在現有的系統中使用緩存,該系統所受到的影響和要做出的調整是非常小的,但是使用緩存以后性能提升卻非常明顯。因此,使用緩存的場景非常多。不僅在系統架構中,在計算機的整個體系結構中緩存幾乎是無處不在的。
?
比如,CPU 中就有緩存,在 CPU 固件里就有 cache,當 CPU 進行計算的時候,它并不總是每次都去內存中讀取數據,而是預加載一部分指令和數據到 cache 里面,也就是 CPU 的緩存里面,CPU 核心計算取的數據其實大多數是 CPU 緩存中的數據。
?
再比如,操作系統的文件緩存。操作系統對磁盤進行操作的時候,它也會對數據進行緩存,以加快操作系統訪問磁盤文件數據的速度。
?
還有就是數據庫的查詢緩存,數據庫本身也會對一些數據表進行緩存。比如對索引的結構 B+ 樹進行緩存,對一些熱點的數據記錄也要進行緩存,以加快應用程序的訪問速度。
?
在外部應用系統中,比較常用的有 DNS 客戶端緩存、HTTP 瀏覽器緩存、HTTP 代理和反向代理緩存、CDN 緩存,以及各種類型的對象緩存,對象緩存常用的比如 Redis、Memcached 等等。
緩存提高性能的優勢
緩存是架構性能優化的最重要的手段,使用緩存來提升系統性能主要有三方面優勢。
第一個方面是緩存的數據來自于內存,訪問速度更快。我們知道數據從內存中讀取要比磁盤上讀取速度會更快,所以使用緩存從內存中讀取數據會使系統獲得更快的響應性能,系統的訪問速度會更快,處理速度也會更快。
第二個方面是緩存中存儲的數據形態通常是最終的結果形態,減少資源消耗。比如說,我們緩存一個網頁、一個對象,這些數據通常是我們計算過的結果。從緩存中讀取數據跟從磁盤中或者數據庫中直接讀取數據不同,從數據庫中讀取的數據要進行加工處理,生成我們最終的結果,而從緩存中讀取的數據通常都是直接的最終結果。因此,使用緩存中的數據可以減少 CPU 的資源消耗,不需要進行中間的計算,可以進一步提高響應的特性。
第三個方面是使用緩存可以降低數據庫磁盤或者網絡的負載壓力。不需要從外部的 IO 設備中去讀取數據,這些數據直接從本地緩存或內存中讀取,減少 IO 設備的訪問壓力。我們知道 IO 設備是最容易出現瓶頸的地方,減少這些設備的訪問壓力、負載壓力,可以更好地提升整個系統的處理能力。
緩存數據存儲(Hash 表)
緩存是存儲在內存中的,那么如何從內存中快速獲取一個數據呢?
?
緩存使用的數據結構主要是哈希(Hash)表。我們看一下哈希表實現的機制。哈希表最終的存儲形式通常是一個順序表,也就是一個數組結構。數組結構的特點是在內存中連續存儲分配。那么,當我們要在哈希表中存儲一個數據的時候,哈希表通常是以 key、value 這樣的數據結構進行存儲的。當我們把一個 key、value 數據結構存儲在一個哈希表中的時候,主要的存儲過程大致如下圖所示。? ? ? ?
首先,我們拿到 key、value 數據結構,在上圖的例子中,key 是字符串 abc,value 是字符串 hello,我們先計算 key 的哈希值,比如字符串 abc 的 hashcode 算出來是 101 這樣一個整型值。往下,計算哈希值 101 對應的 hash 表索引就要對 8 取模。此處 8 指什么?哈希表真正的物理存儲是一個數組,我們建的哈希表長度是 8,如上圖所示。101 對 8 取模余 5,這個 5 就是數組下標的索引值,我們就可以把 abc hello 這樣一個 key、value 值存儲在下標為 5 的數組記錄中。這一步是最關鍵的,通常我們所謂的哈希算法也就是指這一步,即如何把一個哈希值轉換成在數組中對應的位置。這個例子我們使用的是余數哈希,實踐中最常用的也是余數哈希。
?
將來,當我們要進行數據讀取的時候,只要給定 key abc,還是用這樣一個算法過程,先求取它的 hash code 101,然后再對 8 取模。因為數組的長度不變,對 8 取模以后依然是余 5,那么我們到數字下標中去找 5 的這個位置,就可以找到前面存儲進去的 abc 對應的 value 值。
?
通過哈希表可以使整個數據存儲或檢索效率時間復雜都是 O(1)。所以即使存儲非常大的幾百萬上千萬的數據量,通過哈希表也可以非常快地進行數據的查找和讀寫。通過這種手段緩存可以獲得較快的讀寫訪問特性,比數據庫中的讀寫速度要快得多。
緩存的關鍵指標——命中率
影響緩存特性的一個關鍵指標是緩存的命中率。緩存的主要特點是一次寫入多次讀出,通過這種手段減少對數據庫的使用,盡快從緩存中讀取數據,提高性能。所以緩存是否有效,主要就是看它一次寫進去的緩存能不能夠多次去讀出來響應業務的請求,這個判斷指標就叫作緩存的命中率。
?
緩存命中率怎么算呢?查詢得到正確緩存結果除以總的查詢次數,得到的比值就是緩存命中率,比如說十次查詢九次都能夠得到緩存的正確結果,命中率就是 90%。
?
影響緩存命中率的主要因素有三個,分別是:
緩存鍵集合大小
內存空間大小
緩存的壽命
緩存鍵集合大小
緩存中的每個對象都是通過緩存鍵進行識別的。剛才 abc hello 這個例子里 abc 就是一個緩存的鍵,鍵是緩存中唯一的識別符,定位一個對象的唯一方式就是對緩存鍵進行精確的匹配。
?
比如說我們想緩存每個商品的在線商品信息,就需要使用商品 ID 作為緩存鍵。換句話說,緩存鍵空間是你的應用能夠生成的所有鍵的數量。從統計數字上看,應用生成的唯一鍵越多,重用的機會越小。比如說根據 IP 地址緩存天氣數據,可能需要 40 多億個鍵。但是如果基于國家緩存天氣數據,那么只需要幾百個緩存鍵就夠了,全世界也不過就幾百個國家。
?
所以要盡可能減少緩存鍵的數量,鍵的數量越少,緩存的效率越高。設計緩存的時候要關注緩存鍵是如何進行設計的,它的整個的集合范圍,限定在一個既能夠高效使用,又可以減少它的數量,這個時候緩存的性能是最好的。
緩存內存空間大小
緩存可以使用的內存空間決定了緩存對象平均大小和緩存對象的數量。因為緩存通常是存儲在內存中的,緩存對象可用的內存空間相對來說比較昂貴,而且受到嚴格限制。
?
如果想緩存更多的對象,就需要先刪除老的對象,再添加新的對象。而這些老的對象被刪除掉,就會影響到緩存的命中率。所以物理上緩存的空間越大,緩存的對象越多,緩存的命中率也就越高。
緩存對象生存時間(緩存壽命)
緩存對象的生存時間稱為 TTL。對象緩存的時間越長,被重用的可能性就越高。使緩存失效的方法有兩種:一種是超時失效;一種是清除失效,也就是實時清除。如下圖所示。
所謂的超時失效是在構建緩存,即寫緩存的時候,每個緩存對象都設置一個超時時間,在超時之前訪問緩存就會返回緩存的數據,而一旦超時,緩存就失效了,這時候再訪問緩存,就會返回空。
?
而實時清除是說,當有緩存對象更新的時候,直接通知緩存將已經被更新了的數據進行清除。清除了以后,應用程序下一次訪問這個緩存對象鍵的時候,就不得不到數據庫中去查找讀取,這個時候就會得到最新的數據,因為更新總是更新在數據庫里的。
?
還有一種,雖然時間上還沒有失效但是新的對象要寫入緩存,而內存空間不夠了,這個時候就需要將一些老的緩存對象清理掉,為新的緩存對象騰出空間。
?
內存空間清除主要使用的算法是 LRU 算法,LRU 算法就是最近最久未用算法,也就是說清除那些最近最久沒有被訪問過的對象。這個算法使用鏈表結構實現的,所有的緩存對象都放在同一個鏈表上。當一個對象被訪問的時候,就把這個對象移到整個鏈表的頭部。當需要通過 LRU 算法清除那些最近最久未用對象的時候,只需要從隊列的尾部進行查找,越是在隊列尾部的,越是最近最久沒有被訪問過的,也就是優先清除的,騰出的內存空間讓新對象加入進來。
緩存的主要類型
代理緩存
代理緩存是在應用程序—端的代理,緩存在客戶端—端的,代理客戶端訪問互聯網。它的主要作用是互聯網訪問代理。但是同時因為他代理了所有的客戶端 HTTP 請求,所以它可以進行頁面緩存,如果有一些其他的客戶端已經訪問過這個網頁,那么當新的客戶端連接的時候,就可以通過代理緩存中的數據直接返回,避免對數據中心的訪問。
代理緩存是存在客戶端一端的緩存,我們無法進行管理。所以代理緩存雖然存在,但是通常不作為我們系統架構中的一部分,我們能夠管理的是反向代理緩存。
反向代理緩存
代理緩存是代理用戶上網的,而反向代理則是代理數據中心輸出的,是反向代理的。所以反向代理緩存是存在于系統數據中心里的,它是數據中心的統一入口,代理整個數據中心其他服務器的應用處理。
?
用戶通過互聯網連接到數據中心的時候,連接的通常是一個反向代理服務器,反向代理服務器根據用戶的請求,在本地的反向代理緩存中查找是否有用戶請求的數據,如果有就直接返回這個數據,如果沒有再把這個請求向下繼續轉發,請求后面的應用服務器去處理生成數據。
?
反向代理緩存可以多層反向代理緩存的形式出現。因為我們的應用服務器也是經過分層的,在處理的前端通常是一個前端服務器,后面有 Web 服務器,之后有應用服務器,再后還有其他的各類服務器。在這樣一個分層的服務器結構里,我們可以對每一層的服務器都進行反向代理緩存。
?
如下圖所示,前端 Web 服務器和 Web 服務器分為兩層,用戶請求接入的時候,先接入前端 Web 服務器,其上可以加一層反向代理服務器來代理前端 Web 服務器的 HTTP 請求。如果用戶請求的數據已經包含在這個反向代理服務器中,就可以直接返回;如果沒有,就再把 HTTP 請求提交給前端 Web 服務器,前端 Web 服務器會把請求發給后面的 Web 服務器。在 Web 服務器和前端 Web 服務器之間還可以再加一層反向代理服務器。如果前端 Web 服務器的請求在這一層的反向代理服務器中存在,那么這一層反向代理服務器可以直接將數據返還;如果不存在,再將請求下發給 Web 服務器。
通過這樣的方式,極大地減少了前端 Web 服務器或者是 Web 服務器的訪問壓力,同時提高了系統的響應性能。
內容分發網絡 CDN 緩存
所謂的 CDN 是指在用戶請求的前端(盡量前的前端)為用戶提供數據服務。CDN 并不存在于我們的數據中心,也不存在于用戶的訪問系統一端,它介于兩者之間,作為網絡服務商的緩存服務。用戶進行互聯網訪問的時候,需要通過互聯網網絡服務商提供的網絡鏈接才能夠連接到數據中心,那么網絡服務商就可以在自己提供的網絡服務的機房里進行一次緩存操作,提供一次緩存服務。如下圖所示。
客戶端第一次訪問 example.com 的時候,訪問數據中心,數據中心返回 HTML 頁面以后,客戶端解析 HTML,HTML 里面還各種 js 文件、css 文件、圖片等,這些靜態資源訪問的就是 CDN 服務器。CDN 服務器檢查自己是否有需要的靜態資源,如果有,就立即返回給客戶端;如果沒有,就自己訪問數據中心,獲得需要的靜態資源后,緩存在 CDN 服務器上后,再返回客戶端。
?
所以 CDN 緩存也叫作網絡訪問的“第一跳”,用戶請求先到達的是互聯網網絡服務商的機房。在機房里面部署 CDN 服務器,提供緩存服務。如果 CDN 中存在用戶請求的 Web 響應內容,那么就可以直接通過 CDN 進行返回;如果 CDN 中不存在,那么 CDN 會把這個請求通過后面的網絡連接,把它發到系統的數據中心去。數據中心返回的結果依然是先通過 CDN 服務器,CDN 服務器就可以把數據緩存在自己的本地,供后面的用戶請求操作響應。
精選評論
**璋:
老師好,初入架構學習,想請問一下
1、CDN服務是運營商機房的,那進行緩存訪問這些操作是需要跟運營商支付費用的嗎?想去訪問CDN服務器是怎么操作的能簡要介紹一下嗎2、反向代理服務器是不是需要部署在不同的區域? 比如公司總服務器在上海,但新疆用戶多,訪問的時候為了提高速度,是不是就需要在新疆部署一臺反向代理服務器?感謝🙏??? 講師回復:
??? CDN有兩種,一種是自己的服務器部署在運營商的機房,CDN服務管理自己做,這臺服務器想怎么操作怎么操作,一種是CDN云服務,購買CDN容量后,由CDN服務商提供CDN服務,自己是完全不能控制。
反向代理是部署在數據中心服務器前面的一個代理,不能部署在不同區域,除非你在那個區域建了數據中心。
總結
以上是生活随笔為你收集整理的架构师的 36 项修炼第02讲:架构核心技术之分布式缓存(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FlinkX脏值处理
- 下一篇: MAX31856中文文档