NGINX.COM
Web Server Load Balancing with NGINX Plus

本文转载自 The New Stack

WebAssembly(Wasm)之所以能够迅速崛起,是因为它是一种不受语言限制的浏览器运行时环境,可安全、快速地运行 JavaScript 以外的其他语言。虽然 Wasm 最初专为浏览器而设计,但开发人员已开始探索 Wasm 在后端的潜能——面向后端的 Wasm 为服务器和网络管理带来了诸多可能性。

NGINX 类似,许多服务器端技术都采用标准插件模型运行,该模型依赖于静态或动态地将链接对象文件注入在同一地址空间中运行的可执行文件。

不过,插件具有相当大的局限性。具体而言,它们只允许通过原生语言扩展程序来实现可扩展性,这就限制了开发人员对语言和语言特定功能的选择。其他插件必须遵循复杂的链接方法,这些方法要求服务器和客户端语言支持同一功能接口。对于插件的创建者而言,这会增加复杂性。

最后,一些插件通过动态语言和脚本层工作,虽然更易于使用,但会影响性能。动态脚本可能会引入抽象层并带来其他安全风险。例如,远程程序调用(RPC)必须解决网络通信、序列化和反序列化、错误处理、异步行为、多平台兼容性以及这些挑战引起问题时造成的延迟。虽然使用 RPC 的插件具有出色的灵活性,但也大大增加了复杂性。

 

Wasm 的优势:快速、安全、灵活

那么,究竟何为 Wasm?Wasm 是一种二进制格式和运行时环境,用于执行代码。简而言之,Wasm 是一种以近乎原生速度运行代码的低级别、高效和安全的方法。Wasm 代码可使用 C、C++、GolangRust 等高级编程语言编译而成。实际上,Wasm 不受语言限制,并具有可移植性。这一点变得越来越重要,因为部署和维护应用的开发人员日益倾向于尽可能使用单一语言编写应用(换句话说,更少使用 YAML)。

Wasm 通过支持更灵活、更易于管理的插件,开启了标准插件模型的无限可能。与现有插件模型相比,Wasm 有助于更轻松地让插件实现语言中立和硬件中立、模块化及隔离。这样,开发人员可以使用自己选择的语言,根据环境和用例在浏览器以外自定义行为。

Wasm 在实现这一切的同时,还保持了近乎原生代码级的性能,这得益于:

  • 紧凑的二进制格式小于等效的人类可读代码,因此下载和解析速度更快。
  • 更接近原生机器指令的指令集,支持更快地解析和编译为原生代码。
  • 支持强类型的超快 JIT,提供了更多的优化可能,可通过应用各种优化技术更快速地生成和执行代码。
  • 连续的可调整大小的线性内存模型,可简化内存管理,从而实现更高效的内存访问模式。
  • 并发和并行执行,可充分释放多核处理器(目前为 WIP)的性能。

Wasm 的设计初衷是在 Web 上运行不受信任的代码,它拥有一个特别强大的安全模型,其中包括:

  • 沙盒代码执行环境,限制其对系统资源的访问并确保它不会干扰其他进程或操作系统。
  • “内存安全”架构,有助于防止缓冲区溢出等常见安全漏洞。
  • 强大的类型系统,可执行严格的类型规则。
  • 与其他运行时相比,代码量小,减少了攻击面。
  • 字节码格式易于分析和优化,有助于更轻松地检测和修复潜在的安全漏洞。
  • 具有出色的可移植性,将针对不同平台重构代码的需要降至最低。

 

更灵活的插件构建方式

服务器端 Wasm 具有许多显著的潜在优势,包括主要优势和次要优势。首先,在 Wasm 环境中,标准应用开发人员能够更轻松地与后端系统进行交互。Wasm 还允许任何人员细粒度地控制函数在尝试与网络或服务器端应用的较低级别功能交互时的可为和不可为的事项。这一点至关重要,因为后端系统可能会与敏感数据交互,或者需要更高级别的信任。

同样,服务器系统可配置或设计为限制与 Wasm 插件环境的交互,方法是只明确导出有限的功能或只提供特定的文件描述符。例如,每个 Wasm 字节码二进制文件都有一个 imports 片段。在实例化之前,必须满足每项导入要求,以便主机系统注册(或在 Wasm 中,即导出)特定函数,从而作为系统进行交互。

当这些导入要求未能得到满足时,运行时引擎将阻止 Wasm 模块的实例化,便于主机系统保护、控制、验证和限制客户端与环境的交互。

如果使用更传统的插件模型和编译器技术,则很难实现这种细粒度和效用水平。由此带来的困难打消了开发人员制作插件的积极性,进一步限制了选择。最重要的一点是,基于角色的访问控制和基于属性的访问控制以及其他授权和访问控制技术可能会引入复杂的外部系统,这些系统必须与插件和底层服务器端技术同步。相比之下,Wasm 访问控制功能通常直接内置于运行时引擎中,有助于降低复杂性并简化开发流程。

 

展望美好的 Wasm 未来

未来,随着 Wasm 的普及,开发人员可更轻松地为其应用设计定制或半定制的配置和业务逻辑。此外,他们还能够将 Wasm 应用到服务器端,以消除后端、中端和前端之间的大量开发摩擦。

基于 Wasm 的插件未来将带来许多激动人心的优势:更轻松、更精细地微调应用性能,基于应用级指标执行特定扩展和策略触发等。

通过 warg.io,我们已经看到了 Wasm 如何推动使用创新的组合式方法来构建功能,以将现有的软件包管理和注册表方法应用于使用可信的 Wasm 代码元素进行构建。换句话说,Wasm 提供的组合式插件可能与开发人员组合使用多个 npm 模块来实现特定功能的方式并无二致。

应用开发人员和 DevOps 团队通常采用传统手段来提高应用性能。当出现延迟或其他问题时,他们有以下几种选择:

  1. 针对问题投入更多计算资源。
  2. 增加内存(并间接增加 I/O)。
  3. 调查代码,并尝试确定延迟问题的根源。

前两种选择可能成本高昂,最后一种选择则非常费力。有了 Wasm,开发人员可选择在 Wasm 结构内运行会拖慢性能的大部分应用组件或函数,并使用速度更快的语言或结构,而不必拆掉整个应用,并能够专注于处理难度低、见效快的工作(例如,使用 Wasm 内部编译的 C 代码或 Go 代码替换用于计算的慢速 JavaScript 代码)。

事实上,与 JavaScript 相比,Wasm 具有许多性能优势。正如原 Wasm 团队中来自 Mozilla 的 Lin Clark 所说

  • 获取 Wasm 的速度更快,因为它比 JavaScript 更紧凑,即使压缩后也是如此。
  • 解码 Wasm 的速度快于解析 JavaScript。
  • 由于 Wasm 比 JavaScript 更接近机器代码,而且已经在服务器端进行了优化,因此编译和优化花费的时间更少。
  • 代码执行速度更快,因为开发人员为编写一致的高性能代码而所需了解的编译器技巧和问题更少了。此外,Wasm 的指令集更适合机器使用。

展望未来,微服务将不再通过高开销的 Kubernetes API 服务器调用或内部东西向 RPC 进行编排,而是通过模块化、安全且高性能的 Wasm 组件在较小的进程空间和范围内进行编排。

过去,开发人员使用 YAML 等其他数据编码语言来调用自定义资源定义(CRD),并通过其他方式为 Kubernetes 中作为微服务运行的应用添加功能。这增加了开销和复杂性,加大了性能调优的难度。借助基于 Wasm 的插件,开发人员可充分利用成熟且可信的语言原语(Go、Rust、C++),而无需用更多 CRD 去做重复工作。

 

相关阅读

Hero image
免费 O'Reilly 电子书:
《NGINX 完全指南》

更新于 2022 年,一本书了解关于 NGINX 的一切

关于作者

Matthew Yacobucci

首席软件工程师

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。