淺析互聯(lián)網(wǎng)中的緩存機(jī)制
![](http://image.woshipm.com/wp-files/img/68.jpg)
緩存,在互聯(lián)網(wǎng)產(chǎn)品中可以簡單理解為:第一次請求數(shù)據(jù)放到存儲器中,下次顯示該頁面先把上次保存的數(shù)據(jù)顯示出來,同時去請求數(shù)據(jù),請求完成刷新顯示新數(shù)據(jù),并將其再緩存起來。
當(dāng)今互聯(lián)網(wǎng)應(yīng)用(網(wǎng)站或App)的整體實現(xiàn)流程是:用戶的請求從界面(瀏覽器或App界面)到網(wǎng)絡(luò)傳送、應(yīng)用服務(wù)再到存儲(數(shù)據(jù)庫或文件系統(tǒng)),然后返回到界面呈現(xiàn)內(nèi)容。
隨著內(nèi)容信息越來越復(fù)雜,用戶數(shù)和訪問量越來越大,我們的應(yīng)用需要支撐更多的并發(fā)量,同時應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器所做的計算也越來越多。但是往往我們的應(yīng)用服務(wù)器資源是有限的,數(shù)據(jù)庫每秒能接受的請求次數(shù)也是有限的(文件的讀寫也是有限的),如何能夠有效利用有限的資源來提供盡可能大的吞吐量?一個有效的辦法就是引入緩存,每個環(huán)節(jié)中請求可以從緩存中直接獲取目標(biāo)數(shù)據(jù)并返回,從而減少計算量,有效提升響應(yīng)速度,讓有限的資源服務(wù)更多的用戶。
計算機(jī)緩存
計算機(jī)的緩存往往使用的是RAM(斷電就掉的非永久儲存),所以在用完后還是會把文件送到硬盤等存儲器里永久存儲。計算機(jī)里最大的緩存是內(nèi)存條,最快的是CPU上鑲嵌的L1和L2緩存,顯卡的顯存是給顯卡運(yùn)算芯片用的緩存,硬盤上也有16M或者32M的緩存。
其工作原理是當(dāng)CPU要讀取數(shù)據(jù)時,首先從CPU緩存中查找,找到就立即讀取并送給CPU處理;如果沒有找到,就從速率相對較慢的內(nèi)存中讀取并送給CPU處理,同時把這個數(shù)據(jù)所在的數(shù)據(jù)區(qū)塊調(diào)入緩存中,可以使以后對整塊數(shù)據(jù)的讀取都從緩存中進(jìn)行,不必再調(diào)用內(nèi)存。這樣的讀取機(jī)制CPU讀取緩存的命中率非常高,也就是說CPU下一次要讀取的數(shù)據(jù)90%都在CPU緩存中,只有大約10%需要從內(nèi)存讀取。這大大節(jié)省了CPU直接讀取內(nèi)存的時間,也使CPU讀取數(shù)據(jù)時基本無需等待。
WEB瀏覽器緩存
下面我們進(jìn)入正題。
瀏覽器會緩存它瀏覽過的「資源」(包括網(wǎng)頁,圖片等),如果資源在保質(zhì)期內(nèi),那下次同樣的請求直接用緩存。過期之后,會帶上資源上次的修改時間,由服務(wù)器來判斷是否失效,失效的話就會給瀏覽器返回新的數(shù)據(jù)并繼續(xù)緩存下來。
瀏覽器的緩存,存在用戶電腦的硬盤上,用戶每次使用瀏覽器讀取緩存時先將硬盤上的緩存數(shù)據(jù)加載到內(nèi)存中,再讀取給瀏覽器。
瀏覽器端緩存的規(guī)則主要在HTTP協(xié)議頭和HTML的meta標(biāo)簽中定義。他們分別從新鮮度和校驗值兩個維度來規(guī)定瀏覽器是直接使用緩存中的數(shù)據(jù),還是需要去源服務(wù)器獲取更新的版本。
新鮮度(過期機(jī)制):緩存數(shù)據(jù)保質(zhì)期。緩存數(shù)據(jù)必須滿足以下條件,瀏覽器會認(rèn)為它是有效的,足夠新的:
- 含有完整的過期時間控制頭信息(HTTP協(xié)議報文頭),并且仍在有效期內(nèi)
- 瀏覽器已經(jīng)使用過這個緩存數(shù)據(jù),并且在上一次會話中(也就是用戶上一次訪問該數(shù)據(jù)時)已經(jīng)檢查過其新鮮度
滿足以上兩個情況的一種,瀏覽器會直接從緩存中獲取緩存數(shù)據(jù)并渲染給瀏覽器。
校驗值(驗證機(jī)制):服務(wù)器返回數(shù)據(jù)的時候有時在頭信息中帶上這個資源的實體標(biāo)簽,它可以用來作為瀏覽器再次請求過程的校驗標(biāo)識。如過發(fā)現(xiàn)校驗標(biāo)識不匹配,說明數(shù)據(jù)已經(jīng)被修改或過期,瀏覽器需要重新獲取數(shù)據(jù)內(nèi)容。
HTTP緩存機(jī)制
還記得HTTP協(xié)議嗎?在這篇文章中有對HTTP協(xié)議的簡單介紹:淺析前后端數(shù)據(jù)交互
當(dāng)用戶通過瀏覽器發(fā)起一個數(shù)據(jù)請求的時候,瀏覽器會通過以下幾步來獲取數(shù)據(jù):
- 本地緩存階段:先在本地查找該數(shù)據(jù),如果有發(fā)現(xiàn)該數(shù)據(jù),而且該數(shù)據(jù)還沒有過期,就使用此數(shù)據(jù),不會發(fā)送http請求到服務(wù)器
- 協(xié)商緩存階段:如果在本地緩存找到對應(yīng)的數(shù)據(jù),但是不知道該數(shù)據(jù)是否過期,則發(fā)一個HTTP請求到服務(wù)器,然后服務(wù)器判斷這個請求,如果請求的數(shù)據(jù)在服務(wù)器上沒有改動過或過期,則返回304狀態(tài)碼(可以理解為服務(wù)器給瀏覽器的暗號),讓瀏覽器在本地找到該數(shù)據(jù)
- 緩存失敗階段:當(dāng)服務(wù)器發(fā)現(xiàn)請求的資源已經(jīng)修改過,或者這是一個新的請求,服務(wù)器則返回該數(shù)據(jù),并且返回200狀態(tài)碼, 此過程的前提是指找到該數(shù)據(jù),如果服務(wù)器上沒有數(shù)據(jù),則返回404(這個大家多見過吧,就是平時見到404頁面時的狀態(tài)碼)
瀏覽器中的操作對緩存的影響
- 強(qiáng)制刷新:當(dāng)按下ctrl+F5來刷新頁面的時候,瀏覽器將繞過各種緩存(本地緩存和協(xié)商緩存), 直接讓服務(wù)器返回最新數(shù)據(jù)
- 普通刷新:當(dāng)按下F5或者點(diǎn)擊刷新按鈕來刷新頁面的時候,瀏覽器將繞過本地緩存發(fā)送請求給服務(wù)器,此時協(xié)商緩存是有效的
- 回車或跳轉(zhuǎn):當(dāng)在地址欄上輸入回車或者按下跳轉(zhuǎn)按鈕的時候,所有緩存都生效
瀏覽器緩存機(jī)制
安卓、iOS緩存機(jī)制
APP上的緩存機(jī)制和瀏覽器緩存的原理類似,APP與服務(wù)器交互的協(xié)議同樣是大多基于HTTP(S)。
先普及下基礎(chǔ)知識:手機(jī)內(nèi)存包括運(yùn)行內(nèi)存和內(nèi)部存儲。運(yùn)行內(nèi)存是用來運(yùn)行程序的,不能用來永久存儲數(shù)據(jù),手機(jī)一旦關(guān)機(jī)或殺死進(jìn)程,在內(nèi)存中的所有數(shù)據(jù)都將會丟失。內(nèi)部存儲相當(dāng)于計算機(jī)中的硬盤的角色,用于存儲操作系統(tǒng)和應(yīng)用程序的存儲介質(zhì)。
iOS的本地緩存數(shù)據(jù)存在磁盤存儲(內(nèi)部存儲)中,由于Android手機(jī)通常將內(nèi)部存儲器固定在芯上,所以一般無法更換內(nèi)部存儲器的。 為了增強(qiáng)Android手機(jī)的存儲能力,很多Android手機(jī)都支持?jǐn)U展的SD卡(相當(dāng)于計算機(jī)的U盤或者移動硬盤)功能。所以,Android手機(jī)存儲緩存是可以選擇數(shù)據(jù)存儲位置的。
APP端存儲數(shù)據(jù)的時候,會存儲很多字段內(nèi)容,一般情況下后臺會給每條數(shù)據(jù)設(shè)定一個獨(dú)立的id值,那么前端在請求數(shù)據(jù)的可以先查詢本地緩存的數(shù)據(jù)中,最新的一條數(shù)據(jù)的id值,通過網(wǎng)絡(luò)請求,把這個id值發(fā)給服務(wù)端,服務(wù)端會根據(jù)這個id在后臺服務(wù)器中查詢是否有比這個id值更大(更新)的數(shù)據(jù)存在,如果有就把新的數(shù)據(jù)返回給前端APP。
數(shù)據(jù)庫緩存
數(shù)據(jù)庫的緩存機(jī)制分為兩個層面。
- 由數(shù)據(jù)庫提供,可以對數(shù)據(jù)表建立的高速緩存。數(shù)據(jù)庫的數(shù)據(jù)臨時保存在一個位置上,再次同樣的請求直接把這個數(shù)據(jù)返回去,而不需要再次去查詢各種表取數(shù)據(jù)了,減少了查數(shù)據(jù)庫的時間,提升效率。并不是所有的歷史記錄都緩存起來,要有策略,比如只緩存兩個月的數(shù)據(jù),并且兩個月之前有請求過之后不再請求該數(shù)據(jù)的時候就會回收,就是把這條記錄抹掉,就近多次請求的才會保存。時間過長、使用率不高的優(yōu)先清除,要不然緩存太多就失去了緩存的本質(zhì)和意義。
- 在數(shù)據(jù)庫中,數(shù)據(jù)都是存放在磁盤中的。雖然數(shù)據(jù)庫層做了對應(yīng)的緩存,但這種數(shù)據(jù)庫層次的緩存一般針對的是查詢內(nèi)容,一般只有表中數(shù)據(jù)沒有變更的時候,數(shù)據(jù)庫對應(yīng)的緩存才發(fā)揮了作用。有時并不能減少業(yè)務(wù)系統(tǒng)對數(shù)據(jù)庫產(chǎn)生的增、刪、查、改產(chǎn)生的龐大壓力。此時,一般的做法是在數(shù)據(jù)庫與業(yè)務(wù)服務(wù)器之間增加一個緩存服務(wù)器,比如我們熟悉的redis。客戶端第一次請求的數(shù)據(jù)從數(shù)據(jù)庫拿出后就放到了redis中,數(shù)據(jù)不過期或不更改的前提下,下一次的請求都從redis中直接拿數(shù)據(jù),這樣做極大的緩解了數(shù)據(jù)庫的壓力。
服務(wù)器緩存
業(yè)務(wù)服務(wù)器緩存
業(yè)務(wù)服務(wù)器緩存是將動態(tài)頁面直接生成靜態(tài)的頁面放在服務(wù)器上的硬盤里,用戶調(diào)取相同頁面時,靜態(tài)頁面將直接下載到客戶端,不再需要通過程序的運(yùn)行和數(shù)據(jù)庫的訪問,大大節(jié)約了服務(wù)器的負(fù)載。
每次訪問頁面時,會檢測相應(yīng)的緩存頁面是否存在,若不存在,則連接數(shù)據(jù)庫得到數(shù)據(jù)渲染頁面并生成緩存頁面文件,這樣下次訪問的頁面文件就能發(fā)揮作用了。
舉一個小例子:
用戶A訪問a頁面,服務(wù)器解析a頁面返回給用戶A,同時在服務(wù)器內(nèi)存上做一個映射,把a(bǔ)頁面緩存在服務(wù)器的硬盤上。用戶B訪問a頁面,服務(wù)器直接根據(jù)內(nèi)存上的映射找到相應(yīng)的頁面緩存,直接返回給用戶B。這樣做減少了服務(wù)器對同以頁面的重復(fù)解析。
代理服務(wù)器緩存
代理服務(wù)器是客戶端和業(yè)務(wù)服務(wù)器之間的中間服務(wù)器,客戶端先向這個中間服務(wù)器發(fā)起請求,經(jīng)過處理后,再將請求轉(zhuǎn)發(fā)到業(yè)務(wù)服務(wù)器。代理服務(wù)器緩存的運(yùn)作原理跟瀏覽器的運(yùn)作原理差不多,只是規(guī)模更大。可以把它理解為一個共享緩存,不只為一個用戶服務(wù),一般為大量用戶提供服務(wù),因此在減少相應(yīng)時間和帶寬使用方面很有效,同一個緩存數(shù)據(jù)會被重復(fù)使用多次。
以上,就是關(guān)于緩存機(jī)制的簡單總結(jié)。產(chǎn)品汪們,再涉及項目中的緩存機(jī)制時,就不怕被程序猿們懟了!
作者:流年,互聯(lián)網(wǎng)產(chǎn)品設(shè)計師,4年互聯(lián)網(wǎng)產(chǎn)品設(shè)計經(jīng)驗。
本文由 @流年 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。
題圖由作者提供
講的非常好,很有用
太棒了,十分清晰易懂
太棒了!獲益匪淺!666!
講的不錯
nice!講的清晰,易懂!
贊
get it!thank you