深入浅出Node.js(八):Connect模块解析(之二)静态文件中间件
为什么80%的码农都做不了架构师?>>>
上一篇专栏简单介绍了Connect模块的基本架构,它的执行模型十分简单,中间件机制也使得它十分易于扩展,具备良好的可伸缩性。在Connect的良好机制下,我们本章开始将逐步解开Connect生态圈中中间件部分,这部分给予Connect良好的功能扩展。
静态文件中间件
也许你还记得我曾经写过的Node.js静态文件服务器实战,那篇文章中我叙述了如何利用Node.js实现一个静态文件服务器的许多技术细节,包括路由实现,MIME,缓存控制,传输压缩,安全、欢迎页、断点续传等。但是这里我们不需要去亲自处理细节,Connect
的static
中间件为我们提供上述所有功能。代码只需寥寥3行即可:
var connect = require('connect');
var app = connect();
app.use(connect.static(__dirname + '/public'));
在项目中需要临时搭建静态服务器,也无需安装apache之类的服务器,通过NPM安装Connect之后,三行代码即可解决需求。
这里需要提及的是在使用该模块的一点性能相关的细节。
动静分离
前一章提及,app.use()
方法在没有指定路由信息时,相当于app.use("/", middleware)
。这意味着静态文件中间件将会在处理所有路径的请求。在动静态请求混杂的场景下,静态中间件会在动态请求时也调用fs.stat
来检测文件系统是否存在静态文件。这造成了不必要的系统调用,使得性能降低。
解决影响性能的方法既是动静分离。利用路由检测,避免不必要的系统调用,可以有效降低对动态请求的性能影响。
app.use('/public', connect.static(__dirname + '/public'));
在大型的应用中,动静分离通常无需到一个Node.js实例中进行,CDN的方式直接在域名上将请求分离。小型应用中,适当的进行动静分离即可避免不必要的性能损耗。
缓存策略
缓存策略包含客户端和服务端两个部分。
客户端的缓存,主要是利用浏览器对HTTP协议响应头中cache-control
和expires
字段的支持。浏览器在得到明确的相应头后,会将文件缓存在本地,依据cache-control
和expires
的值进行相应的过期策略。这使得重复访问的过程中,浏览器可以从本地缓存中读取文件,而无需从网络读取文件,提升加载速度,也可以降低对服务器的压力。
默认情况下静态中间件的最大缓存时设置为0,意味着它在浏览器关闭后就被清除。这显然不是我们所期望的结果。除非是在开发环境可以无视maxAge
的设置外,生产环境请务必设置缓存,因为它能有效节省网络带宽。
app.use('/public', connect.static(__dirname + '/public', {maxAge: 86400000}));
maxAge
选项的单位为毫秒。YUI3的CDN服务器设置过期时间为10年,是一个值得参考的值。
静态文件如果在客户端被缓存,在需要清除缓存的时候,又该如何清除呢?这里的实现方法较多,一种较为推荐的做法是为文件进行md5处理。
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实例进程中转移到第三方成熟的缓存中去即可。这可以保证:
- 缓存内容不冗余。
- 集中式缓存,减少不一致性的发生。
- 缓存的算法更优秀以保持较高的命中率。
- 让Node.js保持轻量,以解决它更擅长的问题。
Connect推荐服务器端缓存采用varnish
这样的成熟缓存代理。而笔者目前的项目则是通过Redis
来完成后端缓存的任务。
参考内容
- https://www.varnish-cache.org/releases
- http://www.senchalabs.org/connect/static.html
- http://www.senchalabs.org/connect/staticCache.html
关于作者
田永强,新浪微博@朴灵,前端工程师,曾就职于SAP,现就职于淘宝,花名朴灵,致力于NodeJS和Mobile Web App方面的研发工作。双修前后端JavaScript,寄望将NodeJS引荐给更多的工程师。兴趣:读万卷书,行万里路。个人Github地址:http://github.com/JacksonTian。
转载于:https://my.oschina.net/leeldy/blog/85133
深入浅出Node.js(八):Connect模块解析(之二)静态文件中间件相关推荐
- Node.js快速文件服务器(通过HTTP的静态文件)
本文翻译自:Node.js quick file server (static files over HTTP) Is there Node.js ready-to-use tool (install ...
- 【深入浅出Node.js系列十一】Node.js开发框架Express4.x
为什么80%的码农都做不了架构师?>>> #0 系列目录# 深入浅出Node.js系列 [深入浅出Node.js系列一]什么是Node.js [深入浅出Node.js系列二]N ...
- 转载:Node.js入门系列——《深入浅出Node.js》
作者:田永强 日期:2011-12-02 完整版 前言: Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS ...
- 深入浅出Node.js(上)
(一):什么是Node.js Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟 ...
- 深入浅出Node.js(一):什么是Node.js(转贴)
以下内容转自:http://www.infoq.com/cn/articles/what-is-nodejs/ 作者:崔康 [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的 ...
- 深入浅出Node.js
深入浅出Node.js(一):什么是Node.js [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node. ...
- (转)深入浅出Node.js(一):什么是Node.js
原文地址:http://www.infoq.com/cn/articles/what-is-nodejs [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在 ...
- node.js中模块_在Node.js中需要模块:您需要知道的一切
node.js中模块 by Samer Buna 通过Samer Buna 在Node.js中需要模块:您需要知道的一切 (Requiring modules in Node.js: Everythi ...
- 一个月时间整理《深入浅出Node.js》
今天终于把朴灵老师写的<深入浅出Node.js>给学习完了, 这本书不是一本简单的Node入门书籍,它没有停留在Node介绍或者框架.库的使用层面上,而是从不同的视角来揭示Node自己内在 ...
最新文章
- Doolittle算法C语言实现
- 国内高校硕博补贴大公开!(某校博士在读已经年薪 25w 了)
- SQL Server中数据的修改是如何落盘的?
- FreeRTOS 的命名规则
- vsFTP服务器的配置
- 初步探讨WPF的ListView控件(涉及模板、查找子控件)
- Win10上VMware的问题汇总
- 让你的git bash更好看更实用
- Redis-数据结构04-整数集合(intset)
- AI ProCon 2020第一天:40+大厂专家共话AI技术应用下一个十年!
- mysql调用时附加依赖项_c# – 无法加载“MySql.Data”或其中一个依赖项.
- feign multipartfile 多文件上传_Spring Cloud Alibaba 实战(六) - 声明式HTTP客户端-Feign
- 用户访谈与问卷调查怎么做
- 基于STM32的高精度温度测控系统-PCB设计
- MPLAB使用PICKit3.5烧录程序说明
- matlab求矩阵特征值的最大值,[转载]MATLAB用eig()函数求【特征值】【特征向量】【归一化...
- 【Spark NLP】第 15 章:聊天机器人
- 关于微信投票刷票的js代码
- Docker安装PHP-FPM5.6 (自带redis扩展,Mysql扩展,GD库扩展(支持JEPG))
- 计蒜客习题:恋爱纪念日(C语言)