关于luajit:什么是-LuaJIT为什么-Apache-APISIX-选择了-LuaJIT

3次阅读

共计 4295 个字符,预计需要花费 11 分钟才能阅读完成。

本文介绍了 LuaJIT 的高灵活性和高性能,以及 APISIX 作为云原生 API 网关抉择 LuaJIT 的起因。

作者杨陶,API7.ai 技术工程师。

原文链接

什么是 LuaJIT

定义

简略地说,LuaJIT 是 Lua 这种编程语言的实时编译(JIT,Just-In-Time Compilation)器的实现。
对于不太理解 LuaJIT 的读者,咱们能够将 LuaJIT 拆成 Lua 和 JIT 两个局部来了解。

Lua

Lua 是一种优雅、易于学习的编程语言,具备主动内存治理、残缺的词法作用域、闭包、迭代器、协程、正确的尾部调用以及应用关联数组进行十分实用的数据处理。本文不会波及 Lua 的语法,无关内容欢送浏览 Getting Started With Lua。

Lua 的设计指标是能与 C 或其它罕用的编程语言互相集成,这样就能够利用其它语言曾经做好的方面;而它提供的个性又恰好是 C 这类语言不太善于的,比方绝对于硬件层的高层形象,动静的构造,繁难的测试等等。其袖珍的语言内核和只依赖于 ANSI C 规范的特点,使之在各平台上的可移植性变得十分高。因而 Lua 不仅是一个能够作为独立程序运行的脚本语言,也是一个能够嵌入其它利用的嵌入式语言。

但此时的 Lua 还有传统脚本语言常见的两个问题:效率低和代码裸露。而 LuaJIT 引入的 JIT 技术可能无效地解决了这两个问题。

JIT

JIT(Just-In-Time Compilation),实时编译,是动静编译的一种模式。在计算机科学中,动静编译并不是惟一的编译模式,比方现今依然风行的 C 语言应用的就是另一种模式:动态编译。

须要指出的是,咱们也经常将 C 语言的这种与动静编译相同的编译形式称为提前编译(AOT,Ahead-of-Time Compilation),但二者并不是齐全对等的。AOT 仅是形容在执行程序前,将某种“高级”语言编译为某种“低级”语言的行为。其编译的目标语言并不一定特定于程序宿主机上的机器码,而是任意定义的。比方将 Java 编译为 C,或者将 JavaScript 编译为 V8 等等这些行为也会被视为 AOT。因为所有动态编译在技术上都是提前执行的,所以在这种特定的上下文中应用时,咱们能够将 AOT 视为与 JIT 相同的动态编译。

抛开这些繁杂的名词,想到动态编译的产物,你可能会发现,Lua 语言面临的问题也能够通过动态编译来解决。但事实上,这就失落了 Lua 作为脚本语言的劣势:热更新的灵活性和良好的平台兼容性。所以目前除了有非凡需要的脚本语言外,大部分脚本语言都在应用 JIT 尝试进步语言性能,比方 Chromium 平台上应用 V8 的 JavaScript 和应用 YJIT 的 Ruby。

JIT 尝试将 Lua 的动静解释和 C 的动态编译两者的优缺点相结合,在脚本语言的执行期间,通过一直地剖析正在执行的代码片段,编译或从新编译这段代码,以失去执行效率的晋升。此时,JIT 假如的指标是,由此失去的性能晋升可能高于编译或从新编译这段代码的开销。实践上说,因为可能进行动静地从新编译,JIT 在此过程中,能够针对正在运行程序的特定平台架构进行优化、减速,在某些状况下,能产生比动态编译更快的执行速度。

JIT 分为传统的 Method JIT 和 LuaJIT 正在应用的 Trace JIT 两种。Method JIT 是将每一个办法(Method)翻译为机器码;而如下图所示,更先进的 Trace JIT 假设“对只执行一两次的代码,解释执行比 JIT 编译执行要快”,以此为根据对传统 JIT 进行优化,具体表现为将频繁执行的代码片段(即热门路上的代码)认定为须要跟踪的代码,将这部分代码编译成机器码执行。

LuaJIT

而 LuaJIT(2.x 版本)在 Trace JIT 的根底上,集成了应用汇编编写的高速解释器和基于 SSA 并进行优化的代码生成器后端,大幅提高了 JIT 的体现,最终使得 LuaJIT 成为最快的动静语言实现之一。

除此之外,绝对于原生 Lua 中为了与 C 交互而须要编写 Lua 与 C 的简约绑定,LuaJIT 还实现了 FFI(内部函数接口,Foreign Function Interface)。该技术容许了咱们在不分明参数个数和类型的状况下,从 Lua 代码中间接调用内部的 C 函数和应用 C 的数据结构。由此性能,咱们也能够间接应用 FFI 实现所需的数据结构,而非 Lua 原生的 Table 类型,进一步在性能敏感的场景下,晋升程序运行的速度。无关应用 FFI 进步性能的技巧并非本文探讨的领域,更深刻的内容能够参阅 Why Does lua-resty-core Perform Better?。

总而言之,LuaJIT 在 Lua 语法的根底上,实现了迄今为止脚本语言中最快的 Trace JIT 之一,并提供了 FFI 等性能,解决了 Lua 效率低和代码裸露的问题,让 Lua 真正成为了高灵活性、高性能和超低内存占用的脚本语言和嵌入式语言。

与其它语言、WASM 的比照

绝对于 Lua 和 LuaJIT,咱们可能对其它的一些语言更加相熟,比方 JavaScript (Node.js),Python,Golang,Java 等。比照这些大众化的语言,咱们能够看到更多 LuaJIT 的个性和劣势,上面简略列举一些 Lua/LuaJIT 与这些语言的比照:

  • Lua 的语法设计是针对非软件工程师所设计的。所以像 R 语言一样,Lua 也领有数组下标从 1 开始等适宜普通人的设计。
  • Lua 非常适合作为嵌入式语言。Lua 自身领有一个轻量的 VM,而 LuaJIT 在增加各种性能和优化后,也依然很轻量。所以绝对 Node.js 和 Python 之类宏大的运行环境,LuaJIT 间接集成到 C 编写的程序中后也不会增大太多体积。因而,实际上 Lua 是所有嵌入式语言中使用量比拟大且支流的抉择。
  • Lua 也很适宜做“胶水”语言。相似 JavaScript(Node.js) 和 Python,Lua 也能很好地连贯不同的库和代码。但稍有不同的是,Lua 与底层生态的耦合性更高,所以在不同的畛域中,Lua 的生态可能并不通用。

WASM(Web Assembly)是一种新兴的跨平台技术。这种起初设计为补充而非取代 JavaScript 的技术,因为可能将其它的语言编译成 WASM 字节码,同时还能作为平安沙箱运行代码,使得越来越多的程序也在思考应用 WASM 作为嵌入或者胶水的平台。即便如此,Lua/LuaJIT 在比照新兴的 WASM 时,也依然有不少劣势:

  • WASM 的性能是受限的,无奈达到汇编的水准。广泛场景下的性能,WASM 必定好过 Lua,但与 LuaJIT 有所差距。
  • WASM 与宿主程序的数据传递效率比拟低。而 LuaJIT 能够通过 FFI 进行高效率的数据传递。

为什么 Apache APISIX 抉择 LuaJIT

只管上文形容了 LuaJIT 本身的诸多劣势,但对于大部分开发者而言,Lua 不是一门公众的语言,LuaJIT 更不是一个公众的抉择。那为什么 Apache 基金会所属的云原生 API 网关 Apache APISIX 还是抉择了 LuaJIT 呢?

作为云原生的 API 网关,Apache APISIX 兼具动静、实时、高性能等特点,提供了负载平衡、动静上游、灰度公布(金丝雀公布)、服务熔断、身份认证、可观测性等丰盛的流量治理性能。咱们能够应用 Apache APISIX 来解决传统的南北向流量,也能够解决服务间的东西向流量,还能够用作 k8s 的 Ingress Controller。

而这所有都建设在 Apache APISIX 所抉择的 NGINX 和 LuaJIT 技术栈之上。

LuaJIT 与 NGINX 联合带来的劣势

NGINX 是一个出名的高性能 HTTP、TCP/UDP 代理和反向代理的 Web 服务器。

但在应用中,咱们会发现很宜人的是,每次批改 NGINX 的配置文件后,都须要应用 nginx -s reload 从新加载 NGINX 配置。

不仅如此,频繁地应用该命令从新加载配置可能会造成连贯的不稳固,减少业务失落的可能性;而在某些状况下,NGINX 重载配置的机制也可能会造成旧过程的回收工夫过长,影响失常的业务。对于该问题的深刻探讨,能够浏览 为什么 NGINX 的 reload 不是热加载?,这里不进行深刻开展。

Apache APISIX 诞生的目标之一就是解决 NGINX 的动静配置问题,LuaJIT 的高灵活性、高性能和超低内存占用带来了这种可能性。
以最具普遍性的路由为例,Apache APISIX 通过在 NGINX 配置文件中只配置单个 location 作为主入口,而后续的路由散发则由 APISIX 的路由散发模块实现,以此实现了路由的动静配置。

为了实现足够高的性能,Apache APISIX 应用 C 编写了基于前缀树的匹配路由算法,并在此基础上应用 LuaJIT 提供的 FFI 编写了实用于 Lua 的接口。而 Lua 的灵活性,也使得 Apache APISIX 的路由散发模块,能够轻易地反对通过特定的表达式等办法,对同一前缀的上级路由进行匹配。最终在代替 NGINX 原生路由散发性能的前提下,实现了兼具高性能、高灵活性的动静配置性能。无关这部分性能的具体实现,能够查看 lua-resty-radixtree 和 route.lua。

另外,不只是路由,从负载平衡、健康检查,到上游节点配置、服务端证书,以及扩大 APISIX 能力的插件自身,都能在 APISIX 不重启的状况下从新加载。

同时,除了在应用 LuaJIT 进行插件等性能的开发,Apache APISIX 还反对了 Java、Go、Node、Python 以及 WASM 等多种形式开发插件,也让 Apache APISIX 的二次开发门槛大大降低,使 Apache APISIX 取得了丰盛的插件生态和沉闷的开源社区。

总结

LuaJIT 是 Lua 的实时编译器实现。

Apache APISIX 作为一个动静、实时、高性能的开源 API 网关,基于 NGINX 与 LuaJIT 带来的高性能、高灵便等个性,提供了负载平衡、动静上游、灰度公布、服务熔断、身份认证、可观测性等丰盛的流量治理性能。

目前 Apache APISIX 曾经来到了全新的 3.x 版本,并带来了更多的开源我的项目集成、云供应商集成,原生的 gRPC 反对,更多的插件开发方式抉择,以及服务网格反对等性能。欢送退出 Apache APISIX 社区,理解更多 LuaJIT 在云原生 API 网关中的利用。

对于 API7.ai 与 APISIX

API7.ai(干流科技)是一家提供 API 解决和剖析的开源根底软件公司,于 2019 年开源了新一代云原生 API 网关 — APISIX 并捐献给 Apache 软件基金会。尔后,API7.ai 始终踊跃投入反对 Apache APISIX 的开发、保护和社区经营。与千万贡献者、使用者、支持者一起做出世界级的开源我的项目,是 API7.ai 致力的指标。

正文完
 0