通过小故事,了解多一点何谓 Node 高性能

hello~亲爱的看官老爷们大家好~最近身体抱怨,只好宅居家中天天啃书,将 Java 基础啃完一大部分。通过学习新语言,算是对以前 Node 底层部分一知半解的知识,有了较为全面的了解,因而有了这个可爱的小故事。

故事主要是简单地讲述何谓 Node 高性能,或者更应该说的是它低消耗,即同样硬件条件下能承载更多请求,由于能力所限,难免有错,还望不吝赐教。下面开始讲故事~希望你们喜欢:)

背景

某天,CPU 大表弟与 CPU 小表妹来到网关大表哥家做客,三人决定玩过家家打发时间。然而大表哥家并没有对应的玩具,于是,他们就地取材,找出了些玩具,并作出了如下规定:

  • 小熊玩偶是服务员,负责纪录客人,传递订单和提供菜品等服务。
  • 能上发条,到一定时间就会敲鼓的机器人是厨师。收到服务员送来的订单后上发条,上一半表示做雪糕,上全部表示煮汤,敲鼓后说明菜做好了。
  • 有一张名为资源的小桌子(最多容纳10只玩偶),只要是工作的服务员或厨师,就得放在小桌子上,反之则离开桌子。
  • 这是一间福利快餐店,客人不入店不给钱,服务更多客人才是目标,而客人则由网关大表哥看心情生成(即可能偶尔很多,偶尔根本就没有)。

设定完成,三人可以正式开始玩过家家啦!

各自的设计

大表弟选择提供 VIP 服务,每个客人来都提供一只小熊服务员为他服务,当客人来时只需在不同的小熊上身上贴上上当前客人的编号与菜式即可。

小表妹则用了不同的方案,她觉得大表弟的太浪费资源小桌子的位置了,只需要为所有客人都提供一个常驻的小熊服务员即可,客人来时在小熊那记录好不同客人的编号与菜式,多放厨师才能服务更多的客人。

在这样的场景下,你认为哪个设计更好呢?

相信大家都会认为小表妹的设计会更好。由于资源小桌子面积有限,表弟的设计,同时只能服务 5 位客人(5 只小熊与 5 只机器人);而表妹的设计则能服务 9 位客人(1 只小熊与 9 只机器人)。而从客人等待的时间上说,是相差无几的(慢的是厨师,而不是服务员)。

现在让我们回到编程的世界,厨师上发条炒菜即 I/O 操作,一般是新开一个线程。可以看到,CPU 很快,但 I/O 很慢(可以想象到,必然是表弟表妹在等待发条机器人敲鼓)。 表弟的设计其实是粗略的 Java 模型,每个请求到来之际则开出一个新线程(新的小熊)进行处理,碰到 I/O 操作则原地等待,但仍占着资源。而表妹的设计则是粗略的 Node 模型,无论多少个请求到来,均只有一个执行线程(只有唯一一只小熊)。当等待一个请求的 I/O 操作结果时,可以处理另一个请求的的 I/O 操作结果,能更充分地利用资源。

简而言之,在相同的硬件资源下(服务器配置、带宽等),Node 能用更少的资源(线程)处理相同数量的请求。也就是说,同样的硬件资源下 Node 能承载更多的请求。单个请求的响应时间也不会比 Java 慢。

不同的规则

表弟为此结果愤愤不平,于是他提议修改一下规则。如果客人要吃的是雪糕,那么用做一道加法作业题取代上发条的厨师如何。表妹表示同意,之后欢声笑语中打出GG。因为她发现,只要有客人点了雪糕,她就得停下来数手指,什么都干不了。而可恶的表弟虽然也是数手指,但只要有煮汤的请求,他能先停下来,新找一只小熊玩偶传递订单后再回去数手指,处理客人订单比她快。

如果说之前的规矩是 I/O 密集型的话,那么修改后处理雪糕订单就是 CPU 密集型了。可以看到,一旦 Node 涉及较为耗时的运算,处理请求的速度将直线下降。即使是不同的请求(如煮汤的),由于只有一个执行线程,都得等待运算完成后才能处理。而 Java 则不一样,尽管还是得等待运算结果,但由于它自身是多线程的,阻塞了做雪糕请求,并不影响煮汤请求的响应。忽略语言本身的运算能力,Node 的模型导致它在处理 CPU 密集型业务时不如 Java

值得一提的是,不用过分担心运算的问题。服务器的 CPU 相当快,正常业务逻辑,就算是套了两三层循环也不是特别大的问题,不一定就是性能瓶颈,不要未发现问题而先优化。一般而言,不涉及图形运算或大数据处理等业务,Node 处理起来还是没问题的。

小结

至此,煮家家的故事就讲得差不多了,希望让你明白到为何 Node 在处理 I/O 密集型业务时,显现出极高的性能,或者说更低的消耗。小故事有部分细节尚未展示出来,比如不为每个新请求创建线程,可以省下线程创建与销毁的开销。尽管可以通过线程池解决,但 Node 在负荷大量请求的情况下,较少地切换线程,减少上下文切换带来的开销,也是它高性能的一个原因。

但要注意,使用任何一种语言编写的服务器,在性能到达瓶颈之前,响应请求的速度都不会显著地快于其他语言。所谓 Node 高性能,其实更应该说的是它的低消耗。

而最后一点,Javascript 是单线程,但 Node 是多线程,它采用多进程的方式充分利用 CPU。这点不少同学都有点糊涂的~

感谢各位看官大人看到这里,知易行难,希望本文对你有所帮助~谢谢!