深刻淺出Node.js(八):Connect模塊解析(之二)靜態文件中間件

上一篇專欄簡單介紹了Connect模塊的基本架構,它的執行模型十分簡單,中間件機制也使得它十分易於擴展,具有良好的可伸縮性。在Connect的良好機制下,咱們本章開始將逐步解開Connect生態圈中中間件部分,這部分給予Connect良好的功能擴展。 html

靜態文件中間件

也許你還記得我曾經寫過的Node.js靜態文件服務器實戰,那篇文章中我敘述瞭如何利用Node.js實現一個靜態文件服務器的許多技術細節,包括路由實現,MIME,緩存控制,傳輸壓縮,安全、歡迎頁、斷點續傳等。可是這裏咱們不須要去親自處理細節,Connectstatic中間件爲咱們提供上述全部功能。代碼只需寥寥3行便可: 前端

var connect = require('connect');  
var app = connect(); 
app.use(connect.static(__dirname + '/public'));

在項目中須要臨時搭建靜態服務器,也無需安裝apache之類的服務器,經過NPM安裝Connect以後,三行代碼便可解決需求。
這裏須要說起的是在使用該模塊的一點性能相關的細節。 node

動靜分離

前一章說起,app.use()方法在沒有指定路由信息時,至關於app.use("/", middleware)。這意味着靜態文件中間件將會在處理全部路徑的請求。在動靜態請求混雜的場景下,靜態中間件會在動態請求時也調用fs.stat來檢測文件系統是否存在靜態文件。這形成了沒必要要的系統調用,使得性能下降。
解決影響性能的方法既是動靜分離。利用路由檢測,避免沒必要要的系統調用,能夠有效下降對動態請求的性能影響。 git

app.use('/public', connect.static(__dirname + '/public'));

在大型的應用中,動靜分離一般無需到一個Node.js實例中進行,CDN的方式直接在域名上將請求分離。小型應用中,適當的進行動靜分離便可避免沒必要要的性能損耗。 github

緩存策略

緩存策略包含客戶端和服務端兩個部分。
客戶端的緩存,主要是利用瀏覽器對HTTP協議響應頭中cache-controlexpires字段的支持。瀏覽器在獲得明確的相應頭後,會將文件緩存在本地,依據cache-controlexpires的值進行相應的過時策略。這使得重複訪問的過程當中,瀏覽器能夠從本地緩存中讀取文件,而無需從網絡讀取文件,提高加載速度,也能夠下降對服務器的壓力。
默認狀況下靜態中間件的最大緩存時設置爲0,意味着它在瀏覽器關閉後就被清除。這顯然不是咱們所指望的結果。除非是在開發環境能夠無視maxAge的設置外,生產環境請務必設置緩存,由於它能有效節省網絡帶寬。 算法

app.use('/public', connect.static(__dirname + '/public', {maxAge: 86400000}));

maxAge選項的單位爲毫秒。YUI3的CDN服務器設置過時時間爲10年,是一個值得參考的值。
靜態文件若是在客戶端被緩存,在須要清除緩存的時候,又該如何清除呢?這裏的實現方法較多,一種較爲推薦的作法是爲文件進行md5處理。 apache

http://some.url/some.js?md5

當文件內容產生改變時,md5值也將發生改變,瀏覽器根據URL的不一樣會從新獲取靜態文件。md5的方式能夠避免沒必要要的緩存清除,也能精確清除緩存。
因爲瀏覽器自己緩存容量的限制,儘管咱們可能設置了10年的過時時間,可是也許兩天以後就被新的靜態文件擠出了本地緩存。這將持續引發靜態服務器的響應,也即意味着,客戶端緩存並不能徹底解決下降服務器壓力的問題。
爲了解決靜態服務器重複讀取磁盤形成的壓力,這裏須要引出第二個相關的中間件:staticCache後端

app.use(connect.staticCache());  
app.use(「/public」, connect.static(__dirname + '/public', {maxAge: 86400000}));

這是一個提供上層緩存功能的中間件,可以將磁盤中的文件加載到內存中,以提升響應速度和提升性能。
它的官方測試數據以下: 瀏覽器

static(): 2700 rps 
node-static: 5300 rps 
static() + staticCache(): 7500 rps

另外一個專門用於靜態文件託管的模塊叫node-static,其性能是Connect靜態文件中間件的效率的兩倍。可是在緩存中間件的協助下,能夠彌補性能損失。
事實上,這個中間件在生產環境下並不推薦被使用,並且它將在Connect 3.0版本中被移除。可是它的實現中有值得玩味的地方,這有助於咱們認識Node.js模型的優缺點。
staticCache中間件有兩個主要的選項:maxObjectsmaxLength。表明的是能存儲多少個文件和單個文件的最大尺寸,其默認值爲128和256kb。爲什麼會有這兩個選項的設定,緣由在於V8有內存限制的緣由,做爲緩存,若是沒有良好的過時策略,緩存將會無限增長,直到內存溢出。設置存儲數量和單個文件大小後,能夠有效抑制緩存區的大小。
事實上,該緩存還存在的缺陷是單機狀況下,一般爲了有效利用CPU,Node.js實例並不僅有一個,多個實例進程之間將會存在冗餘的緩存佔用,這對於內存使用而言是浪費的。
除此以外,V8的垃圾回收機制是暫停JavaScript線程執行,經過掃描的方式決定是否回收對象。若是緩存對象過大,鍵太多,則掃描的時間會增長,會引發JavaScript響應業務邏輯的速度變慢。
可是這個模塊並不是沒有存在的意義,上述說起的缺陷大多都是V8內存限制和Node.js單線程的緣由。解決該問題的方式則變得明瞭。
風險轉移是Node.js中經常使用於解決資源不足問題的方式,尤爲是內存方面的問題。將緩存點,從Node.js實例進程中轉移到第三方成熟的緩存中去便可。這能夠保證: 緩存

  1. 緩存內容不冗餘。
  2. 集中式緩存,減小不一致性的發生。
  3. 緩存的算法更優秀以保持較高的命中率。
  4. 讓Node.js保持輕量,以解決它更擅長的問題。

Connect推薦服務器端緩存採用varnish這樣的成熟緩存代理。而筆者目前的項目則是經過Redis來完成後端緩存的任務。

參考內容

關於做者

田永強,新浪微博@樸靈,前端工程師,曾就任於SAP,現就任於淘寶,花名樸靈,致力於NodeJS和Mobile Web App方面的研發工做。雙修先後端JavaScript,寄望將NodeJS引薦給更多的工程師。興趣:讀萬卷書,行萬里路。我的Github地址:http://github.com/JacksonTian。 

相關文章
相關標籤/搜索