【译】使用.NET将WebAssembly扩展到云(一)
原文 | Richard Lander
翻译 | 郑子铭
WebAssembly(Wasm)是一种令人兴奋的新虚拟机和(汇编)指令格式。 Wasm 诞生于浏览器,是 Blazor 项目的重要组成部分。 Wasm 的第二个行动是针对应用程序和功能的云计算。 WebAssembly 系统接口 (WASI) 是新的推动者,为 WebAssembly 代码提供了一种安全地跨语言调用和实现任意 API 的方法。现在可以使用 .NET 8 中的 wasi 实验工作负载通过 .NET 创建 WASI 应用程序。我们正在探索这些新技术并在此环境中运行 .NET 应用程序……。真的,任何地方。
这篇文章将帮助您了解 Wasm 的广泛使用,并描述 .NET 已经可以实现的功能。他们说历史不会重演,但会押韵。我们又回来进行另一轮“一次编写,随处运行”。 WASI 应用程序是可移植的二进制文件,可以在任何硬件或操作系统上运行,并且不特定于任何编程语言。这一次,感觉不一样了。这不仅仅是供应商的神经;一切都是中立的。
Wasm 和 WASI
Wasm 可能会为我们提供云计算的重启,并承诺提供单一云原生二进制文件、更高的密度和更便宜的多租户。出于同样的原因,它也开启了边缘计算的可能性。事实上,CloudFlare 和 Fastly 已经使用 Wasm 在边缘托管公共计算。
Wasm 与在 Linux 容器中运行应用程序不同,后者是对现有标准和代码的(良好且聪明的)重新打包。 Wasm 更像是在没有操作系统的环境中运行应用程序,只有汇编代码、内存和对外部世界的标准化(和门控)访问(通过 WASI)。
Build 2023 上的 Hyperlight 演示(4m 视频)深入了解了支持 Wasm 的云的外观。它演示了在新的轻量级安全虚拟机管理程序中运行的 Blazor 应用程序。 Hyperlight 激发了新托管范例的想象力。
WebAssembly 系统接口 (WASI)、WebAssembly 接口类型 (WIT) 和 WebAssembly 组件模型是最新一轮 Wasm 创新的关键规范。它们基本上仍处于设计阶段并正在经历重大变化。这篇文章(以及 .NET 8 实现)以 WASI Preview 1 为中心。我们希望 .NET 9 实现使用 WASI Preview 2。
WIT 和 wit-bindgen 使用任何源语言编写的组件都可以与主机系统进行通信。 WIT 对 C# 支持的实现由 @silesmo 领导。 Wasm 和 WIT 一起定义了应用程序二进制接口(ABI)。
我们期望 WASI 成为一组标准的 WIT 类型,提供对低级功能的访问(例如获取时间和读取文件)。这些低级类型有效地形成了跨编程语言和操作系统的“Wasm 标准库”。例如,我们从来没有 Rust 开发人员和 .NET 开发人员可以同时使用的标准和共享功能。历史上还没有任何广泛部署的本机代码公开具有 OO 形状(如接口)的 API,可以跨编程语言和操作系统使用。
标准 WIT 类型以 wasi- 开头,定义“平台”。您可以将它们视为与 .NET 中的系统命名空间类似的方式(与 WASI 中的“S”匹配)。继续类比,您可以在 System 命名空间之外创建自己的 .NET 命名空间,WIT 也是如此。
这些帖子在更详细地构建 WASI 方面做得非常出色。
即将到来的承诺是能够采用现有的 .NET 应用程序或库并将其编译为 Wasm 目标。我们的设计本能是在 .NET 堆栈中实现相对较高的 WIT 接口(例如为 wasi-sql 创建 ADO.NET 数据提供程序),这将使现有代码(包括许多现有的 NuGet 包)能够正常工作,特别是对于没有本机依赖项。
Wasm 应用程序在 Wasm 运行时中运行,例如 wasmtime。与 Docker 非常相似,您可以使用特定功能配置该运行时。例如,如果您希望 Wasm 代码能够访问键/值存储,您可以向其公开一个键/值接口,该接口可以由本地数据库或云服务支持。
Wasm 运行时旨在可嵌入到应用程序中。事实上,有一个 wasmtime 包用于在 .NET 应用程序中托管 Wasm。 .NET 代码可以作为 Wasm 运行,但 .NET 应用程序可以托管 wasmtime?!?是的,这个空间开始看起来是圆形的。虽然这些场景看起来很循环,但它们最终可能非常有用,与 AppDomain 的使用方式大致相似。这也让人想起所有“docker in docker”场景。
我们期待更多的创新、更多的 Wasm 运行时和更多的行业参与者。事实上,Wasm 已经升级为 W3C 规范。 W3C 是 Wasm 的完美家园,让它成长为广泛的行业规范,就像之前的 HTML 和 XML 一样。
wasi-实验工作量
.NET 8 包含一个名为 wasi-experimental 的新工作负载。它构建在 Blazor 使用的 Wasm 功能之上,将其扩展为在 wasmtime 中运行并调用 WASI 接口。它还远未完成,但已经实现了有用的功能。
让我们从理论转向演示新功能。
安装 .NET 8 SDK 后,您可以安装 wasi-experimental 工作负载。
dotnet workload install wasi-experimental
注意:此命令可能需要管理员权限,例如在 Linux 和 macOS 上使用 sudo。
您还需要安装 wasmtime 来运行您即将生成的 Wasm 代码。
使用 wasi-console 模板尝试一个简单的示例。
$ dotnet new wasiconsole -o wasiconsole
$ cd wasiconsole
$ cat Program.cs
using System;
Console.WriteLine("Hello, WASI Console!");
$ dotnet run
WasmAppHost --runtime-config /Users/rich/wasiconsole/bin/Debug/net8.0/wasi-wasm/AppBundle/wasiconsole.runtimeconfig.json
Running: wasmtime run --dir . -- dotnet.wasm wasiconsole
Using working directory: /Users/rich/wasiconsole/bin/Debug/net8.0/wasi-wasm/AppBundle
Hello, WASI Console!
该应用程序使用 wasmtime 运行。这里没有 x64 或 Arm64,只有 Wasm。
dotnet run 提供额外的信息(在控制台输出中)来帮助解释发生了什么。未来这种情况可能会改变。与主机系统的所有交互均由 wasmtime 管理。
我们可以更深入地查看 AppBundle 目录。
$ ls -l bin/Release/net8.0/wasi-wasm/AppBundle
total 24872
-rwxr--r-- 1 rich staff 11191074 Oct 31 07:53 dotnet.wasm
-rwxr--r-- 1 rich staff 1526128 Oct 11 14:00 icudt.dat
drwxr-xr-x 6 rich staff 192 Nov 19 19:35 managed
-rwxr-xr-x 1 rich staff 48 Nov 19 19:35 run-wasmtime.sh
-rw-r--r-- 1 rich staff 915 Nov 19 19:35 runtimeconfig.bin
drwxr-xr-x 2 rich staff 64 Nov 19 19:35 tmp
-rw-r--r-- 1 rich staff 1457 Nov 19 19:35 wasiconsole.runtimeconfig.json
$ ls -l bin/Release/net8.0/wasi-wasm/AppBundle/managed
total 3432
-rw-r--r-- 1 rich staff 27136 Nov 19 19:35 System.Console.dll
-rw-r--r-- 1 rich staff 1711616 Nov 19 19:35 System.Private.CoreLib.dll
-rw-r--r-- 1 rich staff 5632 Nov 19 19:35 System.Runtime.dll
-rw-r--r-- 1 rich staff 5120 Nov 19 19:35 wasiconsole.dll
SDK 将应用程序发布到独立部署中。 .NET 运行时 — dotnet.wasm — 已经编译为 Wasm(在我们的构建机器上)。应用程序和 dotnet.wasm 在 wasmtime 中一起加载,运行所有代码。应用程序的实际托管代码(位于托管目录中)在运行时解释,就像 Blazor WebAssembly 一样。 @yowl 和 @SingleAccretion 社区成员一直在尝试 Wasm 和原生 AOT。
您可能想知道为什么我们需要将所有这些文件分开,而显然更好的选择是拥有一个 wasiconsole.wasm 文件。我们也可以这样做,但稍后会在帖子中介绍它,因为我们需要在机器上安装更多的软件(目前 wasi 实验工作负载不包含这些软件)。
RuntimeInformation 告诉我们什么?
RuntimeInformation 是我最喜欢的类型之一。它让我们更好地了解目标环境。
我们可以稍微更改示例以显示一些更有用的信息。
using System;
using System.Runtime.InteropServices;
Console.WriteLine($"Hello {RuntimeInformation.OSDescription}:{RuntimeInformation.OSArchitecture}");
Console.WriteLine($"With love from {RuntimeInformation.FrameworkDescription}");
它产生这个输出。
Hello WASI:Wasm
With love from .NET 8.0.0
第一行很有趣。操作系统是WASI,架构是Wasm。这是有道理的,有更多的背景。文章前面提到 Wasm 可以被认为是“无操作系统”,但是我们不能简单地称之为 Wasm,因为现有的浏览器和 WASI 环境有很大不同。因此,该环境唯一一致的名称是 WASI,而 Wasm 明确是“芯片架构”。
Wasm 是一个 32 位计算环境,这意味着 2^32 字节是可寻址的。但是,Wasm 运行时可以配置为使用 memory64,从而可以访问 >4GB 的内存。我们还没有对此的支持。
访问主机文件系统
Wasmtime(和其他 Wasm 运行时)提供将主机目录映射到来宾目录的选项。从用户的角度来看,这与使用 Docker 进行卷挂载类似,但实现细节有所不同。
让我们看一个依赖目录安装的简单应用程序。它使用 Markdig 包将 markdown 转换为 HTML。公平地说,Markdig 并不是为了以 Wasm 的身份运行而编写的。只要能够为其创建一个舒适的管理环境,Markdig 就会很高兴,这就是我们所做的。
让我们在 Mac M1 (Arm64) 机器上尝试一下。
$ pwd
/Users/rich/git/wasm-samples/tomarkup
$ dotnet publish
$ cd bin/Release/net8.0/wasi-wasm/AppBundle
$ cat run-wasmtime.sh
wasmtime run --dir . dotnet.wasm tomarkup $*
$ ./run-wasmtime.sh
A valid inputfile must be provided.
$ wasmtime run --dir . --mapdir /markdown::/Users/rich/markdown --mapdir /tmp::/Users/rich dotnet.wasm tomarkup $* /markdown/README.md /tmp/README.html
$ ls ~/*.html
/Users/rich/README.html
$ cat ~/markdown/README.md | head -n 3
# .NET Runtime
[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/runtime/runtime?branchName=main)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=129&branchName=main)
$ cat ~/README.html | head -n 3
<h1>.NET Runtime</h1>
<p><a href="https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=129&branchName=main"><img src="https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/runtime/runtime?branchName=main" alt="Build Status" /></a>
<a href="https://github.com/dotnet/runtime/labels/help%20wanted"><img src="https://img.shields.io/github/issues/dotnet/runtime/help%20wanted?style=flat-square&color=%232EA043&label=help%20wanted" alt="Help Wanted" /></a>
--mapdir 正在挂载从主机到来宾的目录。
如您所见,Markdown 文件已转换为 HTML。为了简洁起见,显示了每个文件的前三行。
目录挂载所需的 CLI 手势目前有点不方便。这是我们需要在未来版本中考虑的内容。这实际上是一个 dotnet run 和 wasmtime run 应该如何关联的问题。
但它能算字数吗?
我最近出版了《System.IO 的便利》,重点关注字数统计。我们能否获得与 Wasm 相同的代码来运行并看看它的运行速度有多快?
该文章中的字数统计基准测试在 Linux x64 上运行。让我们保持不变,但这次以 Wasm 身份运行。
$ pwd
/Users/rich/git/convenience/wordcount/count
$ grep asm count.csproj
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<WasmSingleFileBundle>true</WasmSingleFileBundle>
$ dotnet publish
$ cd bin/Release/net8.0/wasi-wasm/AppBundle/
$ WASMTIME_NEW_CLI=0 wasmtime run --mapdir /text::/home/rich/git/convenience/wordcount count.wasm $* /text/Clarissa_Harlowe
11716 110023 610515 /text/Clarissa_Harlowe/clarissa_volume1.txt
12124 110407 610557 /text/Clarissa_Harlowe/clarissa_volume2.txt
11961 109622 606948 /text/Clarissa_Harlowe/clarissa_volume3.txt
12168 111908 625888 /text/Clarissa_Harlowe/clarissa_volume4.txt
12626 108593 614062 /text/Clarissa_Harlowe/clarissa_volume5.txt
12434 107576 607619 /text/Clarissa_Harlowe/clarissa_volume6.txt
12818 112713 628322 /text/Clarissa_Harlowe/clarissa_volume7.txt
12331 109785 611792 /text/Clarissa_Harlowe/clarissa_volume8.txt
11771 104934 598265 /text/Clarissa_Harlowe/clarissa_volume9.txt
9 153 1044 /text/Clarissa_Harlowe/summary.md
109958 985714 5515012 total
我更新了项目文件以包含 wasi-wasm 和 true 并注释掉 PublishAot 相关属性。我还添加了一个runtimeconfig.template.json 文件。未对应用程序代码进行任何更改。
现在,我们将整个应用程序放在一个文件包中。
$ ls -l bin/Release/net8.0/wasi-wasm/AppBundle/
total 6684
-rw-r--r-- 1 rich rich 1397 Nov 19 19:59 count.runtimeconfig.json
-rwxr-xr-x 1 rich rich 6827282 Nov 19 19:59 count.wasm
-rw-r--r-- 1 rich rich 915 Nov 19 19:59 runtimeconfig.bin
-rwxr-xr-x 1 rich rich 27 Nov 19 19:59 run-wasmtime.sh
drwxr-xr-x 2 rich rich 4096 Nov 19 19:59 tmp
看起来好多了。该应用程序只有不到 7MB。我必须安装 WASI-SDK 才能使用 WasmSingleFileBundle 属性并设置环境变量以使 dotnetpublish 能够找到所需的工具。
$ echo $WASI_SDK_PATH
/home/rich/wasi-sdk/wasi-sdk-20.0/
wasmtime 最近发生了重大变化。我选择使用 WASMTIME_NEW_CLI=0 来恢复运行示例的旧行为。
让我们回到性能。首先,作为 wasm 运行(通过解释器执行托管代码):
$ time WASMTIME_NEW_CLI=0 wasmtime run --mapdir /text::/home/rich/git/convenience/wordcount count.wasm $* /text/Clarissa_Harlowe
11716 110023 610515 /text/Clarissa_Harlowe/clarissa_volume1.txt
12124 110407 610557 /text/Clarissa_Harlowe/clarissa_volume2.txt
11961 109622 606948 /text/Clarissa_Harlowe/clarissa_volume3.txt
12168 111908 625888 /text/Clarissa_Harlowe/clarissa_volume4.txt
12626 108593 614062 /text/Clarissa_Harlowe/clarissa_volume5.txt
12434 107576 607619 /text/Clarissa_Harlowe/clarissa_volume6.txt
12818 112713 628322 /text/Clarissa_Harlowe/clarissa_volume7.txt
12331 109785 611792 /text/Clarissa_Harlowe/clarissa_volume8.txt
11771 104934 598265 /text/Clarissa_Harlowe/clarissa_volume9.txt
9 153 1044 /text/Clarissa_Harlowe/summary.md
109958 985714 5515012 total
Elapsed time (ms): 821
Elapsed time (us): 821223.8
real 0m0.897s
user 0m0.846s
sys 0m0.030s
现在有了我们对 Wasm 的(甚至更多)实验性原生 AOT 支持。
$ time WASMTIME_NEW_CLI=0 wasmtime run --mapdir /text::/home/rich/git/convenience/wordcount count.wasm $* /text/Clarissa_Harlowe
11716 110023 610515 /text/Clarissa_Harlowe/clarissa_volume1.txt
12124 110407 610557 /text/Clarissa_Harlowe/clarissa_volume2.txt
11961 109622 606948 /text/Clarissa_Harlowe/clarissa_volume3.txt
12168 111908 625888 /text/Clarissa_Harlowe/clarissa_volume4.txt
12626 108593 614062 /text/Clarissa_Harlowe/clarissa_volume5.txt
12434 107576 607619 /text/Clarissa_Harlowe/clarissa_volume6.txt
12818 112713 628322 /text/Clarissa_Harlowe/clarissa_volume7.txt
12331 109785 611792 /text/Clarissa_Harlowe/clarissa_volume8.txt
11771 104934 598265 /text/Clarissa_Harlowe/clarissa_volume9.txt
9 153 1044 /text/Clarissa_Harlowe/summary.md
109958 985714 5515012 total
Elapsed time (ms): 60
Elapsed time (us): 60322.2
real 0m0.107s
user 0m0.064s
sys 0m0.045s
现在,在 Linux x64 上使用 CoreCLR 运行:
$ time ./app/count ../Clarissa_Harlowe/
11716 110023 610515 ../Clarissa_Harlowe/clarissa_volume1.txt
12124 110407 610557 ../Clarissa_Harlowe/clarissa_volume2.txt
11961 109622 606948 ../Clarissa_Harlowe/clarissa_volume3.txt
12168 111908 625888 ../Clarissa_Harlowe/clarissa_volume4.txt
12626 108593 614062 ../Clarissa_Harlowe/clarissa_volume5.txt
12434 107576 607619 ../Clarissa_Harlowe/clarissa_volume6.txt
12818 112713 628322 ../Clarissa_Harlowe/clarissa_volume7.txt
12331 109785 611792 ../Clarissa_Harlowe/clarissa_volume8.txt
11771 104934 598265 ../Clarissa_Harlowe/clarissa_volume9.txt
9 153 1044 ../Clarissa_Harlowe/summary.md
109958 985714 5515012 total
Elapsed time (ms): 77
Elapsed time (us): 77252.9
real 0m0.128s
user 0m0.096s
sys 0m0.014s
这些都是有趣的结果。我们有解释、AOT 和 JIT 代码生成方法可供比较。 Wasm 解释器能够在不到一秒的时间内计算(略低于)一百万个单词,而 AOT 编译的 Wasm 和 JIT 运行时可以在大约 100 毫秒内完成同样的操作。
注意:Main 方法是运行 main 的时间,由 StopWatch 测量。流程是整个流程的持续时间,以时间来衡量。
此图表显示了上下文中的所有结果,包括 System.IO 的便利性帖子中的结果。
wasmtime JIT 将 Wasm 代码编译到目标环境(在本例中为 Linux+x64)。例如,可以使用 wamr 对 Wasm 代码进行 AOT。我将把它留到另一篇文章中。
原文链接
Extending WebAssembly to the Cloud with .NET
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 (MingsonZheng@outlook.com)
【译】使用.NET将WebAssembly扩展到云(一)的更多相关文章
- s3存储桶:s3可扩展的云存储
S3(Simple Storage Service,简单存储服务),即可扩展的云存储,又称桶存储,S3 是一种面向 Internet 的存储服务.S3为任意类型的文件提供临时或永久的存储服务.用于存储 ...
- SuperEdge: 使用WebAssembly扩展边缘计算场景
作者 SuperEdge 开发者团队 概要 SuperEdge 是 一个开源的分布式边缘计算容器管理系统,用于管理多个云边区域中的计算资源和容器应用. 在当前架构中,这些资源和应用能够作为一个 Kub ...
- 【Linux】扩展阿里云数据盘分区和文件系统
扩容云盘只是扩大存储容量,不会扩容文件系统 一.准备工作 在扩展数据盘扩展分区和文件系统前,请提前完成以下工作. 创建快照以备份数据,防止操作失误导致数据丢失. 通过ECS控制台或者API扩容云盘容量 ...
- 基于 Golang 构建高可扩展的云原生 PaaS(附 PPT 下载)
作者|刘浩杨 来源|尔达 Erda 公众号 本文整理自刘浩杨在 GopherChina 2021 北京站主会场的演讲,微信添加:Erda202106,联系小助手即可获取讲师 PPT. 前言 当今时 ...
- 译:Datetime类型的扩展
译文出处:http://www.codeproject.com/Articles/870939/Datetime-Extensions 本文主要针对System.DateTime类型的一系列扩展.包括 ...
- 「译」用 Blazor WebAssembly 实现微前端
原文作者: Wael Kdouh 原文链接:https://medium.com/@waelkdouh/microfrontends-with-blazor-webassembly-b25e4ba3f ...
- Python3.7+Django2.0.4配合Mongodb打造高性能高扩展标签云存储方案
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_141 书接上回,之前有一篇文章提到了标签云系统的构建:Python3.7+jieba(结巴分词)配合Wordcloud2.js来构 ...
- 基于AWS的云服务架构最佳实践
ZZ from: http://blog.csdn.net/wireless_com/article/details/43305701 近年来,对于打造高度可扩展的应用程序,软件架构师们挖掘了若干相关 ...
- [译] 企业级 OpenStack 的六大需求(第 3 部分):弹性架构、全球交付
全文包括三部分: 第一部分:API 高可用和管理以及安全模型 第二部分:开放架构和混合云兼容 第三部分:弹性架构和全球交付 需求 5 - 扩展.弹性和性能 企业级的内容很丰富.过去,企业级往往和高可靠 ...
- Windows Azure 安全最佳实践 - 第 6 部分:Azure 服务如何扩展应用程序安全性
多种Windows Azure服务可以帮助您将应用程序安全性扩展到云. 有三种服务可提供多个提供程序之间的身份标识映射.内部部署数据中心间的连接和相互发送消息的应用程序功能(无论应用程序位于何处). ...
随机推荐
- C#设计模式03——简单工厂的写法
什么是C#简单工厂? C#简单工厂是一种创建对象的设计模式,它定义一个工厂类来创建指定类型的对象,而不是在客户端代码中直接创建对象.简单工厂模式通常使用静态方法来生成对象,并且这些静态方法通常被称为工 ...
- CentOS下PHP7安装mysqlnd模块
单独安装mysqlnd驱动 如果是centos下的yum安装方式,那么可以参考后续操作. 因为mysqlnd是mysql原生的驱动,如果已经安装了php-mysql,则需要先卸载,否则会遇到冲突. 先 ...
- [转帖]Oracle进程中的 LOCAL=NO 和 LOCAL=YES
https://www.cnblogs.com/wjoyxt/p/3780860.html 我们在服务器上用sqlplus 连接数据库,在查看进程,会多出一条记录: oracle 16007 1600 ...
- Jmeter学习之八_测试kafka
Jmeter学习之八_测试kafka 背景 最近在持续学习. 昨天学习了grafana展示Jmeter测试数据库的结果 今天想着能够测试一下kafka验证一下kafka的吞吐量等信息 说干就干的. 遇 ...
- [转帖]Linux | crontab定时任务及开机自启项
本文总结如何使用 crontab 创建定时任务及开启自启项 1. 本文基于 CentOS 7.9 系统所写. Updated: 2022 / 9 / 5 Linux | crontab定时任务及开机自 ...
- 使用buildx在x86机器上面编译arm64架构的Docker镜像
buildx 多架构编译 安装docker 下载docker 下载buildx 安装架构支持 docker run --privileged --rm tonistiigi/binfmt --inst ...
- [转帖]【JVM】类文件结构
Class文件的定义 一组以8字节为基础单位的二进制流, 各个数据项目严格按照顺序紧凑排列在class文件中, 中间没有任何分隔符,这使得class文件中存储的内容几乎是全部程序运行的程序. 注:Ja ...
- 拜占庭将军问题和 Raft 共识算法讲解
作者: 京东物流 郭益如 导读 在分布式系统中, 什么是拜占庭将军问题?产生的场景和解决方案是什么?什么是 Raft 共识算法?Raft 算法是如何解决拜占庭将军问题的?其核心原理和算法逻辑是什么?除 ...
- 微信小程序之某个节点距离顶部和底部的距离 createSelectorQuery
这个方法可以用来在上滑滚动的时候,让某一个区域置顶, 在下滑的时候,又变为原来的位置哈! <huadong :class="{'hident':isFixed}" id=&q ...
- Why gRPC ?
gRPC(gRPC Remote Procedure Call)是由 Google 开发的开源 RPC 框架,它基于 HTTP/2 标准,使用 Protocol Buffers 作为接口定义语言(ID ...