[译] Node.js 之战: 如何在生产环境中调试错误

本文讲的是[译] Node.js 之战: 如何在生产环境中调试错误,

Node.js 之战: 在生产环境中调试错误

在这篇文章,这篇文章讲述了 Netflix、RisingStack 和 nearForm 在生产环境中遇到 Node.js 错误的故事 - 因此你可以此为鉴,避免犯上同样的错误。同时你将会学到如何调试 Node.js 的错误。

感谢来自 Netflix 的 Yunong Xiao、来自 Strongloop 的 NearForm 和来自 Shubhra Kar 的 Matteo Collina 对这篇文章的见解与帮助。

过去4年里,我们在 RisingStack 的生产环境中运行 Node 应用,积累了许多相关经验 - 感谢Node.js 咨询、学习和开发 的业务支持。

Netflix 和 nearForm 的 Node 开发团队都一样,我们都有把调试过程记录下来的习惯,因此整个开发团队 (现在是全世界的开发团队) 都可以从我们的错误中学习。

Netflix 与 Node 调试: 了解你的依赖库

让我们慢慢阅读我们的朋友 Yunong Xiao 在 Netflix 发生的故事。

Netflix 的开发团队发现他们的应用的响应时间在逐渐变长 - 他们部分终端的延迟每小时增加 10 ms。

同时,CPU 使用率的上升也反映了问题的存在。

Netflix debugging Nodejs in production with the Request latency graph

不同时间段请求的传输时间 - 图片来源: Netflix

一开始,他们调查是否是 request handler 造成其响应时间变长。

在隔离测试后,他们发现 request handler 的响应时间稳定在 1 ms 左右。

所以问题并不是这个,他们开始怀疑到底层,是不是栈出现了问题。

接下来 Yunong 和 Netflix 开发团队的尝试是这个 CPU 火焰图 和 Linux 性能事件

Flame graph of Netflix Nodejs slowdown

火焰图反映了 Netflix 的响应速度正在变慢 - 图片来源: Netflix

你可以从火焰图中看到的东西是

  • 它有一些很高的栈 (这代表有许多函数被调用)
  • 并且一些矩形很宽 (代表我们在这些函数中耗费了一些时间)

经过深入调查,开发团队发现 Express 的 router.handle 和 router.handle.next 有许多引用。

Express.js 的源代码揭示了一系列有趣的事情:

  • 所有终端的 Route handlers 都储存在一个全局数组中。
  • Express.js 递归地遍历并唤醒所有 handlers 直到它找到合适的 route handler。

在揭示谜题的解决方案前,我们需要知道更多的细节:

Netflix 的底层代码包含了每 6 分钟运行的定时代码,从拓展资源中抓取新的路由配置信息,更新应用的 route handlers 从而响应改变的信息。

这些是通过删除并添加新的 handlers 来实现的。意外的是,同时它再一次添加了相同的静态 handler - 甚至是以前的 API route handlers。这造成的结果是,响应时间额外增加了 10 ms。

从 Netflix 的错误中获取的教训

  • 一定要了解你的依赖库 - 首先,你必须在生产环境中使用它们之前,彻底地了解它们。
  • 可观察性是关键 - 火焰图帮助 Netflix 工程团队解决了问题。

从这里阅读整个故事: 火焰图中的 Node.js

当你最需要帮助时候的专家指引

商业化 Node.js,由 RisingStack 提供

了解更多

RisingStack CTO: "加密是要花时间的"

你可能已经听过我们的故事 拆分单体式应用的故事,我们的 CTO Peter Marton 把 Trace (我们的 Node.js 监控系统) 分离成多个微服务模块。

我们现在讨论的错误是 Trace 开发时的响应速度变慢:

作为一个在 PaaS 运行的 早期 Trace 版本,它通过公共云来与我们的其他服务通信。

为了确保我们的请求是完整的,我们决定对所有请求进行签名。为了实现这个,我们看了 Joyent 的 HTTP signing library。很棒的是,request 这一模块支持开箱即用的HTTP签名。

解决方案代价不仅很大,而且会对我们的响应速度造成不好的影响。

network delay in nodejs request visualized by trace

网络延迟增加了我们的响应时间 - 图片来源: Trace

从图中可看到,所给定的终端响应速度为 180 ms,然而对于总体来说,单独两个服务的网络延迟只是 100 ms。

一开始,我们 用 Kubernetes 转移 PaaS provider。我们希望响应速度会快一点,这样内部网络就会平衡。

我们的方法奏效了 - 终端的响应速度提高了。

然而,我们想要更好的结果 - 大幅度降低 CPU 的使用率。下一步是分析 CPU 的使用情况,就像 Netflix 的人们做的一样:

crypto sign function taking up cpu time

从截图可以看出,crypto.sign 函数消耗的 CPU 时间最多,每次请求花费 10 ms。为了解决这个问题,你有两种选择:

  • 如果你在可信任的环境中运行应用,你可以去除请求签名,
  • 如果你在不可信的环境中运行,你可以升级你的机器让它拥有更强大的 CPU。

从 Peter Marton 中获取的教训

  • 服务之间的终端信息传输会对用户体验有巨大的影响 - 尽可能的平衡内部网络。
  • 加密可能会消耗大量时间。

nearForm: 不要堵塞 Node.js 的事件循环

React 现在很流行。开发者在前端和后端都会使用它,甚至他们更进一步用它来构建同构的 JavaScript 应用。

然而,渲染 React 页面会让 CPU 有挺大的负担,当绘制复杂的 React 内容时会受到 CPU 限制。

当你的 Node.js 正在进行绘制,它会堵塞事件循环,因为它的行为都是基于同步的。

结果就是,服务器可能会毫无反应 - 当请求堆积起来,会把所有的负担都堆在 CPU 上。

更糟的是即使请求端已经关闭,请求仍然会被处理 - 仍然会对 Node.js 应用造成负担,nearForm 对此有解释 Matteo Collina

不仅是 React,大多数字符串操作也会这样。 如果你在构建 JSON REST APIs,你应该花心思在 JSON.parse 和 JSON.stringify

Strongloop(现在是 Joyent) 的 Shubhra Kar 对此解释是,解析和转化成 JSON 字符串的等消耗巨大的操作也会消耗大量时间 (同时在这期间会堵塞事件循环)。

functionrequestHandler(req, res) {
  const body = req.rawBody
  let parsedBody
  try {
    parsedBody = JSON.parse(body)
  }
  catch(e) {
     res.end(newError('Error parsing the body'))
  }
  res.end('Record successfully received')
}

简易的 request handler

这个例子展示了一个简易的 request handler,用来解析 body。对于内容不多的情况下,它运行的挺好 - 然而,如果 JSON 的大小要以兆来描述的话,可能会花费数秒的时间来执行 而不是在毫秒时间内执行。同理 JSON.stringify 也一样。

为了缓解这个问题,首先你要了解它们。为此,你可以用 Matteo 的 loopbench 模块,或者Trace 的事件循环度量功能。

通过 loopbench,如果请求没有被实现,你可以返回状态码 503 给负载平衡器。为了启用这项功能,你要使用选项 instance.overLimit。这样 ELB 或者 NGINX 可以在不同的后端中重试,这样请求有可能会被处理。

一旦你了解这个问题并理解它,你就能开始修正它 - 你可以通过平衡 Node.js 流或者改变正在使用的架构来进行修正。

从 nearForm 中获取的教训

  • 总要留心对 CPU 负担大的操作 - 这类的操作越多,在你的事件循环里对 CPU 造成的压力越大。
  • 字符串操作会对 CPU 造成巨大负担

在生产环境中调试 Node.js 错误

我希望 Netflix、RisingStack 和 nearForm 的例子会对你在生产环境中调试 Node.js 应用有帮助。

如果你想要了解更多,我建议看下最近这些文章,它们会加深你的 Node 知识:

如有任何疑问,请留下评论让我们知道!






原文发布时间为:2017年4月28日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-08-15 07:11:32

[译] Node.js 之战: 如何在生产环境中调试错误的相关文章

在生产环境中使用 NODEJS 一年记

本文讲的是在生产环境中使用 NODEJS 一年记, 本文是「我为什么弃 Python 从 Node.js」一文的续集.一年多前,我因为对 Python 的挫败,还想解释为什么转而尝试 Node ,故写下那篇文章. 一年后,公司内部的 CLI(命令行) 工具,客户项目以及我司产品的更新,这些都是我学到的.不仅仅是 Node,基本上对 JavaScript 也学到不少. 易学难精 Node 学起来很容易,尤其是对有 JavaScript 的基础的人.谷歌搜索一些入门教程,折腾一会儿 Express,

使用IBM性能分析工具解决生产环境中的性能问题

序言 企业级应用系统软件通常有着对并发数和响应时间的要求,这就要求大量的用户能在高响应时间内完成业务操作.这两个性能指标往往决定着一个应用系统软件能否成功上线,而这也决定了一个项目最终能否验收成功,能否得到客户认同,能否继续在一个行业发展壮大下去.由此可见性能对于一个应用系统的重要性,当然这似乎也成了软件行业的不可言说的痛 -- 绝大多数的应用系统在上线之前,项目组成员都要经历一个脱胎换骨的过程. 生产环境的建立包含众多方面,如存储规划.操作系统参数调整.数据库调优.应用系统调优等等.这几方面互

生产环境中的容器之工作流

本文讲的是生产环境中的容器之工作流,[编者的话]很多公司已经在生产环境里大规模使用容器.前一篇文章里介绍了Spotify,DramaFever,Built.io和IIIEPE如何以及为什么使用容器.本文继续深入讨论这几个公司的工作流. 构建应用程序以及管理pull请求 在生产环境使用容器的一大吸引人之处是创建无缝的开发到生产环境的能力,最先代码在开发人员的笔记本上,然后能够整体移动到测试环境,并且随后直接部署,而不会因为底层基础架构环境的改动而导致问题. IIIEPE怎么做 Luis Elizo

在生产环境中使用Docker必须注意的事情

本文讲的是在生产环境中使用Docker必须注意的事情,[编者的话]本文以最近非常火的希特勒怒喷Docker的视频为线索,详细分析了Docker存在的一些问题和弱点,以及在生产环境中使用Docker所要注意的方面.这些问题包括隔离性.镜像安全.Docker缺省配置.发布及部署:文章的最后分析了微软最近在容器支持方面的动作. 我们不能否认Linux容器是一个非常强大的概念,它组合了众多优秀的Linux内核功能和Docker开源工具,任何背景知识的开发者都很容易使用. 在2016年容器峰会上,Brya

生产环境中使用Docker Swarm的一些建议

本文讲的是生产环境中使用Docker Swarm的一些建议[编者的话]实践中会发现,生产环境中使用单个Docker节点是远远不够的,搭建Docker集群势在必行.然而,面对Kubernetes,Mesos以及Swarm等众多容器集群系统,我们该如何选择呢?它们之中,Swarm是Docker原生的,同时也是最简单,最易学,最节省资源的,至少值得我们多了解一下.本文将介绍一些非常实用的建议. [深圳站|3天烧脑式Kubernetes训练营]培训内容包括:Kubernetes概述.架构.日志和监控,部

IT生产环境中容器编排系统的五个最佳做法

本文讲的是IT生产环境中容器编排系统的五个最佳做法[编者的话]本文主要讲述了生产环境中使用容器编排系统需要注意的5个最佳做法. [深入浅出学习 etcd]etcd为分布式系统提供可靠.高效的配置管理服务,在Docker.Kubernetes.Mesos等平台中扮演了越来越重要的角色.作为2013年开始的项目,它还很年轻,官方文档中缺乏实现上全面.系统的介绍,本课程深入浅出地介绍了etcd的实现,并为运维和二次开发提供了系统的指导和建议. 如果您的企业IT运维组织结构已转移到Docker等容器技术

基于在生产环境中使用php性能测试工具xhprof的详解_php实例

xhprof 是facebook开源出来的一个php性能测试工具,也可以称之为profile工具,这个词不知道怎么翻译才比较达意.跟之前一直使用的xdebug相比,有很多类似之处.以前对xdebug有一些记录还可以供参考,但是它的缺点是对性能影响太大,即便是开启了profiler_enable_trigger参数,用在生产环境中也是惨不忍睹,cpu立刻就飙到high.而xhprof就显得很轻量,是否记录profile可以由程序控制,因此,用在生产环境中也就成为一种可能.在它的文档上可以看到这样一

详解将ASP.NET Core应用程序部署至生产环境中(CentOS7)_实用技巧

将ASP.NET Core应用程序部署至生产环境中(CentOS7) 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. 部署ASP.NET Core应用程序 配置Nginx 配置守护服务(Supervisor) 这段时间在使用Rabbit RPC重构公司的一套系统(微信相关),而最近相关检验(逻辑测试.压力测试)已经完成,接近部署至线上生产环境从而捣鼓了ASP.NET Core应用程序在CentOS上的部署

在生产环境中使用Apache Mesos和Docker

本文讲的是在生产环境中使用Apache Mesos和Docker,[编者的话]本文翻译自 IVO VERBERK博客,Docker容器软件已受到了从科技巨头到企业的广泛注意.但是,随着容器概念转变成为现实世界中的成熟技术,那么问题就变成了:怎么样才能快速把Docker应用于生产环境中呢? 介绍 在生产环境中安全有效地的运行Docker容器会有很多复杂的挑战.许多复杂性挑战都是在跨多主机间运行容器产生的.这些跨主机的容器可能需要保持或共享状态,也可能需要相互通信,还可能会随时消失.为了高容错性和可