技术控

    今日:104| 主题:49431
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Node 性能优化

[复制链接]
城府 发表于 2016-11-28 17:12:05
47 4

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
前言

  没有 profile 谈优化都是耍流氓,性能优化的大前提是 profile ,有数据才能找出程序慢在哪里了。
   本篇文章主要介绍 Node 后端的性能优化,前端的同学可以看看 Chrome 的 devtools https://github.com/CN-Chrome-...
  一、Web 应用优化

  性能的瓶颈往往在 IO
  IO 层优化

  磁盘 IO 为什么慢

  计算机里的常见 IO 有 :
  
       
  • CPU 一二级缓存
       
  • 内存
       
  • 硬盘
       
  • 网络
      
  硬盘的 IO 开销是非常昂贵的,硬盘 IO 花费的 CPU 时钟周期是内存的 41000000/250 = 164000 倍。
  所有在一般应用中,优化要首先考虑数磁盘 IO , 通常也就是数据层的优化,说到数据库优化,很多人第一时间会想到加索引,但是什么加了索引查询会变快呢?索引要怎么加才合适呢?
  为什么索引快

   关于索引的原理可以看看这篇文章, 索引原理 。索引快主要的原因是:
  
       
  • 索引占用空间更小,可以有效减少磁盘 IO 次数。
       
  •   索引可以使用方便快速查询的数据结构,如 b+树
      
  索引怎么加

   回到我们的主题, 没有 profile 谈优化都是耍流氓
  以 mongo 为例,mongo 是带有慢查询功能的。
   MongoDB 查询优化分析 这篇文章介绍了如何开启和使用 mongo 的慢查询功能。
  开启慢查询收集功能后,使用 db.system.profile.find().pretty() 语句可以查询到哪些语句的查询比较慢。以下面这个查询语句为例:
  [code]query new_koala.llbrandomredpackage query: { user_id: "56ddb33e23db696f89fdae2a", status: { $ne: 1 } }[/code]  查询条件是 user_id、status 两个,所以给这两个字段加上索引可以提高查询速度。
  当然,如果 mongo 没有是先开启慢查询,扫描一下 mongo.log 也是个办法。
  [code]grep '[0-9][0-9][0-9]ms' /var/log/mongodb/mongodb.log[/code]  这样就可以找出所有查询耗时大于100 ms 的记录。然后再对症下药即可。
  缓存大法好,有选择地用。

  上文有说到,内存 IO 比磁盘 IO 快非常多,所以使用内存缓存数据是有效的优化方法。常用的工具如 redis、memcached 等。
   缓存效果显著,所以很多时候一谈到优化,很多人就会想到加缓存,但是使用缓存是有代价的,你需要维护缓存的更新和失效,这是个 繁琐 的事情,用上了缓存后你会经常碰到缓存没有及时更新带来的问题。
  重要的事情说多几遍:
   缓存有副作用
   缓存有副作用
   缓存有副作用
   并不是所有数据都需要缓存, 访问频率高,生成代价比较高 的才考虑是否缓存,也就是说影响你性能瓶颈的考虑去缓存。
   而且缓存还有 缓存雪崩缓存穿透 等问题要解决。见 缓存穿透与缓存雪崩
  静态文件缓存

  静态文件如图片、js 文件等具有不变性,是非常适合做缓存的。
  常见的静态文件缓存服务有 nginx、vanish 等。
  代码层面优化。

  合并查询

  在代码这一块,常做的事情是将多次的查询合并为一次,消灭 for 循环,实际上还是减少数据库查询。例如
  [code]for user_id in userIds
     var account = user_account.findOne(user_id)[/code]  这类代码实际上可以改写成:
  [code]var user_account_map = {}   // 注意这个对象将会消耗大量内存。
user_account.find(user_id in user_ids).forEach(account){
    user_account_map[account.user_id] =  account
}
for user_id in userIds
    var account = user_account_map[user_id][/code]  这样就把 N 次的查询合并为一次。
  实际上还是为了减少 IO。
  关于过早优化

     性能优化的工作做多了以后,往往会陷入一个什么都想着去优化的状态,这样就可能陷入过早优化的深坑中。
   这里引用一下其他人的观点
    https://www.zhihu.com/questio...
   
Node 性能优化-1 (数据库优化,profile,计算机,Chrome,主题)
    二、内存泄露排查

  Node 是基于 V8 这个 js 引擎的,这里我们了解下 V8 里的内存相关的知识。
  V8 的 GC 垃圾回收机制

  V8 的内存分代

  在 V8 中,主要将内存分为新生代和老生代两代。新生代的对象为存活时间比较短的对象,老生代中的对象为存活时间较长的或常驻内存的对象。
  默认情况下,新生代的内存最大值在 64 位系统和 32 位系统上分别为 32 MB 和 16 MB。V8 对内存的最大值在 64 位系统和 32 位系统上分别为 1464 MB 和 732 MB。
  为什么这样分两代呢?是为了最优的 GC 算法。新生代的 GC 算法 Scavenge 速度快,但是不合适大数据量;老生代针使用 Mark-Sweep(标记清除) & Mark-Compact(标记整理) 算法,合适大数据量,但是速度较慢。分别对新旧两代使用更适合他们的算法来优化 GC 速度。
  详情参见《深入浅出 nodejs》5.1 V8 的垃圾回收机制与内存限制
  V8 的 GC log

  在启动程序的时候添加 --trace_gc 参数,V8 在进行垃圾回收的时候,会将垃圾回收的信息打印出来:
  [code]➜  $ node --trace_gc aa.js
...
[94036]       68 ms: Scavenge 8.4 (42.5) -> 8.2 (43.5) MB, 2.4 ms [allocation failure].
[94036]       74 ms: Scavenge 8.9 (43.5) -> 8.9 (46.5) MB, 5.1 ms [allocation failure].
[94036] Increasing marking speed to 3 due to high promotion rate
[94036]       85 ms: Scavenge 16.1 (46.5) -> 15.7 (47.5) MB, 3.8 ms (+ 5.0 ms in 106 steps since last GC) [allocation failure].
[94036]       95 ms: Scavenge 16.7 (47.5) -> 16.6 (54.5) MB, 7.2 ms (+ 1.3 ms in 14 steps since last GC) [allocation failure].
[94036]      111 ms: Mark-sweep 23.6 (54.5) -> 23.2 (54.5) MB, 6.2 ms (+ 15.3 ms in 222 steps since start of marking, biggest step 0.3 ms) [GC interrupt] [GC in old space requested].
...[/code]  V8 提供了很多程序启动选项:
              启动项     含义                   –max-stack-size     设置栈大小             –v8-options     打印 V8 相关命令             –trace-bailout     查找不能被优化的函数,重写             –trace-deopt     查找不能优化的函数           使用 memwatch 模块来检测内存泄露

  npm模块 memwatch 是一个非常好的内存泄漏检查工具,让我们先将这个模块安装到我们的app中去,执行以下命令:
  [code]npm install --save memwatch[/code]  然后,在我们的代码中,添加:
  [code]var memwatch = require('memwatch');[/code]  然后监听 leak 事件
  [code]memwatch.on('leak', function(info) {
console.error('Memory leak detected: ', info);
});[/code]  这样当我们执行我们的测试代码,我们会看到下面的信息:
  [code]{
start: Fri Jan 02 2015 10:38:49 GMT+0000 (GMT),
end: Fri Jan 02 2015 10:38:50 GMT+0000 (GMT),
growth: 7620560,
reason: 'heap growth over 5 consecutive GCs (1s) - -2147483648 bytes/hr'
}
mem[/code]  memwatch 发现了内存泄漏!memwatch 判定内存泄漏事件发生的规则如下:
  当你的堆内存在5个连续的垃圾回收周期内保持持续增长,那么一个内存泄漏事件被派发

   了解更加详细的内容,查看 memwatch
  使用 heapdump dump 出 Node 应用内存快照

  检测到了内存泄露的时候,我们需要查看当时内存的状态,heapdump 可以抓下当时内存的快照。
  [code]memwatch.on('leak', function(info) {
console.error(info);
var file = '/tmp/myapp-' + process.pid + '-' + Date.now() + '.heapsnapshot';
heapdump.writeSnapshot(file, function(err){
   if (err) console.error(err);
   else console.error('Wrote snapshot: ' + file);
  });
});[/code]  运行我们的代码,磁盘上会产生一些 .heapsnapshot 的文件到/tmp目录下。
  使用 Chrome 的开发者工具分析内存消耗

     heapdump 提供的内存快照是可以用 Chrome 的开发者工具来查看的。把 .heapsnapshot 文件导入到 Chrome Developer Tools

Node 性能优化-2 (数据库优化,profile,计算机,Chrome,主题)

123下一页
友荐云推荐




上一篇:[iOS] A Simple And Minimalist iOS AlertController
下一篇:写正则不要再瞎转义了
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

女圭女圭音せ 发表于 2016-11-28 20:42:46
路过,我是来打酱油的!
回复 支持 反对

使用道具 举报

RenatoLyki 发表于 2016-11-28 21:30:11
我也来顶一下..
回复 支持 反对

使用道具 举报

越qfjgc 发表于 2016-11-28 22:04:07
顶贴不认真,大脑有问题。
回复 支持 反对

使用道具 举报

cvzco 发表于 2016-11-28 22:45:34
楼上的很有激情啊!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表