优化快速 + 滑动 HTML 渲染时间
Optimize Express + Swig HTML rendering time
我遇到了一个关键问题。
我的应用程序体系结构描述如下:
nginx -> Web App (Express/NodeJS) -> API (Jetty/Java) -> MySQL
API 应用程序经过了很好的优化,因此无需在此处提及其性能。(~200 毫秒/频率,100 个频率/秒)
我的网络应用程序:
- 表达
- 摇摆模板引擎
在执行配置文件日志时,我注意到 Swig 模板引擎的 HTML 渲染时间会阻止 I/O 太长,因此它会大大增加其他待处理请求的等待时间。
对于渲染 1MB 的文本/html 响应,Swig 模板需要 ~250 毫秒。
这是我的压力测试的输出:
$ node stress.js 20
Receive response [0] - 200 - 431.682654ms
Receive response [1] - 200 - 419.248099ms
Receive response [2] - 200 - 670.558033ms
Receive response [4] - 200 - 920.763105ms
Receive response [3] - 200 - 986.20115ms
Receive response [7] - 200 - 1521.330763ms
Receive response [5] - 200 - 1622.569327ms
Receive response [9] - 200 - 1424.500137ms
Receive response [13] - 200 - 1643.676996ms
Receive response [14] - 200 - 1595.958319ms
Receive response [10] - 200 - 1798.043086ms
Receive response [15] - 200 - 1551.028243ms
Receive response [8] - 200 - 1944.247382ms
Receive response [6] - 200 - 2044.866157ms
Receive response [11] - 200 - 2162.960215ms
Receive response [17] - 200 - 1941.155794ms
Receive response [16] - 200 - 1992.213563ms
Receive response [12] - 200 - 2315.330372ms
Receive response [18] - 200 - 2571.841722ms
Receive response [19] - 200 - 2523.899486ms
AVG: 1604.10ms
如您所见,请求越晚,等待时间越长。
当我返回响应代码而不是渲染 HTML 时,通过修改一些代码:
function render(req, res, next, model) {
return res.status(200).end(); // add this line
res.render('list', model);
}
压力测试输出更改为:
$ node stress.js 20
Receive response [0] - 200 - 147.738725ms
Receive response [1] - 200 - 204.656645ms
Receive response [2] - 200 - 176.583635ms
Receive response [3] - 200 - 218.785931ms
Receive response [4] - 200 - 194.479036ms
Receive response [6] - 200 - 191.531871ms
Receive response [5] - 200 - 265.371646ms
Receive response [7] - 200 - 294.373466ms
Receive response [8] - 200 - 262.097708ms
Receive response [10] - 200 - 282.183757ms
Receive response [11] - 200 - 249.842496ms
Receive response [9] - 200 - 371.228602ms
Receive response [14] - 200 - 236.945983ms
Receive response [13] - 200 - 304.847457ms
Receive response [12] - 200 - 377.766879ms
Receive response [15] - 200 - 332.011981ms
Receive response [16] - 200 - 306.347012ms
Receive response [17] - 200 - 284.942474ms
Receive response [19] - 200 - 249.047099ms
Receive response [18] - 200 - 315.11977ms
AVG: 263.30ms
我之前尝试过实施一些解决方案,但没有一个可以减少响应时间:
使用节点群集(我的服务器中有 2 个工作线程)
if (conf.cluster) {
// cluster setup
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died');
// create new worker
cluster.fork();
});
} else {
rek('server').listen(conf.port, function() {
console.log('Application started at port ' + conf.port + ' [PID: ' + process.pid + ']');
});
}
} else {
rek('server').listen(conf.port, function() {
console.log('Application started at port ' + conf.port + ' [PID: ' + process.pid + ']');
});
}
使用 JXCore 与 16 个线程(最大线程数没有)
jx mt-keep:16 app.js
使用 NGINX 负载平衡
启动 4 个节点进程
$ PORT=3000 forever start app.js
$ PORT=3001 forever start app.js
$ PORT=3002 forever start app.js
$ PORT=3003 forever start app.js
nginx.conf
upstream webapp {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
server {
listen 80;
location / {
proxy_pass http://webapp;
}
[...]
}
我认为上述所有解决方案都会提供多个进程/线程,这些进程/线程在执行 HTML 渲染等繁重任务时不会相互阻塞,但结果与我的预期不同:等待时间不会减少。尽管日志显示请求实际上由多个进程/线程提供服务。
我在这里错过了什么点吗?
或者你能告诉我另一种减少等待时间的解决方案吗?
创建集群不会减少响应时间,但它将允许您并行运行响应而不会阻塞 IO。当然,为了正确使用集群,您需要为主节点设置自己的逻辑,以有效地控制工作线程。在没有适当逻辑的情况下添加集群永远不会给您带来任何真正的好处。为了使此操作正确工作,您的主节点需要处理所有传入的请求,并将它们分发给工作线程进行处理。然后,工作人员将结果发送回主节点,由主节点处理其余部分。
我认为您应该检查以下几点:
->避免使用模板缓存阻止 IO
->将模板拆分为多个部分并按需使用负载
->收集数据的时间已经覆盖了一次?
这里真正的答案是缓存。
每次压力时页面是否都要重新呈现?我不认为模板数据每分钟都在变化,如果有的话。
一个解决方案可能是编写 2 个充当"三明治"的中间件,渲染的路由应该具有这样的结构:
- 请求
- 从缓存中获取中间件
- 数据库???
- 摇摆模板
- 放入缓存中间件
- 响应中间件
put-in-cache
应该将编译的模板写入一个非常快速的缓存数据库(REDIS 非常适合此),使其在 1 分钟内过期,并使用 url 或其他(更聪明的)机制(如请求它的 userid 或标头)对其进行索引
get-from-cache
会在每个 HTTP 请求上查询 REDIS 以获取"索引查询",以防它找到已经编译的模板,它应该res.send
- 如何在输入中放置时间=“0”;时间“;在html中使用javascript
- 如何使用javascript在html中查找日期时间格式
- javascript函数将当前时间显示为html选择标记的预选值
- 按时间启用HTML按钮
- HTML 5<音频>-在特定时间点播放文件
- HTML 5 音频 :是否有在更改缓冲持续时间时触发的事件
- 画布 HTML 加载时间
- 使用 javascript 解析和显示 HTML 音频当前时间
- 我们怎么知道消除HTML/JS/CSS文件中的空白可以缩短页面加载时间呢
- Ckeditor:如何在mysql中避免使用Ckeditor中的html标签来节省时间
- HTML表单中的时间条目验证
- 增加在选择元素HTML中搜索的时间
- 如何从html输入类型=“”中只获得Angular控制器变量中的时间值;时间”;
- Powerbuilder/Javascript HTML数据窗口SetItem日期时间失败
- 如何在HTML视频达到特定时间标记时触发事件
- 使用javascript for html显示特定时区的日期和时间
- 根据一天中的时间转到新的 html 文件
- 在 rails / html / js 中创建一个时间轴
- 在 HTML 字段中填写本地日期时间和时区名称
- 我如何从jquery中的html表中提取从时间,到时间(约会时间)