WebAssembly 组件模型 — 原因、方法和内容(第 1 部分)
原文作者:Timo Stark - F5 专业服务工程师
原文链接:WebAssembly 组件模型 — 原因、方法和内容(第 1 部分)
转载来源:NGINX 中文官网
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
如果您有兴趣开始使用 WebAssembly 组件模型,但面对庞大的生态系统不知从何处着手吗?如果是,那么本文正适合您!
在本文中,我们将分享一些经验和心得,它们是我们在向 NGINX Unit 中添加对 WebAssembly 组件模型的支持时所获得的——感谢我们强大而活跃的社区。
如果您已经熟悉 Wasm 生态系统,或者只是想了解如何编写代码,请关注本帐号,参考本系列博文的第二篇。
WebAssembly 组件模型和 NGINX Unit
在推出第一版 Unit Wasm 语言模块之后,我们做了许多工作。在 2023 年 9 月,我们说过:
我们将 WebAssembly 支持作为技术预览版推出,希望尽快代之以 WASI-HTTP 支持。
我们在 Unit 1.32.0 中做到了这一点。该版本支持将 WASI 0.2 API 和 wasi:http/proxy world 用作其主接口的 Wasm 组件。
此处注意,如果前面有你不熟悉的词汇,也不要担心。本文将介绍 WebAssembly (Wasm) 组件模型的概念,以及 WebAssembly 系统接口 (WASI) 在其中所扮演的角色,还将探讨“WebAssembly 接口类型”的意义。
正如之前的博文中所述,Wasm 运行时与 Wasm 模块通过共享内存以原始字节的形式共享数据。要理解此字节流,主机和 Wasm 模块必须如出一口,或者从技术上说,实现相同接口。NGINX Unit 的核心概念是创建一个与特定应用相关的 HTTP 请求的上下文,并与运行时共享内存中的这组字节。
这正是我们在 unit-wasm 中所做的。虽然学习如何向 Unit 添加 Wasm 支持既有趣也很有必要,然而这与实现或采用某一标准相去甚远,因此就需要 Wasm 组件模型上场了。
WebAssembly (Wasm) 组件模型明确了不同的 Wasm 模块或组件之间及其与运行时环境之间的通信方式。它建立了必须满足的特定契约,以确保编译到 Wasm 组件中的代码可以托管在兼容的运行时上,并在运行期间与其他 Wasm 组件无缝交换数据。
如需获取这一理论框架的应用示例,请查看 NGINX Unit 中的实现,它是典型的 Wasm 组件模型实例。
Wasm 组件模型的两个重要组成部分是 WebAssembly 系统接口 (WASI) 和 WebAssembly 接口类型 (WIT)。下面我们来详细了解一下这两个标准。
WASI 和 WIT
WASI 是 “WebAssembly System Interface(WebAssembly 系统接口)”的缩写,由 Wasmtime 项目推出,专为 Wasm 而设计。它是 Wasm 的可移植系统接口,支持访问多项操作系统的功能,包括文件和文件系统、套接字、时钟、随机数等。为什么需要它?
因为我们现在创建的 Wasm 组件是针对服务器端运行时而非基于浏览器的 Wasm 运行时(使用 Web API 或 JavaScript)。浏览器之外的代码需要一种方式来与底层系统通信。为了更好地理解 WASI 的作用,我们用 Rust 编写了一个非常简单的程序,它会输出 “Hello World”。
我们编写的代码可以编译成一个可执行的二进制文件。程序启动后,我们会看到命令行上输出“Hello World”。这背后其实是 POSIX 标准在发挥作用,它定义了系统调用。系统调用在不同操作系统上的工作方式不同。
WASI 为这些系统调用提供了一个抽象层,可供编译到 Wasm 的代码使用。兼容 WASI 的运行时能够处理该代码的执行。我们将在本系列博文第二篇的 Rust 教程中进一步介绍其实际应用。自 WASI 提案的 Preview2 开始,WASI-API 在 WIT 文件中进行定义。
WIT(Wasm 接口类型)是一种用于定义接口的描述性接口描述语言 (IDL),而非一种通用编码语言。编写的 WIT 文件不包含任何业务逻辑,只是纯粹的契约定义。多个接口可以进一步组合为 ”world”。虽然深入了解如何创建自己的 WIT 文件不是必需的,但有助于在构建组件时查找问题或排除故障。
Wasm 组件模型和 wasi:http/proxy world 使用的 WIT 文件由字节码联盟 (Bytecode Alliance) 创建和维护。截至本文撰写之时,使用它们的最佳方式是通过 Wasmtime 项目的 GitHub 代码库,以及进行手动拉取。
WIT 文件的一个有趣之处在于其版本控制系统。由于实现 Wasm 运行时的主机以及我们将要构建的组件都在为 WIT 文件定义的契约创建绑定,因此我们必须指向这些契约的同一版本,或者选择支持多个 WIT 文件版本的运行时。这值得再写一篇博文。现在,我们只考虑最新的稳定版本,它发布于 2024 年 2 月,标记为 WASI 0.2。该版本包括 wasi:cli world 和 wasi:http world。
在 WebAssembly 生态系统中,这些契约被称为 “world”,下文将使用这一术语。就 NGINX Unit 用例而言,我们的目标非常明确,那就是 wasi:http/proxy world。您可以将 wasi:http/proxy world 视为一组描述 HTTP 请求和响应的接口,包括所有数据(HTTP 方法、请求头、正文等)。如果您是老 Web 开发人员,这可能会让您想起 CGI。
NGINX Unit、Wasmtime 和 Rust — 运行时实现
经过上面的介绍,我们现在知道 WASI/WIT 在支持组件模型方面扮演重要角色。作为站点,Unit 必须实现 WIT 文件定义的 WASI HTTP 代理接口才能履行契约。对此我们早已知晓。那既然使用 Wasmtime 作为 Wasm 运行时,我们何不将此任务委托给运行时呢?
当然,完全可以!不过,有一个虽不起眼但很重要的细节:我们当时的实现完全是用 C 语言编写的,使用的是 Wasmtime C-API。遗憾的是,这些 API 缺乏支持组件模型的必要功能。
正如本文开头所述,只要找到对的人,心往一处想,再复杂的挑战均可迎刃而解。无论过去还是现在,Fermyon 都是我们极具价值的重要合作伙伴。经过一场 Slack 和 Zoom 深夜会议后,我们发现在 Wasmtime C-API 中添加对组件模型的原生支持过于复杂。此外,没有 bindgen 等自动化工具的帮助,使用 WIT 文件手动实现接口将需要大量维护工作。
在向 Fermyon 解释 NGINX Unit 的内部结件和当前基于 C 语言的语言模块的工作原理后,他们分享了一个支持 Wasmtime 的 Rust API 的基于 Rust 的 Unit 语言模块原型。再没有 C-API 的什么事了。
现在,我们准备好开始写代码了。
后续
在下一篇中,我们将介绍使用 Rust 和 WASI 0.2 API 创建 Wasm 组件的流程。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
MCP协议重大升级,Spring AI Alibaba联合Higress发布业界首个Streamable HTTP实现方案
本文作者:刘军、张宇,Spring AI Alibaba Contributor 文章摘要 MCP 官方引入了全新的 Streamable HTTP 传输层,对原有 HTTP+SSE 传输机制有重大改进。本文将: 详细解析 Streamable HTTP 的设计思想、技术细节以及实际应用。 详解 Spring AI Alibaba 开源框架提供的 Streamable HTTP Java 实现。 提供 Spring AI Alibaba + Higress 的 Streamable HTTP 完整可运行示例与讲解。 HTTP+SSE 原理及缺陷 在原有的 MCP 实现中,客户端和服务器通过两个主要通道通信: HTTP 请求/响应: 客户端通过标准 HTTP 请求发送消息到服务器 服务器发送事件(SSE): 服务器通过专门的 /sse 端点向客户端推送消息 主要问题 这种设计虽然简单直观,但存在几个关键问题: 不支持断线重连/恢复 当 SSE 连接断开时,所有会话状态丢失,客户端必须重新建立连接并初始化整个会话。例如,正在执行的大型文档分析任务会因 WiFi 不稳定而完全中断,迫使用户重...
- 下一篇
Java程序使用预处理语句的性能提升
Java程序使用预处理语句的性能提升 GreatSQL提供了对服务器端预处理语句(Prepared Statements)的支持。预处理语句可以利用了高效的客户机/服务器二进制协议。使用带有参数值占位符的预处理语句有以下好处: 每次执行时解析语句的开销更少。通常,数据库应用程序处理大量几乎相同的语句,只对语句中的文字值或变量值进行更改,如 SELECT 和 UPDATE 中的 WHERE,UPDATE 语句中的 SET 和 INSERT 语句中的VALUES。 防范SQL注入攻击。参数值可以包含未转义的SQL引号和分隔符。 本文编写Java程序,执行常规SQL语句和预处理语句,对比性能差异,量化预处理语句的性能提升。 1. 程序设计 通过Java程序进行DML操作,每次DML的数量是10万条,每50条一个提交批次。对比执行预处理语句和普通SQL语句,通过执行时间长短,判断执行的性能。 函数testInsertPerformance对比 INSERT 性能; 函数testUpdatePerformance对比 UPDATE 性能; 函数testSelectPerformance对比 SE...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作