【實踐】你真的認識 Web 快取體系?

天府雲創發表於2017-09-11
前言

很高興認識大家,之前做過很多分享,今天這次終於講到正題了。因為之前一直講自動化運維,其實做這麼多年運維,自動化運維沒幹多少年。這幾年很多公司各方面機器數量多了,規模大了才開始去做自動化運維。

今天的課題是高效能Web架構之快取體系,之所以講這個體系是因為作為一名運維工程師,我們經常會遇到Web站點訪問很慢的情況。要解決這個問題,直接找開發,問題也不一定能解決。因為這個問題不僅僅是開發的問題,

這個問題涉及到瀏覽器從發出請求到響應請求的一系列問題,所有地方都需要一點點摸清楚才能最後找到問題所在。

1、認識Web快取知識體系 1.1從HTTP請求說起

我們從一個Http的請求開始,先介紹下環境,左邊是我們的使用者端瀏覽器,右邊是我們的Web伺服器,當然Web伺服器後面整體架構就不說了。

  • 第一步,當使用者瀏覽器發出一個請求,這個請求會經過網路到達Web伺服器。這句話說明了當一個資料包從使用者端傳送到Web伺服器端,這個時間是時網路延遲時間。

  • 第二步,Web伺服器處理請求,並響應資料。如果是動態請求我需要查快取,查資料庫,最終把請求返回給瀏覽器,這個時間是響應時間。

  • 第三步,響應資料從Web伺服器傳送給使用者端,這又是網路傳輸時間。

  • 第四步,使用者瀏覽器接收資料,本地計算和渲染。這個時間就是計算和渲染的時間,你的JS指令碼不一樣,渲染時間也是不一樣的,但是這個時間是比較小的。

1.2 處理資料的時間去哪了?

Web訪問時間大家看主要花費在哪幾個方面,客戶端請求,從使用者端發到伺服器端,伺服器端響應,伺服器端發回使用者端,還有一個比較大的時間是處理資料的時間。

我們來研究一下時間都去哪兒了,傳送時間+傳輸時間+處理時間=響應時間傳送時間=資料量位元數/頻寬傳輸時間=傳輸距離/傳輸速度,這就是整個資料包的傳輸時間。

目前網路的處理時間很多時候我們不是說不能去優化,至少可以說我們普通的運維和開發在這塊接觸的少一些。現在可能也有很多做網路傳輸優化的產品,這裡我們暫不討論。

1.3 如何縮短處理時間

我們今天討論,如何縮短處理時間。因為返回資料我們可以通過各種各樣方式解決。那麼處理時間如何縮短也有很多方式。比如你去提高伺服器併發,修改架構等等有非常多的處理方式。我們們今天講如何使用快取來減少處理時間這是今天的重點。

就像我說的在網上找不到一個完整的請求從出來一直到最後所經歷的快取,怎麼辦?自己寫一個,我按照一個Http請求從瀏覽器發出一直到最後,把所經歷的快取全部做了一遍。

首先使用者層在瀏覽器輸入一個域名,這個時候第一步不是DNS解析。第一步是瀏覽器DNS快取,比如谷歌、火狐瀏覽器預設的就是60秒。這沒有嚴格意義上的上下級,應用程式DNS快取,作業系統DNS快取,DNS快取伺服器。最後解析出IP地址,然後到瀏覽器快取。

我們會講瀏覽器快取協商的三種辦法。然後請求繼續往下就走到代理層,CDN代理快取。

然後請求會到達Web伺服器,然後到應用層,然後到資料庫,有資料庫快取,然後到系統層面。

最後要訪問硬碟上某一個檔案,有系統層面快取。最後到物理層,要訪問硬碟上的某一個資料,要讀寫某一個blog,這就涉及到物理層。我們僅包括讀快取,沒有包括寫快取。

2、關於Buffer與Cache 2.1什麼是Buffer和Cache?

  • Buffer一般用於寫操作,我們稱之為寫緩衝。為什麼會有Buffer呢?因為不同的計算裝置它的速度不同,比如說CPU能直接往硬碟寫資料嗎?因為硬碟太慢了,所以CPU只能寫在記憶體裡,記憶體再往硬碟寫,我們稱之為快取。

  • Cache一般用於讀操作,我們可以稱之為讀快取,我們把正常取用的資料放在離我們最近的地方,我們可以快速取到。

2.2 什麼是Cache

這是一個Cache案例,這是CPU有三級快取,三級Cache,然後記憶體。現在先不要考慮Cache和Buffer的區別。

2.3 什麼是Buffer?

白色曲線區域是左轉彎待轉區,它的作用是:比如現在是紅燈,但是我們車可以越過停止線到左轉彎待轉區,待轉區是弧形的,離目的地更近的區域,這就是生活中Buffer的案例。

我將車停在離目的地更近的地方,這樣轉彎的時候一下子就可以轉過去,我可以轉得更快,轉得更快就可以減少道路的擁堵,這就是Buffer的作用。

2.4 再次定義Buffer與Cache!

在我們計算機中也是一樣的,CPU寫資料不能直接寫硬碟,因為硬碟太慢了,我不能等待,這時候我把資料寫在記憶體中返回,剩下記憶體再往硬碟裡寫。

但是很多時候我們不會特別區分Buffer和Cache,因為很多的區域會發現,不僅僅有讀快取Cache的功能,也有寫快取Buffer的功能。所以你經常看到有些區域是Buffer開始,或者統一叫做開始,這個時候怎麼分辨呢?

根據它的功能不同來區分是Buffer還是Cache,有的Cache就僅僅指的是讀快取,它沒有Buffer功能,但是有的Cache裡面有Cache有Buffer,比如記憶體就是典型的。我們寫資料寫記憶體,讀資料也是記憶體裡面讀,這個就是典型的名詞的問題。所以很多時候我們不用糾結它是Buffer還是Cache,我們怎麼分辨呢?

我們通過它的功能來分辨:

  • Cache一般用於讀快取,用於將頻繁讀取的內容放入快取,下次再讀取相同的內容,直接從快取中讀取,提高讀取效能,快取可以有多級。

  • Buffer一般用於寫緩衝,用於解決不同介質直接儲存速度的不同,將資料寫入到比自己相對慢的不是很多的中間區域就返回,然後最終再寫入到目標地址,提高寫入效能,緩衝也可以有多級。就像記憶體寫硬碟也很難,所以硬碟都會用快取。

我們都知道硬碟都會有一個Cache,這個Cache其實有Buffer的功能,也有Cache的功能。因為寫資料只要往硬碟裡寫資料,就會經過Cache區域,讀資料,我們很多有預讀的功能也要經過這個區域,這個區域就叫做Buffer開始或者簡稱開始。

可以看到快取和緩衝都可以有多級,或者說可以分層。我們們很多做開發的,應該會知道分層分級這種設計是一個架構師最基本的設計方式。

3.關於Cache 3.1存放位置

Cache存放位置,我們還是站在Web架構角度。

  • 客戶端,我這個網頁要存在客戶端當然快了,使用者根本不用發請求直接就開啟了,這時候就是瀏覽器快取。瀏覽器就是把我的快取存在使用者客戶端,所以使用者開啟頁面就會非常快。

  • 記憶體,記憶體就分為最快本機記憶體,但是本機記憶體的容量有限,這時候可以存在遠端伺服器記憶體。比如分散式快取其實就是存在遠端伺服器的記憶體,當然效能沒有本地記憶體好,因為要經過網路傳輸。網路傳輸就會有時間,會有效能的影響。

  • 硬碟,本機硬碟是最優的,再往下遠端伺服器硬碟,比如我們用的分散式軟體系統,或者共享檔案系統,這就是典型的遠端伺服器硬碟。

3.2 記憶體檔案儲存之tmpfs介紹

還有一種方式,像這樣存在本機記憶體,比如我們寫一個應用程式,這個應用程式要把資料存在本機記憶體,開發就很容易做到。

舉個例子,對於運維來說,我有一些資料訪問非常頻繁,但是我又沒法快速把它放在記憶體中,這時候怎麼辦?其實linux系統給我們提供了一個檔案系統,可以把我們資料直接放在記憶體中,就是tmpfs。

如果大家是老運維,你工作至少在七八年以上的運維,應該對這個比較熟悉,因為最早的時候基本都會用到tmpfs,tmpfs是怎麼玩的呢?它是把資料直接放在共享記憶體中,它是特殊檔案系統,我這裡做了一個案例。

我們可以看到這個tmpfs,是系統預設的,是32G,使用率12k,這個時候我僅需放81兆檔案,你會馬上發現dev/shm目錄就佔用81兆,可用記憶體同62237變成62156,共享記憶體從42變成123。

這個時候做一個小學計算題,可用記憶體,說明我們放81兆檔案是佔用了記憶體空間的。然後共享記憶體,可以證明我們/dev/shm是Linux給共享記憶體用的,這就是典型的案例。

3.4 記憶體檔案儲存之tmpfs使用方法

這個tmpfs怎麼用呢?直接#就可以了,當然你還可以設定不同大小。用tmpfs有什麼優勢呢?

  • 第一,儲存空間的設定和動態變化,放裡面就增加,刪了就自動縮減。

  • 第二,速度。天下武功,唯快不破,因為它是記憶體。

  • 第三,沒有永續性,這是它的缺點也是優點。為什麼是缺點呢?機器一重啟資料丟失了,為什麼是優點呢?因為有些場景下機器重啟就要讓他丟失。

這就看你怎麼用了,比如我把快取資料放在這兒就會比較快,如果說你又想用它的優勢,又想保持永續性,方式也很多,只要每次資料可實時同步就可以解決。

另外我們做反向代理快取,資料是要落盤的,這時候可以考慮使用tmpfs。還有session檔案放在tmpfs,還有將socket檔案放在tmpfs,還有其他需要高效能讀寫的場景。

3.5 記憶體檔案儲存之tmpfs優勢對比

為什麼講這個呢?因為我們之前有一個案例就使用到tmpfs,是電商有一次做活動,我們內部剛好有一個需求,需要一個效能讀寫的場景,要不停地寫,不停地讀,這個時候我們考慮了非常多其他的方案,發現I/O就是扛不住,這時候就想起了tmpfs,直接就可以用。這是講Cache的儲存位置就帶出了tmpfs。

3.6 Cache的幾個重要指標

這裡有一個面試題,我們手機常用的一個功能,雲備份,可以備份你的圖片和簡訊到雲端,這樣的功能是否需要CDN加速,為什麼?我的手機簡訊備份到雲上,換一個手機再下載下來,這樣的需求需要使用CDN加速嗎?其實答案非常明確,不需要。當然有別的疑惑一會兒再說,我只是說雲備份的場景是不需要的,為什麼?

這就涉及到快取幾個重要的特性。快取的命中率,所有快取如果沒有命中率,只會加慢整個流程,為什麼?

因為我們加快取相當於資料訪問和讀取加了一層路徑,這個路徑如果沒有發揮作用就會變慢,所以快取命中率是快取非常重要的指標,就可以解釋為什麼說這樣的需求不需要CDN加速,原因是因為沒有命中率。

我的圖片、簡訊只有我自己能訪問到,我同步到雲端,換手機的時候,只有我自己才下,快取命中率是0%,當然是不需要CDN加速的。

但是還有一種場景可能會需要,就是雲盤。但云盤有兩種不同場景,我們現在用的把資料同步到雲盤上,這個是不是需要CDN加速呢?不一定,一般這種雲盤都非常智慧的,它在下載的時候會判斷你這個資源的熱度。

具體怎麼做,因為我沒有幹過不知道,但是我們有類似相關係統,給資源熱度打分。比如說當資源熱度很高的時候,這個時候說明下載的人比較多,這個時候可以考慮放在CDN上。

但是儲存的時候還有很多的比如驗證,可能就不會上傳等等很多儲存功能,今天主要是快取為主,講讀快取。這個時候有可能需要CDN加速,但是雲備份場景是不需要的。這就是說我們掌握問題要掌握知識的最根本的地方,這個時候不管我們做什麼,你會發現所有問題都會迎刃而解。

4、關於客戶端的優化 4.1瀏覽器與DNS快取

當我們發出一個Http請求,第一步要做DNS解析。這是一個谷歌瀏覽器的截圖,這就是DNS快取儲存的地方。可以看到我訪問谷歌,我訪問的時間剛好是1分鐘60秒,下面這是瀏覽器DNS快取。

現在像HTML5有一個新特性,叫做DNS運貨區,這是京東首頁,可以看到很多的連結,什麼意思呢?一個頁面元件最多的是圖片等等東西。我先講一個前置條件,Http協議我們通常稱為流式的,為什麼?

因為我是邊下載邊渲染,一個瀏覽器首先會請求Web伺服器,拿到整個HTML頁面,瀏覽器會從上往下挨行讀,每讀到一個行,瀏覽器會提一個新的執行緒下載新的頁面元件資源,下載完成就直接渲染出來了。

為什麼我們開啟網頁會慢

問題一、當遇到阻塞的時候網頁開啟慢

當遇到什麼情況下會阻塞?當遇到載入JS會阻塞,你會看到一個頁面一直在轉圈,JS阻塞,因為JS有可能會修改頁面的道路數,所以載入JS的時候要等JS下載完畢,並執行完畢,才能繼續往下載入。

所以我們經常做Web優化的時候,我們會把CSS放在頁面頂端,把JS在頁面放在底部,因為JS下載會阻塞。

問題二、為什麼一個檔案有多個域名

第二個問題,你會懷疑京東一個圖片為什麼值得上10—30這麼多個域名呢?是因為瀏覽器訪問一個Web站點,瀏覽器是有併發限制的,不可能單程式跑,像火狐這種一般不同版本可能6—8個併發,但是併發是針對的域名,所以他搞了很多域名,這樣就可以讓頁面開啟更快。

但是域名多了就會產生另外一個問題,DNS解析就多了,這時候怎麼辦呢?HTML5有一個新特性叫做DNS運貨區,我可以把先把DNS解析獲取一遍,等你下面用的時候直接用就可以了,不用再解析了。

這些手段其實都是來加快前端優化的手段,當然還有很多,比如減少頁面元件,頁面元件少了當然開啟就快了。或者合併請求,比如我們們做運維,做淘寶的,就支援做元件合併,比如把某些小的CSS、JS合併起來傳送,這樣就會更快。

如何優化

當然還有CSS背景偏移,很多小圖示,我其實只是一個圖片,我下載下來再通過背景偏移技術,再把它展示在頁面上。還有比如懶載入,為了加快首屏時間,我使用懶載入。我先把首屏需要的資源載入下來,滑鼠往下拖的時候再一點點載入,這些手段都是加快首屏時間或者Web頁面開啟的時間。

當然DNS快取還有很多其他的,除了瀏覽器DNS快取,剩下的就是系統檔案。系統DNS快取,到localDNS,localDNS也是叢集,有快取,所以每一級都是DNS快取。

很多時候我們對於一些比如你要改某一個DNS的A記錄,我們會怎麼做呢?我會提前把A記錄TTL生存週期時間改得很短,這樣我改A記錄的時候就會很快,當然大家做運維會知道,中國有很多小的運營商耍流氓,把DNS快取設了很長,我還見過設好幾天的,所以改完以後在一些小的地方就是不生效。

DNS解析完畢,解析成公網IP地址,瀏覽器就會往公網IP地址發起請求。當然中間涉及到網路傳輸,一個request的網路傳輸,一個資料的網路傳輸,這個時候就涉及到Http快取線上,一個客戶端和server端要對話就是通過Http對話。

我發一個request告訴你伺服器能不能使用本地快取,快取有沒有過期,伺服器告訴他你可以使用本地快取。

4.2關於瀏覽器快取

瀏覽器快取協商有三種方式,首先我們看瀏覽器快取在什麼地方,上圖是火狐瀏覽器,火狐放在記憶體和磁碟。有的時候火狐瀏覽器大家發現會開啟比較慢,載入快取,記憶體裡有很多這樣的資料。

4.2.1 基於Last-Modifiedh快取協議

我們看第一種快取協商方式,基於最後修改時間的快取協商,我們都知道預設情況下,所有的系統都會有三個時間。

我們有一個最後修改時間,那我們所有的Web瀏覽器都很聰明,預設情況下都會通過SDNT系統呼叫,可以獲取到靜態檔案最後修改時間。當你請求一個靜態頁面的時候,瀏覽器預設會返回給你這個頁面最後修改時間是什麼。

第一次請求會發現都是200,我們看一下request頭部,請求頭,響應頭,在響應頭裡可以看到最後修改時間是2016年,這就是我的檔案修改時間,瀏覽器預設會把這個時間帶上。

現在我點選重新整理按鈕,你會發現Web伺服器返回了304,這就是基於最後修改時間的快取協商。這個時候請求頭請求的時候怎麼請求呢?

它會問瀏覽器,你告訴我這個頁面儲存修改時間是這個,你告訴我有沒有改,瀏覽器就告訴它,兄弟這個頁面沒有改過,你直接使用本地快取就可以。這個時候我們Web伺服器不會發資料給瀏覽器,瀏覽器直接使用本地快取就可以了。

但是你說動態的行不行,行,為什麼?你偽造一個Http頭部是可以的。所以為什麼講這個,不是說搞笑說段子。你要明白客戶端、瀏覽器通過什麼溝通,就是通過Http協議,只要你返回的時候返回一個頭部有最後修改時間,就能實現這個功能,只不過這是瀏覽器一個預設的行為。

4.2.2 基於Etag快取協議

第二種快取協商方式打標籤,一個頁面頻繁在最後修改時間變動,但是內容沒有變,我的頁面是每次重新生成的,但是頁面內容並沒有變。如果基於最後修改時間,這個快取就失效了,這時候就通過打標籤方式,通過不同演算法給頁面算一個值,然後發給瀏覽器。

每次你問我這個值有沒有發生改變,但這個演算法每個瀏覽器都不一樣,如果你不好理解,可以理解為做了HTML5給客戶端,每次拿HTML5來問我對不對,但是它其實不是做HTML5加密出來的。

上面兩種快取協商都有一個問題,因為要發起協商,我發給你,你再發給我,雖然沒有發生任何資料的產生,但是至少我返回了一個資料,證明你要給我建一個TCP三次握手和建立Http,這會佔用我的資源。

4.2.3 基於Expires快取協商cedilla消滅連線

第三次快取協商就是基於過期時間,這個是針對運維的,對於開發知道就行了。那麼客戶端和伺服器時間不同步怎麼辦?其實瀏覽器很聰明,它還有一個Cache—Control,它會算一個本地頭部時間,告訴你檔案生存週期多久,不管你客戶端時間對不對,你都能正確使用過期時間。

4.3 你真的會重新整理嗎?

如果有了這些快取,我們就來看一下到底會不會使用瀏覽器重新整理。比如火狐瀏覽器有一個重新整理按鈕,你按重新整理按鈕的時候,這個時候對於基於最後修改時間和打標籤的方式就會受影響。

但是基於過期時間是不受影響的,所以說很多時候我只要設了一年過期,你狂點F5是沒有用的。那麼怎麼辦呢?強制重新整理,ctrl+F5強制重新整理,瀏覽器這時候就會發起一個全新的請求,不會使用任何快取,所以我之前看到很多前端開發人員不會使用重新整理,我覺得好尷尬,點了半天不起作用。跑過來問運維,運維說你怎麼重新整理的,F5,F5不行,要ctrl+F5。

這就延伸出另外一個問題,比如我給某個資源設過期時間一年,但是不到一年我想改怎麼辦,你總不能讓我通知幾千萬使用者按一下ctrl+F5吧。有幾種方式,第一是直接修改檔名,第二是使用時間戳。

當然這個時候如果還用到CDN的時候,就要注意了,我們做CDN配置的時候有兩種,一種是URL帶時間戳,一種是不帶時間戳,URL做快取的時候不帶時間戳,那你就只能改名了,要不然你還要在CDN做強制重新整理,當然也可以,不是說不可以。你做一個小系統,你直接調CDN做快取重新整理也是可以的,就比較費勁了,這個就看需求。

5、關於工作中的一些感悟

我看大家在座的都工作時間比較久,大家可以想工作時間早和工作時間久回答問題發生什麼變化。我剛工作的時候別人問我問題我馬上回答,我直接回答說這樣是對的,等工作時間久了別人問我問題我會回答不一定,無論什麼問題回答都是不一定

為什麼?要看你的需求,不同需求我的回答就是不一樣的。所以後來別人說班長問什麼你都不一定,我說是的,你以前學技術的時候,你只需要做到這個就可以了,當你知道多的時候就會發現就是不一定。我們為開始學的時候搞一個負載均衡,我覺得這就是叢集。後來所有東西都是不一定,一定要看你的需求。

更有甚者在群裡問,班長支撐千萬PV是什麼架構?“不一定”。這就很難說了,這一定要看需求的,你說一個小型網站,就一個Http頁面,支援幾十億PV都沒有問題。所以要看你的業務型別,如果說電商那就複雜了,電商的體系體量整個業務就很複雜,所以不同業務,不同架構就是不一樣的。

這裡延伸出另外一個問題,大家現在工作不好乾,為什麼不好乾?不管你是做開發還是做運維,現在網際網路發展都開始有場景化,你之前是做電商的,不管是開發還是運維,你跳一家遊戲公司,想薪資翻倍不可能,因為你的經驗複製不過去。

你之前是做支付介面開發的,現在跳到Web商城,沒有支付是完全不同的。我們們做運維也是一樣的,所以我們們要不停學習,如果不學習只能慢慢被淘汰。

相關文章