快取服務器設計與實現(四)

來源:互聯網
上載者:User
        這裡我們聚焦一個問題,就是緩衝滿的情況。一般的cache都會配置容量,無論是記憶體緩衝還是磁碟緩衝,都不能無節制的去使用他們。這裡以磁碟緩衝為例,如果配置的限額已用完,該如何處理呢?        對於nginx,如果你開啟了cache功能,那麼你通過ps命令看到這樣的進程:cache manager process。其實這個進程的作用主要是在檔案失效或者磁碟空間不足的時候,刪除對象。那麼怎麼刪,什麼標準?        由於每個緩衝對象都有一個最長有效期間,過了這個時間對象就認為無效了,需要刪掉。在nginx的緩衝系統中有個lru隊列,裡面的元素其實是對象在rbtree中的一個node。每次hit一個對象,對應的node就從隊列中脫離,然後重新插入到隊列頭部,這樣最近被訪問的node就被移到隊列開頭,冷的對象則逐漸推向隊尾,一個最基本的LRU思想(當然這樣的處理存在公認的問題,即不能準確判斷一個檔案的冷熱程度,在隊尾的也不一定就是冷的)。而這個cache manager進程就是從隊尾開始,查看是否有失效的檔案。很顯然,如果隊尾的節點沒有失效,那麼整個隊列上也就都沒有問題。後面nginx就會設定定時器,過一段時間再來做檢查。但是如果此時緩衝滿了,又沒有檔案失效,那麼就要做lru來刪一些冷的檔案,這個也是沒有辦法的事情。在刪的時候,也是從lru隊列的尾部開始,如果當前檔案已經沒有請求在使用,那麼就可以直接刪了。如果還有請求在用,那麼它就從後往前找下一個可以刪的對象。一般它嘗試找20次,如果找20次還沒有找到一個可刪的目標,那就先歇一會再處理。刪到什麼程度結束呢?一般刪掉到磁碟使用量低於配額就可。當然你可以指定一些標準,例如刪掉總量的10%等等。還有一點要說明一下:因為每個緩衝對象都要對應一個記憶體結構,這些空間來自共用記憶體,在記憶體不足的時候分配可能會失敗,那麼這時也需要採取一些挽救措施。nginx的處理就是去做lru,雖然lru是來刪檔案,顯然在刪的同時,記憶體中的控制結構也會被釋放,這樣就可以起到緩解記憶體緊張的局面。        這塊的東西基本就是這樣,剩下的就是一些代碼細節,有興趣的朋友可以去翻看nginx代碼。        來看第二個問題:一個快取服務器異常停機或者要進行維護關機了,當機器再次啟動快取服務的時候,會遇到一個令人難以接受的狀況。因為你之前的機器跑了很久,已經緩衝了成千上萬的檔案,體積高達數百G甚至上T。如果現在這個機器要提供服務,那麼會由於之前的緩衝不可用(其實是不可見),而導致大量的回源請求。要是把客戶來源站點給打死了,就等著客戶找你算賬吧。        所以關鍵的問題,就是如何重建之前的緩衝。其實檔案都還在磁碟上,缺失的只是記憶體中的控制資訊,沒有這些資訊就不能打通整個緩衝系統跟實際磁碟檔案的聯絡。在nginx裡面,重建緩衝這項艱巨的任務由一個叫“cache loader process”的進程來完成,同樣的通過ps指令就可以看到。其實原理很簡單,我們先看以前文章中的那個例子:                       /cache/0/8d/8ef9229f02c5672c747dc7a324d658d0

        cache loader process在執行時會去緩衝目錄下遍曆所有的子目錄和檔案,對於檔案需要做一些額外的驗證,判讀該檔案是否符合一個正常快取檔案的特徵,例如檔案名稱是否是32字元(例子中的hash串表示的檔案名稱),檔案最少長度(因為在nginx裡面,快取檔案開頭總是含有特定大小的控制資訊)等。對於nginx認為的非合法檔案,nginx將會予以刪除。假設nginx發現了一個合法的檔案,那麼就需要將它註冊到緩衝系統中,具體的動作包括申請結構,加到rbtree和lru隊列中等。特別是在插入rbtree的時候,檔案名稱正是原來緩衝中用來插入和尋找的關鍵字,所以很方便的就可以完成插入。當cache
loader process
完成了重建緩衝的任務後,就可以exit,因為它已經沒有什麼存在的價值了。        這裡還有一個有意思的地方:如果檔案比較多,重建過程可能會很慢,為此nginx使用了三個個變數來控制速度,loader_threshold,loader_files和loader_sleep。如果loader進程持續工作時間達到loader_threshold,那麼就去歇一會。如果重建的檔案數量到達loader_files,作為獎勵,也可以去歇一會,歇息的時間為loader_sleep。這三個變數都是可以通過配置指定的。這裡有個重要的事情要強調一下:        在loader進程重建緩衝的時候,其實nginx的worker也在同時提供服務,那麼這個loader是否是會影響正常的服務?其實這個loader進程與普通的worker都是由master進程通過fork派生的,所以兩者都可以看到共用記憶體中的一切,由於整個系統的緩衝資訊都在共用記憶體中,兩者對共用資源的訪問就會存在互斥。loader進程中,將一個對象插入到緩衝的過程跟worker中是一樣的,都是先搶鎖,然後尋找,沒有找到再插入。所以一個對象到底是由誰插入到緩衝系統中,完全靠loader和worker公平競爭鎖。而那個競爭中的失敗者,當它後面拿到鎖的時候,就發現讓人捷足先登了,那麼就跳過插入的工作了。反過來也是一樣。

        總的看來,nginx在很多機制上處理都非常的簡單明了,並且繼承了一直以來的高效。雖然站在一個專業cache的角度看,它很多功能還不完善,但是依然有很多值得我們參考和借鑒的東西。如果你想設計和實現一個自己cache,又對功能要求不是那麼高,那去參考nginx的這個模型倒是一個不錯的選擇。        關於cache的設計,還有一個重要的機制就是到期控制。這個至關重要,大家如果對cache有個大概的認識,稍微想一下就能體會它的重要性。這塊後面再拿出篇幅來討論吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.