Nginx为什么要造重复的轮子nginScript

前不久,Nginx发布了一种“代理端”的JavaScript实现nginScript。该实现可以提高Nginx的脚本能力,使Nginx配置更简单、操作更高效,使用户无需编写C模块就可以在Nginx中做更多的事情。目前,nginScript解析器仅支持ECMAScript 5的一个子集,不过后续还会扩展。在对JavaScript求值时,nginScript会使用一个基于寄存器的虚拟机将JavaScript编译成字节码然后在Nginx(或Nginx Plus)中运行。

许多人对此都非常好奇,既然已经有了V8、SpiderMonkey或其它实现,为什么还要实现一个新的JavaScript运行时。Hacker News上也出现了大量不同的声音。比如,网友stanleydrew就认为这个做法很糟糕,因为它可能让Nginx这个原本很棒的工具走上膨胀之路。对此,网友n42表示:

任何你不想用的特性都是膨胀,但用到的时候就必要了。

而网友eknkc则认为:

它是一个很好的补充。我在高业务量的服务器使用了Varnish,一个原因就是它有“可视化组件库”,这是一种类JavaScript的语言,可以用它来定义请求处理逻辑。nginx将为熟悉它的人提供许多配置选项。

针对这些疑惑和争论,Nginx近日专门撰文解释了他们为什么要创建自己的JavaScript实现。

Nginx有一些独特的需求,他们希望nginScript代码片段可以在Nginx处理请求时运行,以此扩展Nginx处理请求和响应的能力。但是,他们无意创建一个像Node.js那样的持久化的JavaScript应用程序运行时环境。

然而,现有的JavaScript运行时都是针对Web浏览器而设计的,依赖于垃圾收集,很难控制JavaScript VM的资源使用。如果内存溢出,它们就会异常退出。这在浏览器端尚可接受,但在服务器端是不可容忍的。他们希望nginScript能够提供简洁且可以快速执行的规则,而不是对JavaScript的完整支持。而且,Nginx已经有一个经过充分优化的、事件驱动的架构,所以他们不希望受垃圾收集所带来的性能不可预见性所影响。

出于上述种种考虑,他们实现了一种非常简单但与其需求相匹配的JavaScript运行时:

  • 架构——单线程、字节码执行是为了实现快速初始化和处理。由于每个请求会分配一个单独的虚拟机,所以不需要垃圾收集。虚拟机没有复杂的状态或辅助程序初始化,启动速度非常快。
  • 辅助函数——内置操作在Nginx本地实现,用户可以将nginScript视为一种通过编程驱动Nginx本地操作的方式。
  • 预占——Nginx事件驱动模型负责调度单个nginScript VM的执行。当nginScript规则执行阻塞操作时,Nginx会暂停那个虚拟机的执行,待事件完成后再重新调度。这意味着,用户可以采用一种简单线性的方式编写规则,Nginx会调度它们,而且不会有内部阻塞。

截止目前,nginScript尚处于早期开发阶段,当前版本为预览版,其团队一直致力于功能的构建,开发主要是围绕完成核心的语言实现以及实现许多内置的JavaScript对象(如Date、Math等)进行。因此,谈论nginScript的性能还为时过早。但测试表明,nginScript VM的性能同其它解释型语言(PHP、Ruby等)类似,但不如JIT实现快。同时,nginScript团队还专注于nginScript VM与Nginx的整合,比如,如何在Nginx配置中引用nginScript规则,nginScript如何访问和控制Nginx内部构件。对于长时间运行的脚本,他们可能还会引入垃圾收集。nginScript的完整路线图尚未形成,读者可以通过邮件列表分享自己的想法。

感谢郭蕾对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至[email protected]。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号:InfoQChina)关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群InfoQ好读者)。

你可能感兴趣的:(Nginx为什么要造重复的轮子nginScript)