主頁 > 軟體設計 > 大型網站多級快取的分層架構

大型網站多級快取的分層架構

2020-09-15 07:52:03 軟體設計

在互聯網高速發展的今天,快取技術被廣泛地應用,無論業內還是業外,只要是提到性能問題,大家都會脫口而出“用快取解決”,

這種說法帶有片面性,甚至是一知半解,但是作為專業人士的我們,需要對快取有更深、更廣的了解,

快取技術存在于應用場景的方方面面,從瀏覽器請求,到反向代理服務器,從行程內快取到分布式快取,其中快取策略,演算法也是層出不窮,今天就帶大家走進快取,

正文

快取對于每個開發者來說是相當熟悉了,為了提高程式的性能我們會去加快取,但是在什么地方加快取,如何加快取呢?

假設一個網站,需要提高性能,快取可以放在瀏覽器,可以放在反向代理服務器,還可以放在應用程式行程內,同時可以放在分布式快取系統中,

 

 

從用戶請求資料到資料回傳,資料經過了瀏覽器,CDN,代理服務器,應用服務器,以及資料庫各個環節,每個環節都可以運用快取技術,

從瀏覽器/客戶端開始請求資料,通過 HTTP 配合 CDN 獲取資料的變更情況,到達代理服務器(Nginx)可以通過反向代理獲取靜態資源,

再往下來到應用服務器可以通過行程內(堆內)快取,分布式快取等遞進的方式獲取資料,如果以上所有快取都沒有命中資料,才會回源到資料庫,

快取的請求順序是:用戶請求 → HTTP 快取 → CDN 快取 → 代理服務器快取 → 行程內快取 → 分布式快取 → 資料庫,

看來在技術的架構每個環節都可以加入快取,看看每個環節是如何應用快取技術的,

1. HTTP快取

當用戶通過瀏覽器請求服務器的時候,會發起 HTTP 請求,如果對每次 HTTP 請求進行快取,那么可以減少應用服務器的壓力,

當第一次請求的時候,瀏覽器本地快取庫沒有快取資料,會從服務器取資料,并且放到瀏覽器的快取庫中,下次再進行請求的時候會根據快取的策略來讀取本地或者服務的資訊,

 

 

一般資訊的傳遞通過 HTTP 請求頭 Header 來傳遞,目前比較常見的快取方式有兩種,分別是:

  • 強制快取

  • 對比快取

1.1. 強制快取

當瀏覽器本地快取庫保存了快取資訊,在快取資料未失效的情況下,可以直接使用快取資料,否則就需要重新獲取資料,

這種快取機制看上去比較直接,那么如何判斷快取資料是否失效呢?這里需要關注 HTTP Header 中的兩個欄位 Expires 和 Cache-Control,

Expires 為服務端回傳的過期時間,客戶端第一次請求服務器,服務器會回傳資源的過期時間,如果客戶端再次請求服務器,會把請求時間與過期時間做比較,

如果請求時間小于過期時間,那么說明快取沒有過期,則可以直接使用本地快取庫的資訊,

反之,說明資料已經過期,必須從服務器重新獲取資訊,獲取完畢又會更新最新的過期時間,

這種方式在 HTTP 1.0 用的比較多,到了 HTTP 1.1 會使用 Cache-Control 替代,

Cache-Control 中有個 max-age 屬性,單位是秒,用來表示快取內容在客戶端的過期時間,

例如:max-age 是 60 秒,當前快取沒有資料,客戶端第一次請求完后,將資料放入本地快取,

那么在 60 秒以內客戶端再發送請求,都不會請求應用服務器,而是從本地快取中直接回傳資料,如果兩次請求相隔時間超過了 60 秒,那么就需要通過服務器獲取資料,

1.2. 對比快取

需要對比前后兩次的快取標志來判斷是否使用快取,瀏覽器第一次請求時,服務器會將快取標識與資料一起回傳,瀏覽器將二者備份至本地快取庫中,瀏覽器再次請求時,將備份的快取標識發送給服務器,

服務器根據快取標識進行判斷,如果判斷資料沒有發生變化,把判斷成功的 304 狀態碼發給瀏覽器,

這時瀏覽器就可以使用快取的資料來,服務器回傳的就只是 Header,不包含 Body,

下面介紹兩種標識規則:

1.2.1. Last-Modified/If-Modified-Since 規則

在客戶端第一次請求的時候,服務器會回傳資源最后的修改時間,記作 Last-Modified,客戶端將這個欄位連同資源快取起來,

Last-Modified 被保存以后,在下次請求時會以 Last-Modified-Since 欄位被發送,

 

當客戶端再次請求服務器時,會把 Last-Modified 連同請求的資源一起發給服務器,這時 Last-Modified 會被命名為 If-Modified-Since,存放的內容都是一樣的,

服務器收到請求,會把 If-Modified-Since 欄位與服務器上保存的 Last-Modified 欄位作比較:

  • 若服務器上的 Last-Modified 最后修改時間大于請求的 If-Modified-Since,說明資源被改動過,就會把資源(包括 Header+Body)重新回傳給瀏覽器,同時回傳狀態碼 200,

  • 若資源的最后修改時間小于或等于 If-Modified-Since,說明資源沒有改動過,只會回傳 Header,并且回傳狀態碼 304,瀏覽器接受到這個訊息就可以使用本地快取庫的資料,

注意:Last-Modified 和 If-Modified-Since 指的是同一個值,只是在客戶端和服務器端的叫法不同,

1.2.2. ETag / If-None-Match 規則

客戶端第一次請求的時候,服務器會給每個資源生成一個 ETag 標記,這個 ETag 是根據每個資源生成的唯一 Hash 串,資源如何發生變化 ETag 隨之更改,之后將這個 ETag 回傳給客戶端,客戶端把請求的資源和 ETag 都快取到本地,

ETag 被保存以后,在下次請求時會當作 If-None-Match 欄位被發送出去,

 

在瀏覽器第二次請求服務器相同資源時,會把資源對應的 ETag 一并發送給服務器,在請求時 ETag 轉化成 If-None-Match,但其內容不變,

服務器收到請求后,會把 If-None-Match 與服務器上資源的 ETag 進行比較:

  • 如果不一致,說明資源被改動過,則回傳資源(Header+Body),回傳狀態碼 200,

  • 如果一致,說明資源沒有被改過,則回傳 Header,回傳狀態碼 304,瀏覽器接受到這個訊息就可以使用本地快取庫的資料,

注意:ETag 和 If-None-Match 指的是同一個值,只是在客戶端和服務器端的叫法不同,

2. CDN 快取

HTTP 快取主要是對靜態資料進行快取,把從服務器拿到的資料快取到客戶端/瀏覽器,

如果在客戶端和服務器之間再加上一層 CDN,可以讓 CDN 為應用服務器提供快取,如果在 CDN 上快取,就不用再請求應用服務器了,并且 HTTP 快取提到的兩種策略同樣可以在 CDN 服務器執行,

CDN 的全稱是 Content Delivery Network,即內容分發網路,

讓我們來看看它是如何作業的吧:

  • 客戶端發送 URL 給 DNS 服務器,

  • DNS 通過域名決議,把請求指向 CDN 網路中的 DNS 負載均衡器,

  • DNS 負載均衡器將最近 CDN 節點的 IP 告訴 DNS,DNS 告之客戶端最新 CDN 節點的 IP,

  • 客戶端請求最近的 CDN 節點,

  • CDN 節點從應用服務器獲取資源回傳給客戶端,同時將靜態資訊快取,注意:客戶端下次互動的物件就是 CDN 快取了,CDN 可以和應用服務器同步快取資訊,

CDN 接受客戶端的請求,它就是離客戶端最近的服務器,它后面會鏈接多臺服務器,起到了快取和負載均衡的作用,

3. 負載均衡快取

說完客戶端(HTTP)快取和 CDN 快取,我們離應用服務越來越近了,在到達應用服務之前,請求還要經過負載均衡器,

雖說它的主要作業是對應用服務器進行負載均衡,但是它也可以作快取,可以把一些修改頻率不高的資料快取在這里,例如:用戶資訊,配置資訊,通過服務定期重繪這個快取就行了,

 

 

以 Nginx 為例,我們看看它是如何作業的:

  • 用戶請求在達到應用服務器之前,會先訪問 Nginx 負載均衡器,如果發現有快取資訊,直接回傳給用戶,

  • 如果沒有發現快取資訊,Nginx 回源到應用服務器獲取資訊,

  • 另外,有一個快取更新服務,定期把應用服務器中相對穩定的資訊更新到 Nginx 本地快取中,

4. 行程內快取

通過了客戶端,CDN,負載均衡器,我們終于來到了應用服務器,應用服務器上部署著一個個應用,這些應用以行程的方式運行著,那么在行程中的快取是怎樣的呢?

行程內快取又叫托管堆快取,以APC為例,同時會受到托管堆回收演算法的影響,

由于其運行在記憶體中,對資料的回應速度很快,通常我們會把熱點資料放在這里,

在行程內快取沒有命中的時候,我們會去搜索行程外的快取或者分布式快取,這種快取的好處是沒有序列化和反序列化,是最快的快取,缺點是快取的空間不能太大,對垃圾回收器的性能有影響,

這里我們需要關注幾個快取的回收策略,具體的實作架構的回收策略會有所不同,但大致的思路都是一致的:

  • FIFO(First In First Out):先進先出演算法,最先放入快取的資料最先被移除,

  • LRU(Least Recently Used):最近最少使用演算法,把最久沒有使用過的資料移除快取,

  • LFU(Least Frequently Used):最不常用演算法,在一段時間內使用頻率最小的資料被移除快取,

在分布式架構的今天,多應用中如果采用行程內快取會存在資料一致性的問題,

這里推薦兩個方案:

  • 訊息佇列修改方案

  • Timer 修改方案

4.1. 訊息佇列修改方案

應用在修改完自身快取資料和資料庫資料之后,給訊息佇列發送資料變化通知,其他應用訂閱了訊息通知,在收到通知的時候修改快取資料,

 

圖片

 

4.2. Timer 修改方案

為了避免耦合,降低復雜性,對“實時一致性”不敏感的情況下,每個應用都會啟動一個 Timer,定時從資料庫拉取最新的資料,更新快取,

不過在有的應用更新資料庫后,其他節點通過 Timer 獲取資料之間,會讀到臟資料,這里需要控制好 Timer 的頻率,以及應用與對實時性要求不高的場景,

 

圖片

 

行程內快取有哪些使用場景呢?

  • 場景一:只讀資料,可以考慮在行程啟動時加載到記憶體,當然,把資料加載到類似 Redis 這樣的行程外快取服務也能解決這類問題,

  • 場景二:高并發,可以考慮使用行程內快取,例如:秒殺,

5. 分布式快取

說完行程內快取,自然就過度到行程外快取了,與行程內快取不同,行程外快取在應用運行的行程之外,它擁有更大的快取容量,并且可以部署到不同的物理節點,通常會用分布式快取的方式實作,

分布式快取是與應用分離的快取服務,最大的特點是,自身是一個獨立的應用/服務,與本地應用隔離,多個應用可直接共享一個或者多個快取應用/服務,

 

圖片

 

既然是分布式快取,快取的資料會分布到不同的快取節點上,每個快取節點快取的資料大小通常也是有限制的,

資料被快取到不同的節點,為了能方便的訪問這些節點,需要引入快取代理,類似 Twemproxy,他會幫助請求找到對應的快取節點,

同時如果快取節點增加了,這個代理也會只能識別并且把新的快取資料分片到新的節點,做橫向的擴展,

為了提高快取的可用性,會在原有的快取節點上加入 Master/Slave 的設計,當快取資料寫入 Master 節點的時候,會同時同步一份到 Slave 節點,

一旦 Master 節點失效,可以通過代理直接切換到 Slave 節點,這時 Slave 節點就變成了 Master 節點,保證快取的正常作業,

每個快取節點還會提供快取過期的機制,并且會把快取內容定期以快照的方式保存到檔案上,方便快取崩潰之后啟動預熱加載,

5.1. 高性能

當快取做成分布式的時候,資料會根據一定的規律分配到每個快取應用/服務上,

如果我們把這些快取應用/服務叫做快取節點,每個節點一般都可以快取一定容量的資料,例如:Redis 一個節點可以快取 2G 的資料,

如果需要快取的資料量比較大就需要擴展多個快取節點來實作,這么多的快取節點,客戶端的請求不知道訪問哪個節點怎么辦?快取的資料又如何放到這些節點上?

快取代理服務已經幫我們解決這些問題了,例如:Twemproxy 不但可以幫助快取路由,同時可以管理快取節點,

這里有介紹三種快取資料分片的演算法,有了這些演算法快取代理就可以方便的找到分片的資料了,

5.1.1. 哈希演算法

Hash 表是最常見的資料結構,實作方式是,對資料記錄的關鍵值進行 Hash,然后再對需要分片的快取節點個數進行取模得到的余數進行資料分配,

例如:有三條記錄資料分別是 R1,R2,R3,他們的 ID 分別是 01,02,03,假設對這三個記錄的 ID 作為關鍵值進行 Hash 演算法之后的結果依舊是 01,02,03,

我們想把這三條資料放到三個快取節點中,可以把這個結果分別對 3 這個數字取模得到余數,這個余數就是這三條記錄分別放置的快取節點,

 

 

 

Hash 演算法是某種程度上的平均放置,策略比較簡單,如果要增加快取節點,對已經存在的資料會有較大的變動,

5.1.2. 一致性哈希演算法

一致性 Hash 是將資料按照特征值映射到一個首尾相接的 Hash 環上,同時也將快取節點映射到這個環上,

如果要快取資料,通過資料的關鍵值(Key)在環上找到自己存放的位置,這些資料按照自身的 ID 取 Hash 之后得到的值按照順序在環上排列,

 

 

如果這個時候要插入一條新的資料其 ID 是 115,那么就應該插入到如下圖的位置,

 

 

同理如果要增加一個快取節點 N4 150,也可以放到如下圖的位置,

 

 

這種演算法對于增加快取資料,和快取節點的開銷相對比較小,

5.1.3. Range Based 演算法

這種方式是按照關鍵值(例如 ID)將資料劃分成不同的區間,每個快取節點負責一個或者多個區間,跟一致性哈希有點像,

例如:存在三個快取節點分別是 N1,N2,N3,他們用來存放資料的區間分別是,N1(0, 100], N2(100, 200], N3(300, 400],

那么資料根據自己 ID 作為關鍵字做 Hash 以后的結果就會分別對應放到這幾個區域里面了,
 關注公眾號可獲取一線互聯網公司面試題目額

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/44303.html

標籤:架構設計

上一篇:微服務的資料庫設計

下一篇:學習重構(2)-重新組織函式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more