上一篇專欄簡單介紹了Connect模塊的基本架構,它的執行模型十分簡單,中間件機制也使得它十分易於擴展,具有良好的可伸縮性。在Connect的良好機制下,咱們本章開始將逐步解開Connect生態圈中中間件部分,這部分給予Connect良好的功能擴展。 html
也許你還記得我曾經寫過的Node.js靜態文件服務器實戰,那篇文章中我敘述瞭如何利用Node.js實現一個靜態文件服務器的許多技術細節,包括路由實現,MIME,緩存控制,傳輸壓縮,安全、歡迎頁、斷點續傳等。可是這裏咱們不須要去親自處理細節,Connect
的static
中間件爲咱們提供上述全部功能。代碼只需寥寥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-control
和expires
字段的支持。瀏覽器在獲得明確的相應頭後,會將文件緩存在本地,依據cache-control
和expires
的值進行相應的過時策略。這使得重複訪問的過程當中,瀏覽器能夠從本地緩存中讀取文件,而無需從網絡讀取文件,提高加載速度,也能夠下降對服務器的壓力。
默認狀況下靜態中間件的最大緩存時設置爲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
中間件有兩個主要的選項:maxObjects
和maxLength
。表明的是能存儲多少個文件和單個文件的最大尺寸,其默認值爲128和256kb。爲什麼會有這兩個選項的設定,緣由在於V8有內存限制的緣由,做爲緩存,若是沒有良好的過時策略,緩存將會無限增長,直到內存溢出。設置存儲數量和單個文件大小後,能夠有效抑制緩存區的大小。
事實上,該緩存還存在的缺陷是單機狀況下,一般爲了有效利用CPU,Node.js實例並不僅有一個,多個實例進程之間將會存在冗餘的緩存佔用,這對於內存使用而言是浪費的。
除此以外,V8的垃圾回收機制是暫停JavaScript線程執行,經過掃描的方式決定是否回收對象。若是緩存對象過大,鍵太多,則掃描的時間會增長,會引發JavaScript響應業務邏輯的速度變慢。
可是這個模塊並不是沒有存在的意義,上述說起的缺陷大多都是V8內存限制和Node.js單線程的緣由。解決該問題的方式則變得明瞭。
風險轉移是Node.js中經常使用於解決資源不足問題的方式,尤爲是內存方面的問題。將緩存點,從Node.js實例進程中轉移到第三方成熟的緩存中去便可。這能夠保證: 緩存
Connect推薦服務器端緩存採用varnish
這樣的成熟緩存代理。而筆者目前的項目則是經過Redis
來完成後端緩存的任務。
田永強,新浪微博@樸靈,前端工程師,曾就任於SAP,現就任於淘寶,花名樸靈,致力於NodeJS和Mobile Web App方面的研發工做。雙修先後端JavaScript,寄望將NodeJS引薦給更多的工程師。興趣:讀萬卷書,行萬里路。我的Github地址:http://github.com/JacksonTian。