Node.js,这个用于构建可扩展网络应用的服务器端 JavaScript 软件平台,在过去几年中一直受到许多开发者的追捧,尽管它的流行也激怒了一些其他人,他们发布了大量负面博客文章来指出其被认为的缺点。尽管如此,虽然新兴且未经考验,Node 仍在继续赢得更多拥护者。
2011 年,LinkedIn 加入了这场运动,当时它选择用 Node 重建其核心移动服务。这家专业的社交网站一直在依赖 Ruby on Rails,当时正在寻求性能和可扩展性的提升。凭借其对非阻塞原语和单线程事件循环的广泛使用,Node 看起来很有前景。
在 Ryan Dahl(现就职于 Joyent,该公司赞助并维护 Node)于 2009 年创建 Node.js 之后不久,开发者们就迅速抓住了它。由于 Node 使用 JavaScript,一种主要与 Web 应用客户端相关的语言,它为从事客户端工作的开发者也从事服务器端的相应功能扫清了道路。
Kiran Prasad 于 2011 年加入 LinkedIn 担任移动工程高级总监,他领导了公司向 Node 的转型。在服务器端,LinkedIn 的移动前端现在完全用 Node 构建。Prasad 承认 Node 并非适用于所有工作的最佳工具,但在分析 LinkedIn 的系统后,Prasad 和他的团队确定,提高效率所需的是一个事件驱动系统。Node 也被证明很有吸引力,因为它精简、轻量,同时允许直接操作数据对象。
Prasad 为他在 LinkedIn 移动服务部门的角色做好了充分准备,他在 Palm 和 Handspring 的 WebOS 平台上积累了多年的移动应用工作经验,此外还曾担任移动 Web 软件的独立开发者(担任 Sliced Simple 的 CEO 和 Aliaron 的 CTO)。
他在这里与 Kelly Norton 和 Terry Coatta 讨论了 LinkedIn 采用 Node.js 的情况。Norton 是最早参与 Google Web Toolkit (GWT) 的软件工程师之一,之后共同创立了 Homebase.io,该公司开发下一代营销工具。
Coatta 是 Marine Learning Systems 的 CTO,该公司开发了一个针对海运业的学习管理系统。他之前曾在 AssociCom、Vitrium Systems、GPS Industries 和 Silicon Chalk 工作过。
KELLY NORTON 告诉我们 LinkedIn 决定使用 Node.js 的原因。
KIRAN PRASAD 我们当时运行的是基于进程的 Ruby on Rails 系统,而且很明显,它无法以我们需要的规模进行扩展。我想,如果您愿意投入足够的资金,您总是可以扩展某些东西,但显然这似乎不是正确的方法。此外,使用移动模式(其中存在大量微连接),我们可以看到基于进程的方法在使用 Ruby on Rails 堆栈时会遇到困难。
我们还注意到,Rails 的性能损失相当大,因为我们进行了大量的字符串操作,而我们使用的 Ruby 解释器版本在垃圾回收所有小字符串对象时显得吃力。它也没有针对 JSON(JavaScript 对象表示法)转换进行特别优化,而 JSON 正是我们的后端提供给我们的,也是我们的前端希望消费的。
显然,Ruby on Rails 的构建更多的是作为一个 Web 堆栈,因为它的真正价值在于它为该结构提供的模板,以及它为应用程序和控制器提供的一些框架概念。但是,当您进行客户端渲染时(移动系统就是这种情况),控制器和视图实际上会移动到客户端。
在像 LinkedIn 这样规模更大、更高的堆栈中,您也会开始分解模型。也就是说,在那个时候您实际上并不在 Rails 的 Active Record 内部,因为您最终会下降到其他服务器或服务。这意味着中间层开始变得非常薄,并且真正专注于字符串操作。
因此,当我们真正开始研究它时,我们说:“这肯定感觉不再那么合适了。它不是为了完成我们现在尝试做的事情而设计的。”那么,我们可以用什么来代替它呢?它必须是事件驱动的,擅长字符串操作,并且轻便、快速且易于使用。我们开始研究 Ruby 中的一些事件驱动框架,例如 EventMachine,以及 Python 中的 Twisted。但是,当我们最初开始研究这个问题时,似乎没有主流的事件驱动 Java 框架。虽然 Play 现在变得越来越流行,但在我们进行分析时,即 2011 年初,由于某种原因它没有出现在我们的雷达上。
KN 但是除了事件驱动之外,Node 还有什么如此引人注目?
KP 我们研究了 Node 并对其进行了一些负载测试,在测试中,它会向大约六个其他服务发送请求,抓取数据,合并数据,然后以相当简单的方式将其弹出。我们一直运行到大约 50,000 QPS(每秒查询数)。在此过程中,我们发现 Node 大约比我们之前使用的快 20 倍,而且其内存占用也更小。
显然,Node.js 还提供了其他超越技术方面的优势。JavaScript 是一种很多人都理解并且可以轻松编码的语言。此外,Node 当时(现在仍然是)受到了很多炒作,这并没有什么坏处。在某些方面,这让我更容易招聘。
TERRY COATTA 您提到您已经放弃在 Ruby 中使用 Active Record 作为您的模型表示,但显然该模型最终必须去某个地方。为什么您没有选择使用您已经拥有的模型基础设施来处理中间件?
KP 模型的特点是它们实际上是围绕对象设计的。它们具有属性;它们具有方法;它们结构非常化且静态类型;并且您正在尝试创建一个环境,使它们非常稳固,以便您确切地知道每个对象是什么。这正是我们在第一次接触面向对象设计时被教导的方法。
因此,您可能会认为更面向对象的语言非常适合构建这样的系统。但是,然后它会移动到视图控制器,而在移动系统中,视图控制器会被一直推送到客户端。那么问题就变成了:中间还剩下什么?基本上,您在那里找到的只是一堆有效地操作数据哈希以格式化它们的函数。因此,现在您只剩下格式化和少量聚合。
我不确定当时我是否真的清楚地表达了我们为什么选择 Node.js。现在,在使用它几年后,已经非常清楚,在这个本质上是您的前端(现在字面上在客户端中)和您的后端(恰好是您的数据模型)之间的粘合层的层中,函数式语言实际上是最合适的。在这一点上,我们所有的后端 stuff 都是用 Java 编写的,而且我们使用的所有 Java 堆栈都更基于进程。
TC 那么,有了在中间层使用 Node.js 的这种经验,您会考虑将其用于后端吗?
KP 目前,我们正在创建一个特定于移动设备的数据存储,作为其中的一部分,我们分析了是否应该用 Node.js 和 JavaScript 构建它。结果证明,团队想要一些更精确或类型化的东西,我想是这样。我实际上正在努力避开经典的编程 stuff,例如采用更静态类型的方法,但团队绝对希望能够定义一个具有某些方法和属性的对象,并保证这一点,这样就不会有人把它搞砸。他们不希望任何人在那里接管该原型或对其进行任何操作。尽管如此,从性能的角度来看,我很想尝试一个更事件驱动的框架。目前,我们内部正在使用 Rest.li 来完成一些后端数据存储 stuff,因为我们真的相信事件驱动 stuff 已经改变了我们的架构。
TC 就您观察到的 Node.js 性能加速而言,您是否也为您正在考虑用于中间件层的其他语言构建了轻量级原型?
KP 我们使用事件驱动框架 EventMachine 和 Twisted 对 Ruby 和 Python 进行了一些原型设计。最重要的是,Node 在原始吞吐量方面被证明比两者都快 2-5 倍。更令人兴奋,真正让我们信服 Node 的是,编写 Node 原型只花了我们两到三个小时,而编写 EventMachine 和 Twisted 原型则花了我们大约一两天的时间,仅仅是因为我们必须下载更多的东西。
例如,您需要确保您没有使用 Python 中的标准 HTTP 库,而是使用了 Async HTTP 库。这种事情几乎普遍适用。无论我们想做什么,我们都不能使用标准的 Python 库。相反,我们必须使用特殊的 Twisted 版本。Ruby 也是如此。像社区中的许多其他人一样,我们发现使用 Node 入门要容易得多,您需要的一切基本上都在那里。此外,我们使用 Node 能够更快地启动 stuff,这真的很重要。那只是另一种形式的性能,对吧?开发人员的生产力绝对算数。
内存占用也是一个因素。我们研究了 VM(虚拟机)在这些语言中的工作效果,而 V8 JavaScript 引擎彻底击败了其他一切。我们在进行 50,000 QPS 的所有这些操作,并且我们在大约 20 到 25 MB 的内存中运行它。在 EventMachine 和 Twisted 中,仅仅加载所有必要的类来执行异步 stuff 而不是标准 stuff 就更像是 60 到 80 MB。仅从原始级别来看,Node 将仅在大约一半的内存占用中运行。
KN 您最终错过了哪些您在更“模型化”的环境中会拥有的东西?
KP 因为我们拥抱了 JavaScript 的函数式特性,所以我们认为我们首先不必将从后端传入的所有内容转换为一组对象以及这些对象上的一组方法。这也意味着我们不必理清这些对象的层次结构、子类是什么、基类是什么、所有这些东西是如何构造的以及所有这些不同对象之间的关系是什么。但这正是您在基于模型和对象的系统中需要做的事情。因此,对我们来说,它更像是说,“好的,您将访问这三个端点,然后您将合并数据并弹出另一个对象。”
但实际上,它不是对象,而是哈希,对吧?您正在消费相邻的东西,然后弹出一些其他相邻的东西。这几乎就像您有一个过滤器,您通过它运行一个流。数据通过并从另一侧弹出——这让您完全绕过了所有关于对象是什么、它们如何工作以及它们如何交互的思考。因此,这让我们更快地到达了我们想去的地方。
既然我们已经完成了,我们正在回顾并处理一些函数。现在,它们都与它们想要的任何东西对话。如果函数 A 想要与 Profile、Companies 和 Jobs 对话,然后合并它们,那么它就会直接与 Profiles、Companies 和 Jobs 对话。然后,如果函数 B 想要与 Profiles、Companies 和其他东西对话,它也会直接这样做。但是,函数 A 和 B 不会使用相同的功能接口来与 Profiles 或 Companies 对话。问题是,如果我们在与 Companies 对话的方式中存在错误,我将不得不在两个地方修复它。如果我想添加日志记录,以便我可以查看某人与 Companies 对话的所有实例,那么事情就不会集中化,以至于一切都会很好地漏斗下来。虽然我们没有创建对象层,但我们开始认识到,至少对于 RESTful API,我们需要创建一组函数,这些函数位于我们希望与之通信的每种资源类型的前面。这有点像代理该接口。这是我们一路走来学到的东西之一,现在我们开始通过创建这个新的抽象层来修复它。
TC 您提到重构代码以引入额外的层。如果您考虑一下您现在在重构方面投入的时间量,您是否认为您最终仍然会花费大致相同的时间来创建您的代码库,就像您采用其他方法一样?
KP 我猜不会,因为这不仅仅是编码本身需要多长时间。这还关乎流程的方方面面。例如,当您编写您的应用程序,然后键入“Node”来运行该应用程序时,它实际上只需要大约 20-100 毫秒才能启动。对于 Ruby,仅仅让 Rails 控制台启动有时就需要 15-30 秒。我也没有准备好说 Node 严格从编码的角度来看在任何情况下都存在不足。从各个方面来看,Node 的构建都更加精简、轻量、快速。因此,我每天做的每件小事、每个细微之处最终都会更快。
对于更结构化的语言,您必须考虑诸如编译时间和构建时间之类的事情。然后,您最终会构建本质上是热插拔环境,其中环境正在运行,但 IDE 也能够连接并操作运行时。您几乎必须这样做,因为它需要很长时间才能启动,进行更改,然后再启动。Node 消除了所有这些问题,仅仅是因为它太快了。
是的,重构增加了编码时间,同时也消除了我们最初在快速完成事情时所享受的简单性。但我认为,由于 Node 非常精简和轻量,我们能够实现的总体效率足以弥补我们必须做的任何少量重构。
TC 如果您要开始另一个基于 Node 的项目,您是否会在最初尝试构建更多的结构?
KP 我认为这不是一个特定于 Node 的问题。这更多的是个人偏好的问题。我自己的观点是,前端 UI 代码往往只能持续大约一年半到两年。很少有代码能持续五年到十年。我相信,造成这种情况的原因甚至与代码质量没有太大关系,而是更多地受到技术发展和鼓励软件开发人员以四年为增量工作这一事实的驱动。您不断有新人查看您的代码,而且我知道,每当我查看任何东西时,即使只是一张表格,我确信我可以构建一个更好的表格。因此,我相信自然的趋势是,每一年半到两年,一组新人都会查看一些特定的代码库,并决定他们可以做得更好。
鉴于此,只要它是模块化的——或者甚至重写整个东西——并承担一两个月的损失,可能比缓慢地发展代码库更快。因此,如果让我重新做这个项目,我可能会以相同的方式做。无论如何,我更倾向于先构建一个项目,将其发布,然后在稍后提取一个平台(如果可以的话)——而不是先构建一个完美的平台和所有组件,然后再尝试以正确的顺序将它们连接起来。我认为在您实际运行某些东西并可以看到您的痛点之前,您不可能知道正确的顺序是什么。然后您就可以知道您实际上需要在哪里提取库并开始做一些事情。
一旦决定转换为 Node,Prasad 的团队就必须弄清楚实施和维护的最佳方法。由于 LinkedIn 的移动服务团队在很大程度上习惯了 Ruby on Rails,他们在设置 Node.js 结构时模仿了他们之前的 Rails 结构的部分内容,这使他们能够快速启动项目。团队规模很小,因此 Prasad 能够监控向 JavaScript 的过渡并快速检测到问题。
使用 Node.js 进行编程是事件驱动的,因此需要不同的方法。尽管涉及少量重构,但团队不必创建新的抽象或额外的函数。他们所做的大部分本质上是句法上的。他们还减少了抽象层,这大大缩小了代码库的规模。
KN 您说您的偏好是直接投入到一个项目中,并以快速的方式做事。我完全同意。事实上,我想说我自己的理念是,既然您在进入项目时并不真正知道您需要优化什么,那么您真正应该着手优化的是您更改事物的能力。
所以我真的很想知道您是如何构建代码以及您使用了哪些实践来让您最初快速行动,然后在您的项目约束变得更加清晰时继续快速行动。
KP 当时我们很多人都是 Ruby on Rails 开发人员,所以他们熟悉 Rails 世界中的目录树结构和术语。我们模仿了该术语,这让我们获得了巨大的快速启动。Node 非常简洁,很像 Rails,这也很有帮助,但也有点可怕,因为您不确定如何构建 stuff,也没有指南告诉您如何做。
我们做出的第二个有帮助的决定是将所有控制器和视图放在客户端,而模型则放在后端。从目录结构的角度来看,这意味着我们的模型结构或视图目录中不会出现任何文件。虽然我们使用了术语控制器,但我们实际上更多地是在使用格式化程序,从某种意义上说,您会得到一些东西,发出几个请求,格式化该东西,然后将其弹出。
这意味着我们仍然拥有这个旧的 Rails 结构,只是大多数目录实际上是空的——顺便说一句,空目录实际上是一件好事。我们将目录留在那里只是为了防止人们尝试在该目录中创建东西。这就像一个代码审查工具,它说:“如果我们开始在该目录中创建东西,那一定是真的做错了什么。”这只是来自我们想要如何使用 Node 的服务器设计模式。
我们最初做的另一个有益的事情是建立一个基本的测试环境和框架。Rails 以及 Python 的 Django 框架都非常注重 TDD(测试驱动开发)甚至 BDD(行为驱动开发),您可以在填充所有代码之前基本上编写您的测试和序列。当存在测试框架时,这种模型效果非常好。我们基本上采用了已经存在的测试框架,并使用我们编写的一些脚本将其拍到我们的目录结构之上,以使两者进行交互。我们最初开始使用 Vows,但在三个月后最终用 Mocha 编写了我们自己的所有测试。
您可以说建立测试环境和框架是另一种代码模式,但它可能比使用任何其他语言都要困难——尤其是在处理 Node 的事件驱动方面。即使我们最终重构了代码,我们也没有必要做任何重大的事情,例如提出新的抽象或任何额外的函数。我们所做的大部分本质上是句法上的。然后还有一些小的功能性东西——例如,Node 的概念,即在每个回调中,第一个参数应该是 Error,这完全有道理。
但是,然后您无法弄清楚第二个、第三个和第四个参数是什么。或者您只有一个参数吗?还是有五个参数?您如何处理它,以及在您执行回调后它会是什么样子?假设您现在想要更改回调签名。您如何告诉每个调用该函数并期望回调的人签名已更改?我不知道这是否是 Node 特有的,还是 JavaScript 通用的,但我们确实花了一段时间才弄清楚。
KN 您的团队如何沟通接口边界?习惯于使用类型的人不希望放弃接口,因为它们提供了一种具体的文档形式,基本上允许一个团队成员对另一个团队成员说:“这是我的意图。我希望您会以这种特定的方式调用我。”更重要的是,如果事实证明这种调用方式不存在,那可能意味着这是一个您尚未考虑到的用例,因此可能无法工作。
KP 我认为代码内部的库之间以及客户端和服务器之间存在接口。对于客户端和服务器之间的接口,我们使用了 REST(具象状态传输),并且我们有一个非常明确的模型,我们在其中有所谓的“基于视图的模型”,这些模型由 Node 服务器返回。我们会记录这些模型并说:“嘿,这是 REST 接口,这是我们支持的内容。”这本质上与版本化的接口结构一致。实际上,它是经典的 REST。
在代码库中,我们大量使用了模块系统。每个 REST 端点都有一个文件,该文件表示该端点的所有响应,以及映射到路由的模块的公共接口。您可以拥有任意数量的函数,但无论您拥有什么,都将从该模块中导出。通过这种方式,您实际上最终指定了您要公开的函数集。这本质上就是我们用作接口的东西。
然后,在结构上,我们做了一些非常简单的事情:模块内部的每个函数,无论是公共的还是私有的,都以旧式的 C 风格定义。您可以放入一个注释,说明“private”,然后列出您的一些私有函数。或者您可以放入一个注释,说明“public”,然后列出您的所有公共函数。这就像您过去在 C 中所做的那样,对吧?您有一堆函数,您会将私有函数放在一组中,将公共函数放在另一组中。然后您的头文件将基本上公开您的公共接口。所有这些都发生在单个文件中。我们没有头文件,但 module.exports 有效地充当了我们的头文件。
KN 另一个重要的沟通考虑因素与帮助不习惯编写 JavaScript 的团队绕过他们可能遇到的某些雷区有关。
KP 当我们开始做这件事时,我们只有四个人,所以我能够观察到每一次代码提交。每当我看到任何奇怪的东西时,我都会询问它——不一定是因为我认为它是错误的,而是因为我想了解为什么我们使用了那种特定的模式。很容易弄清楚事情以某种方式完成的原因,并弄清楚我们接下来要做什么。现在团队规模大得多,我们正在渗透我们所做选择背后的推理细微之处,这绝对困难得多。现在,每当新人加入团队时,我们都会举办为期三到五天的训练营,这给了我们一个机会来解释,“这是我们做事的方式。我们知道这可能看起来有点奇怪,但这就是我们这样做的原因。”我认为这可能是暴露这些代码模式的最佳方式。
TC 您认为哪些代码模式最重要?
KP 我们最终使用 Step 作为我们的流程控制库。它就像一个超级简单的 Stem,带有两个主要构造。我们稍微增强了这些构造,并最终添加了第三个。基本上,Step 具有瀑布回调的概念,这意味着您将一个函数数组传递给 Step,然后它将按顺序调用每个函数,以便在第一个函数返回时,将调用第二个函数,依此类推。Step 保证了这个序列的顺序,因此即使函数是异步的——意味着它将执行某些事件驱动的操作——该函数也将被传递一个回调,并且它必须在完成其操作后调用一次。无论每个函数是同步的还是异步的,瀑布都将按顺序执行。
Step 还包括一个 group 方法和一个 parallel 方法。我们非常大量地使用 group 方法。这意味着您可以给它一组函数,它将并行执行所有这些函数,然后在所有这些函数都执行完毕后返回。
一个细微之处已经证明对我们来说非常重要。如果我们有一个包含三个函数的组,其中一个函数被破坏了,Step 将不会捕获其他两个函数的响应。相反,它只会调用回调并说,“对不起,我出错了。”
这个环境的负面之处在于,如果我调用六个东西,其中两个是必需的,而四个是可选的,我不会介意等待所有东西都带有一定的超时时间。但是,如果其中一个可选的东西最终出错,那么它看起来就像整个块都出错了。这对我们来说不太理想。因此,我们创建了一个名为 GroupKeep 的函数,该函数运行并执行所有内容,然后如果应该出现错误,它会将错误保存在一个数组中。这样,当回调的调用发出时,就会有一个错误数组。根据错误的位置,您可以很好地了解它是否与必需的东西或可选的东西有关。这使得编写可以在必要时继续进程的代码成为可能。
Node.js 的轻便和精简特性比其他任何东西都更吸引 Prasad 和他的团队。这允许的代码缩减程度被证明是巨大的——从 60,000 行减少到仅仅几千行。
他们现在基本上也没有框架,因此消除了大量不必要的代码。此外,Node 的事件驱动方法需要更少的资源,并将更多功能转移到客户端。最后,它采用了一种函数式方法,减少了抽象层。总而言之,这一切都有助于支持大量用户在各种设备上进行实时操作。
TC 当您谈到您管理初始 Node 原型启动并运行的速度有多快时,这让我怀疑您是否也实现了一些代码缩减。
KP 绝对的。我们的 Node 代码库从原始版本开始略有增长,但仍然在 1,000 到 2,000 行代码的数量级。相比之下,我们之前使用的 Ruby 代码库大约有 60,000 行代码。减少的最大原因是我们当前的代码库基本上是无框架的,这意味着其中没有太多的冗余代码。
第二个重要原因与我们现在采用的更偏向函数式的方法有关,而不是面向对象的方法,这对我们来说是一个重要的转变。在 Ruby 中,自然的倾向是创建一个对象,该对象本质上封装了每个通信和类型。尽管 Ruby 实际上是一种函数式语言,但它比 JavaScript 具有更强的类和对象的概念。因此,在我们早期的代码库中,我们有很多抽象层和对象,这些对象是在更大的组件化、可重构性和可重用性的幌子下创建的。然而,事后看来,我们实际上并不需要其中的大部分。
代码减少的另一个重要原因是 MVC(模型-视图-控制器)模型的推动,至少对于移动系统而非基于 Web 的系统而言是这样。以前,我们主要采用服务器端渲染。现在,随着模板和视图转移到客户端,以及当然还有渲染,很多代码都消失了。随之而来的是一种新的信任和信念,即后端(模型所在的位置)是进行验证和所有其他更高级操作的地方。这意味着不必重复检查,这又消除了大量的代码。
KN 您之前指出,导致您用 Node.js 重写的一个见解是,您意识到您实际上不需要深入理解您正在操作的对象,这意味着您不需要大量修改这些对象。基本上,您可以进行大量的哈希合并。您认为即使使用 Ruby 等其他语言,仅仅通过使用哈希映射原语,您也能达到相同的目的吗?
KP 可能是的,但如果您看看 Ruby,您会发现 Rails 中有很多额外的东西,而 Node 在其基础层面上就内置了 HTTP 服务器方面和客户端方面。这意味着您不需要 HTTP Node 模块和 HTTP 监听模块。
所以,是的,我想如果我们消除了所有对象层次结构,只使用哈希结构,我们或许可以使用 Ruby。但是那样您仍然需要监听 HTTP 并将其转换为控制器,这又会让您回到添加所有这些微层。虽然每个微层都为您提供了一堆您不必编写的代码,但它也增加了一堆您确实需要编写的东西的要求,以便一切都能与您的框架很好地协同工作。
TC 如果您要与即将开展类似项目的人交谈,您会指出什么并说,“嘿,注意这个,否则您会遇到麻烦”?
KP 流程控制。异常处理。虽然这实际上不是 Node 特有的,但我会说,“保持轻量级。保持简洁。” 我认为人们有一种自然的倾向,会说,“嗯,我需要一些可以处理 HTTP 的东西,所以我只需找到一个可以做到这一点的模块”,然后另外 4,000 行代码就会添加到他们的环境中,而他们真正需要的只是一个 HTTP 请求。相反,他们最终得到的是这个超级强大的东西,它不仅提供了这个功能,还提供了一大堆其他的东西。
基本上,Node 如此快速和如此出色的原因是它轻量级且简洁。它几乎没有任何东西,所以您添加到它的每一件小东西,您想要使用的每个额外的 Node 模块,都是有代价的。
KN 对于那些已经启动了 Node 项目的公司,您认为他们可能需要添加到其生态系统中的三个东西是什么,以使其更加强大?
KP 首先是一个好的 IDE。InteliJ IDEA 相当不错,但除此之外,我还没有真正看到适用于 Node 的出色 IDE 和工具集。
其次是允许不断发展的性能分析和监控。更好的 Node 运营监控会很棒,但目前它基本上是一个黑匣子,除非您将自己的监控钩子放入您的代码中。我很想看到 Java VM 中的 JMX 层提供的大部分功能。您可以通过这种方式获得一些非常有用的信息。
然后第三件事是像 New Relic for Node 这样的东西——它可以检查您的 Node 系统正在做的一切,并实际理解您的应用程序,以便它可以为您提供瓶颈和减速的详细分解。那将非常棒,实际上。
爱它,恨它? 让我们知道
[email protected]
© 2013 1542-7730/13/1200 $10.00
最初发表于 Queue vol. 11, no. 12—
在 数字图书馆 中评论这篇文章
Edward Steel, Yanik Berube, Jonas Bonér, Ken Britton, Terry Coatta - Hootsuite:追求响应式系统
当使用微服务时,框架和标准对于开发团队的重要性已变得显而易见。人们常常将微服务提供的灵活性误认为是每个服务都需要使用不同技术。像所有开发团队一样,我们仍然需要将我们使用的技术数量保持在最低限度,以便我们可以轻松培训新人、维护我们的代码、支持团队之间的调动等等。
Peter Christy - 评论:没有路线图的旅行
从广义上看,编程项目失败的次数远远多于成功的次数。在某些情况下,失败是迈向成功的一个有用的步骤,但通常情况下,它仅仅是失败。