express 调优的一个过程和心得,不错的文章
Netflix的软件工程师Yunong Xiao最近在公司的技术博客上写了一篇文章,分析了他所在的团队在将Netflix网站UI转移到Node.js上时遇到的延迟问题。在文章中他描述了找到问题根本原因所经历的复杂的工程过程,以及他们是怎样做出替换底层API框架的决定。
最初,Yunnong的团队观察到API中某些端点的请求延迟会持续上升(每小时增加10ms),并且在高延迟的时段应用占用的CPU资源超过预期。他们最早的假设是请求处理器的一些问题(例如内存泄露)导致了延迟时间上升。为检验这一假设,他们配置了一个可控的环境,并在该环境下度量请求处理器的延迟和请求的总延迟。此外,他们将Node.js的堆大小增加到32GB。他们观察到,在实验过程中请求处理器的延迟和堆大小始终保持不变,但请求总延迟和CPU占用率持续增加。
接下来,他们用CPU火焰图和Linux的Perf Events工具分析CPU使用情况。在仔细分析火焰图(如下图)后,工程师们发现图中很多方框指向Express.js的router.handle和router.handle.next函数。

深入研究Express.js代码库后,工程师们发现:
- 所有端点的路由处理器(route handler)保存在一个全局数组里
- Express.js采用递归遍历所有路由处理器直至找到正确的处理器并调用
正如Yunong所述:
在这种情况下全局数组并不是理想的数据结构。不知道为什么Express.js不采用例如map这样的查询时间为常数的数据结构。更有甚者,数组是递归遍历的。这就解释了为什么会在火焰图里看到这么高的堆。有趣的是,Express.js甚至允许你给单个路由设置多个相同的路由处理器,比如:[a, b, c, c, c, c, d, e, f, g, h]。
请求路由c时,程序会在第一次出现c处理器的位置终止(数组中下标为2的位置)。但是请求d时只会在数组下标6的位置停止,其实不必花费时间遍历a,b和多个c。
为了更清楚地了解Express.js怎么样存储路由,工程师们创建了如下示例:
var express = require('express');
var app = express();
app.get('/foo', function (req, res) {
res.send('hi');
});
// add a second foo route handler
app.get('/foo', function (req, res) {
res.send('hi2');
});
console.log('stack', app._router.stack);
app.listen(3000);
以上代码产生如下结果:
stack [ { keys: [], regexp: /^\/?(?=/|$)/i, handle: [Function: query] },
{ keys: [],
regexp: /^\/?(?=/|$)/i,
handle: [Function: expressInit] },
{ keys: [],
regexp: /^\/foo\/?$/i,
handle: [Function],
route: { path: '/foo', stack: [Object], methods: [Object] } },
{ keys: [],
regexp: /^\/foo\/?$/i,
handle: [Function],
route: { path: '/foo', stack: [Object], methods: [Object] } } ]
从运行结果可以推断出Express.js没有正确地处理重复的路由处理器。Yunong指出:“注意到对于路由/foo,有两个完全一样的路由处理器。更好的方式是,当路由处理器链中出现一个路由有多个路由处理器的情况时,Express.js抛出错误。”
深入分析应用源码后,工程师们发现一个周期函数是出现重复路由器的罪魁祸首。这个函数每小时执行10次,而其目的是为了从外部刷新路由处理器。当团队修改了程序,使得函数不再增加重复的路由处理器后,高延迟和燃烧CPU的问题就随之消失了。
经历这一插曲后,Yunong总结了团队得出几个结论:
首先,在程序投入使用前我们要完全清楚它们的依赖关系。我们没有对Express.js的代码库做深入分析就对它做出了错误的假设,导致我们错误地使用了Express.js的API,这才是造成性能问题的根本原因。
其次,在处理性能问题时,可观测性是极其重要的。火焰图帮助我们洞悉程序的CPU占用情况。如果不能抽样并用火焰图可视化Node.js堆栈使用情况,我无法想象该怎样解决我们的问题。
为了进一步提升可观测性,我们正在迁移到Restify。Restify能提供更好的透视性、可视化以及对应用更好的控制。
查看英文原文:Netflix Burned By Express.js
原帖地址:http://www.infoq.com/cn/news/2014/12/expressjs-burned-netflix
英文中介绍的排查过程比较详细,上中文可以一起来看,收益匪浅
express 调优的一个过程和心得,不错的文章的更多相关文章
- 《高性能SQL调优精要与案例解析》一书谈SQL调优(SQL TUNING或SQL优化)学习
<高性能SQL调优精要与案例解析>一书上市发售以来,很多热心读者就该书内容及一些具体问题提出了疑问,因读者众多外加本人日常工作的繁忙 ,在这里就SQL调优学习进行讨论并对热点问题统一作答. ...
- 小程序组件化框架 WePY 在性能调优上做出的探究
作者:龚澄 导语 性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中.因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用.因此必须另开辟蹊径找出适合小程序的调估方式. 本文 ...
- Informatica_(6)性能调优
六.实战汇总31.powercenter 字符集 了解源或者目标数据库的字符集,并在Powercenter服务器上设置相关的环境变量或者完成相关的设置,不同的数据库有不同的设置方法: 多数字符集的问题 ...
- SQL Server调优系列进阶篇(如何索引调优)
前言 上一篇我们分析了数据库中的统计信息的作用,我们已经了解了数据库如何通过统计信息来掌控数据库中各个表的内容分布.不清楚的童鞋可以点击参考. 作为调优系列的文章,数据库的索引肯定是不能少的了,所以本 ...
- SQL调优
# 问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...
- Java性能优化权威指南-读书笔记(二)-JVM性能调优-概述
概述:JVM性能调优没有一个非常固定的设置,比如堆大小设置多少,老年代设置多少.而是要根据实际的应用程序的系统需求,实际的活跃内存等确定.正文: JVM调优工作流程 整个调优过程是不断重复的一个迭代, ...
- Oracle调优总结(经典实践 重要)
转载:http://langgufu.iteye.com/blog/1974211 Problem Description:1.每个表的结构及主键索引情况2.每个表的count(*)记录是多少3.对于 ...
- SQL Server调优系列进阶篇 - 如何索引调优
前言 上一篇我们分析了数据库中的统计信息的作用,我们已经了解了数据库如何通过统计信息来掌控数据库中各个表的内容分布.不清楚的童鞋可以点击参考. 作为调优系列的文章,数据库的索引肯定是不能少的了,所以本 ...
- Spark&Spark性能调优实战
Spark特别适用于多次操作特定的数据,分mem-only和mem & disk.当中mem-only:效率高,但占用大量的内存,成本非常高;mem & disk:内存用完后,会自己主 ...
随机推荐
- 【转】B2C电子商务系统设计精选
B2C电子商务系统研发——促销引擎设计(一)(Promotion Engine) B2C电子商务系统研发——商品SKU分析和设计(一) B2C电子商务系统研发——商品SKU分析和设计(二) 电商后台系 ...
- SQL---->mySQl数据库1------数据库的增删改查备份恢复
1.在终端输入:mysql -uroot -p 然后输入密码,进入客户端 2.输入:\s 3.创建数据库 3.1创建字符集是utf-8的数据库 3.2创建带校验规则的数据库,校验规则可以在a ...
- VM+CentOS+hadoop2.7搭建hadoop完全分布式集群
写在前边的话: 最近找了一个云计算开发的工作,本以为来了会直接做一些敲代码,处理数据的活,没想到师父给了我一个课题“基于质量数据的大数据分析”,那么问题来了首先要做的就是搭建这样一个平台,毫无疑问,底 ...
- Database Sharding Challenges DATABASE SHARDING
w分布式查询.数据聚合.跨碎片join是可且应避免的.自增主键管理.基于-会话/事务/语句-选择碎片.通过-主键/模块/碎片索引-碎片化数据 http://www.agildata.com/datab ...
- jQuery中通过$.browser来判断浏览器
一.使用方法 语法:$.browser.["浏览器关键字"] $(function() { if($.browser.msie) { alert("this is IE& ...
- Strongly connected---hdu4635(强联通分量)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 先判断图是否强连通.如果不是强连通的,那么缩点. 我们的目的是加最多的边,那么最后的图中,肯定两 ...
- python 类 __module__ __class__
__module__ 和 __class__ __module__ 表示当前操作的对象在那个模块 __class__ 表示当前操作的对象的类是什么 创建一个目录lib 在day7 目录下创 ...
- Nginx 403 forbidden原因及故障模拟重现(转载)
这篇文章是转载过来的一篇文章,觉得不错,因此做个记录. 访问Nginx出现状态码为403 forbidden原因及故障模拟 1) nginx配置文件里不配置默认首页参数或者首页文件在站点目录下没有 i ...
- 基因芯片与NGS区别[转载]
转自:http://blog.sina.com.cn/s/blog_40d4ae110101fjzy.html 1 二代测序与基因芯片的区别与优缺点. 生物芯片相对第二代测序而言,优势在于价格便宜,便 ...
- eclipse-maven安装配置java-web-servlet
eclipse-maven安装配置java-web-servlet 系统说明: win7 64位 一. Maven安装 环境 要求 看Maven下载说明也行 jdk7.0以上 安装配置Maven 下载 ...