高效能伺服器架構(二) 快取清理策略

2021-08-22 12:17:24 字數 3057 閱讀 9807

雖然使用快取思想似乎是乙個很簡單的事情,但是快取機制卻有乙個核心的難點,就是——快取清理。我們所說的快取,都是儲存一些資料,但是這些資料往往是會變化的,我們要針對這些變化,清理掉儲存的「髒」資料,卻可能不是那麼容易。

第一種是使用控制命令。簡單來說,就是在伺服器程序上,開通乙個實時的命令埠,我們可以通過網路資料報(如udp包),或者linux系統訊號(如kill sigusr2程序號)之類的手段,傳送乙個命令訊息給伺服器程序,讓程序開始清理快取。這種清理可能執行的是最簡單的「全部清理」,也有的可以細緻一點的,讓命令訊息中帶有「想清理的資料id」這樣的資訊,比如我們傳送給web伺服器的清理訊息網路包中會帶乙個字串url,表示要清理哪乙個html檔案的快取。這種做法的好處是清理的操作很精準,可以明確的控制清理的時間和資料。但是缺點就是比較繁瑣,手工去編寫傳送這種命令很煩人,所以一般我們會把清理快取命令的工作,編寫到上傳靜態資料的工具當中,比如結合到**的內容發布系統中,一旦編輯提交了一篇新的新聞,發布系統的程式就自動的傳送乙個清理訊息給web伺服器。

第二種是使用字段判斷邏輯。也就是伺服器程序,會在每次讀取快取前,根據一些特徵資料,快速的判斷記憶體中的快取和源資料內容,是否有不一致(是否髒)的地方,如果有不一致的地方,就自動清理這條資料的快取。這種做法會消耗一部分cpu,但是就不需要人工去處理清理快取的事情,自動化程度很高。現在我們的瀏覽器和web伺服器之間,就有用這種機制:檢查檔案md5;或者檢查檔案最後更新時間。具體的做法,就是每次瀏覽器發起對web伺服器的請求時,除了傳送url給伺服器外,還會傳送乙個快取了此url對應的檔案內容的md5校驗串、或者是此檔案在伺服器上的「最後更新時間」(這個校驗串和「最後更新時間」是第一次獲的檔案時一併從伺服器獲得的);伺服器收到之後,就會把md5校驗串或者最後更新時間,和磁碟上的目標檔案進行對比,如果是一致的,說明這個檔案沒有被修改過(快取不是「髒」的),可以直接使用快取。否則就會讀取目標檔案返回新的內容給瀏覽器。這種做法對於伺服器效能是有一定消耗的,所以如果往往我們還會搭配其他的快取清理機制來用,比如我們會在設定乙個「超時檢查」的機制:就是對於所有的快取清理檢查,我們都簡單的看看快取存在的時間是否「超時」了,如果超過了,才進行下一步的檢查,這樣就不用每次請求都去算md5或者看最後更新時間了。但是這樣就存在「超時」時間內快取變髒的可能性。

上面說了執行時靜態的快取清理,現在說說執行時變化的快取資料。在伺服器程式執行期間,如果使用者和伺服器之間的互動,導致了快取的資料產生了變化,就是所謂「執行時變化快取」。比如我們玩網路遊戲,登入之後的角色資料就會從資料庫裡讀出來,進入伺服器的快取(可能是堆記憶體或者memcached、共享記憶體),在我們不斷進行遊戲操作的時候,對應的角色資料就會產生修改的操作,這種快取資料就是「執行時變化的快取」。這種執行時變化的資料,有讀和寫兩個方面的清理問題:由於快取的資料會變化,如果另外乙個程序從資料庫讀你的角色資料,就會發現和當前遊戲裡的資料不一致;如果伺服器程序突然結束了,你在遊戲裡公升級,或者撿道具的資料可能會從記憶體快取中消失,導致你白忙活了半天,這就是沒有回寫(快取寫操作的清理)導致的問題。這種情況在電子商務領域也很常見,最典型的就是火車票網上購買的系統,火車票資料快取在記憶體必須有合適的清理機制,否則讓兩個買了同一張票就麻煩了,但如果不快取,大量使用者同時搶票,伺服器也應對不過來。因此在執行時變化的資料快取,應該有一些特別的快取清理策略。

在實際執行業務中,執行變化的資料往往是根據使用使用者的增多而增多的,因此首先要考慮的問題,就是快取空間不夠的可能性。我們不太可能把全部資料都放到快取的空間裡,也不可能清理快取的時候就全部資料一起清理,所以我們一般要對資料進行分割,這種分割的策略常見的有兩種:一種是按重要級來分割,一種是按使用部分分割。

先舉例說說「按重要級分割」,在網路遊戲中,同樣是角色的資料,有些資料的變化可能會每次修改都立刻回寫到資料庫(清理寫快取),其他一些資料的變化會延遲一段時間,甚至有些資料直到角色退出遊戲才回寫,如玩家的等級變化(公升級了),**裝備的獲得和消耗,這些玩家非常看重的資料,基本上會立刻回寫,這些就是所謂最重要的快取資料。而玩家的經驗值變化、當前hp、mp的變化,就會延遲一段時間才寫,因為就算丟失了快取,玩家也不會太過關注。最後有些比如玩家在房間(地區)裡的x/y座標,對話聊天的記錄,可能會退出時回寫,甚至不回寫。這個例子說的是「寫快取」的清理,下面說說「讀快取」的按重要級分割清理。

假如我們寫乙個**系統,裡面容納了很多產品,這些產品有一些會被使用者頻繁檢索到,比較熱銷,而另外一些商品則沒那麼熱銷。熱銷的商品的餘額、銷量、評價都會比較頻繁的變化,而滯銷的商品則變化很少。所以我們在設計的時候,就應該按照不同商品的訪問頻繁程度,來決定快取哪些商品的資料。我們在設計快取的結構時,就應該構建乙個可以統計快取讀寫次數的指標,如果有些資料的讀寫頻率過低,或者空閒(沒有人讀、寫快取)時間超長,快取應該主動清理掉這些資料,以便其他新的資料能進入快取。這種策略也叫做「冷熱交換」策略。實現「冷熱交換」的策略時,關鍵是要定義乙個合理的冷熱統計演算法。一些固定的指標和演算法,往往並不能很好的應對不同硬體、不同網路情況下的變化,所以現在人們普遍會用一些動態的演算法,如redis就採用了5種,他們是:

1.根據過期時間,清理最長時間沒用過的

2.根據過期時間,清理即將過期的

3.根據過期時間,任意清理乙個

4. 無論是否過期,隨機清理

5.無論是否過期,根據lru原則清理:所謂lru,就是least recently used,最近最久未使用過。這個原則的思想是:如果乙個資料在最近一段時間沒有被訪問到,那麼在將來他被訪問的可能性也很小。lru是在作業系統中很常見的一種原則,比如記憶體的頁面置換演算法(也包括fifo,lfu等),對於lru的實現,還是非常有技巧的,但是本文就不詳細去說明如何實現,留待大家上網搜尋「lru」關鍵字學習。

資料快取的清理策略其實遠不止上面所說的這些,要用好快取這個**,就要仔細研究需要快取的資料特徵,他們的讀寫分布,資料之中的差別。然後最大化的利用業務領域的知識,來設計最合理的快取清理策略。這個世界上不存在萬能的優化快取清理策略,只存在針對業務領域最優化的策略,這需要我們程式設計師深入理解業務領域,去發現資料背後的規律。

高效能遊戲伺服器架構 快取清理策略

雖然使用快取思想似乎是乙個很簡單的事情,但是快取機制卻有乙個核心的難點,就是 快取清理。我們所說的快取,都是儲存一些資料,但是這些資料往往是會變化的,我們要針對這些變化,清理掉儲存的 髒 資料,卻可能不是那麼容易。第一種是使用控制命令。簡單來說,就是在伺服器程序上,開通乙個實時的命令埠,我們可以通過...

高效能伺服器架構(一) 緩衝策略

在伺服器端程式開發領域,效能問題一直是備受關注的重點。業界有大量的框架 元件 類庫都是以效能為賣點而廣為人知。然而,伺服器端程式在效能問題上應該有何種基本思路,這個卻很少被這些專案的文件提及。本文正式希望介紹伺服器端解決效能問題的基本策略和經典實踐 由韓大分享。在伺服器端程式開發領域,效能問題一直是...

高效能伺服器架構

1.請求佇列 連線池 2.主要的業務邏輯挪到應用伺服器處理,資料庫只做輔助的業務處理 3.快取 4.快取更新 同步 快取失效 time out 重新去資料庫中查詢,實時性較差 5.一旦資料庫中資料更新,立即通知前端快取更新,實時性較好 6.快取換頁 記憶體不夠,將不活躍資料換出記憶體 fifo 先進...