原文 | Richard Lander

翻译 | 郑子铭

WebAssembly(Wasm)是一种令人兴奋的新虚拟机和(汇编)指令格式。 Wasm 诞生于浏览器,是 Blazor 项目的重要组成部分。 Wasm 的第二个行动是针对应用程序和功能的云计算。 WebAssembly 系统接口 (WASI) 是新的推动者,为 WebAssembly 代码提供了一种安全地跨语言调用和实现任意 API 的方法。现在可以使用 .NET 8 中的 wasi 实验工作负载通过 .NET 创建 WASI 应用程序。我们正在探索这些新技术并在此环境中运行 .NET 应用程序……。真的,任何地方。

这篇文章将帮助您了解 Wasm 的广泛使用,并描述 .NET 已经可以实现的功能。他们说历史不会重演,但会押韵。我们又回来进行另一轮“一次编写,随处运行”。 WASI 应用程序是可移植的二进制文件,可以在任何硬件或操作系统上运行,并且不特定于任何编程语言。这一次,感觉不一样了。这不仅仅是供应商的神经;一切都是中立的。

Wasm 和 WASI

Wasm 可能会为我们提供云计算的重启,并承诺提供单一云原生二进制文件、更高的密度和更便宜的多租户。出于同样的原因,它也开启了边缘计算的可能性。事实上,CloudFlareFastly 已经使用 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&amp;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&amp;color=%232EA043&amp;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扩展到云(一)的更多相关文章

  1. s3存储桶:s3可扩展的云存储

    S3(Simple Storage Service,简单存储服务),即可扩展的云存储,又称桶存储,S3 是一种面向 Internet 的存储服务.S3为任意类型的文件提供临时或永久的存储服务.用于存储 ...

  2. SuperEdge: 使用WebAssembly扩展边缘计算场景

    作者 SuperEdge 开发者团队 概要 SuperEdge 是 一个开源的分布式边缘计算容器管理系统,用于管理多个云边区域中的计算资源和容器应用. 在当前架构中,这些资源和应用能够作为一个 Kub ...

  3. 【Linux】扩展阿里云数据盘分区和文件系统

    扩容云盘只是扩大存储容量,不会扩容文件系统 一.准备工作 在扩展数据盘扩展分区和文件系统前,请提前完成以下工作. 创建快照以备份数据,防止操作失误导致数据丢失. 通过ECS控制台或者API扩容云盘容量 ...

  4. 基于 Golang 构建高可扩展的云原生 PaaS(附 PPT 下载)

    作者|刘浩杨 来源|尔达 Erda 公众号 ​ 本文整理自刘浩杨在 GopherChina 2021 北京站主会场的演讲,微信添加:Erda202106,联系小助手即可获取讲师 PPT. 前言 当今时 ...

  5. 译:Datetime类型的扩展

    译文出处:http://www.codeproject.com/Articles/870939/Datetime-Extensions 本文主要针对System.DateTime类型的一系列扩展.包括 ...

  6. 「译」用 Blazor WebAssembly 实现微前端

    原文作者: Wael Kdouh 原文链接:https://medium.com/@waelkdouh/microfrontends-with-blazor-webassembly-b25e4ba3f ...

  7. Python3.7+Django2.0.4配合Mongodb打造高性能高扩展标签云存储方案

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_141 书接上回,之前有一篇文章提到了标签云系统的构建:Python3.7+jieba(结巴分词)配合Wordcloud2.js来构 ...

  8. 基于AWS的云服务架构最佳实践

    ZZ from: http://blog.csdn.net/wireless_com/article/details/43305701 近年来,对于打造高度可扩展的应用程序,软件架构师们挖掘了若干相关 ...

  9. [译] 企业级 OpenStack 的六大需求(第 3 部分):弹性架构、全球交付

    全文包括三部分: 第一部分:API 高可用和管理以及安全模型 第二部分:开放架构和混合云兼容 第三部分:弹性架构和全球交付 需求 5 - 扩展.弹性和性能 企业级的内容很丰富.过去,企业级往往和高可靠 ...

  10. Windows Azure 安全最佳实践 - 第 6 部分:Azure 服务如何扩展应用程序安全性

    多种Windows Azure服务可以帮助您将应用程序安全性扩展到云. 有三种服务可提供多个提供程序之间的身份标识映射.内部部署数据中心间的连接和相互发送消息的应用程序功能(无论应用程序位于何处). ...

随机推荐

  1. C#设计模式03——简单工厂的写法

    什么是C#简单工厂? C#简单工厂是一种创建对象的设计模式,它定义一个工厂类来创建指定类型的对象,而不是在客户端代码中直接创建对象.简单工厂模式通常使用静态方法来生成对象,并且这些静态方法通常被称为工 ...

  2. CentOS下PHP7安装mysqlnd模块

    单独安装mysqlnd驱动 如果是centos下的yum安装方式,那么可以参考后续操作. 因为mysqlnd是mysql原生的驱动,如果已经安装了php-mysql,则需要先卸载,否则会遇到冲突. 先 ...

  3. [转帖]Oracle进程中的 LOCAL=NO 和 LOCAL=YES

    https://www.cnblogs.com/wjoyxt/p/3780860.html 我们在服务器上用sqlplus 连接数据库,在查看进程,会多出一条记录: oracle 16007 1600 ...

  4. Jmeter学习之八_测试kafka

    Jmeter学习之八_测试kafka 背景 最近在持续学习. 昨天学习了grafana展示Jmeter测试数据库的结果 今天想着能够测试一下kafka验证一下kafka的吞吐量等信息 说干就干的. 遇 ...

  5. [转帖]Linux | crontab定时任务及开机自启项

    本文总结如何使用 crontab 创建定时任务及开启自启项 1. 本文基于 CentOS 7.9 系统所写. Updated: 2022 / 9 / 5 Linux | crontab定时任务及开机自 ...

  6. 使用buildx在x86机器上面编译arm64架构的Docker镜像

    buildx 多架构编译 安装docker 下载docker 下载buildx 安装架构支持 docker run --privileged --rm tonistiigi/binfmt --inst ...

  7. [转帖]【JVM】类文件结构

    Class文件的定义 一组以8字节为基础单位的二进制流, 各个数据项目严格按照顺序紧凑排列在class文件中, 中间没有任何分隔符,这使得class文件中存储的内容几乎是全部程序运行的程序. 注:Ja ...

  8. 拜占庭将军问题和 Raft 共识算法讲解

    作者: 京东物流 郭益如 导读 在分布式系统中, 什么是拜占庭将军问题?产生的场景和解决方案是什么?什么是 Raft 共识算法?Raft 算法是如何解决拜占庭将军问题的?其核心原理和算法逻辑是什么?除 ...

  9. 微信小程序之某个节点距离顶部和底部的距离 createSelectorQuery

    这个方法可以用来在上滑滚动的时候,让某一个区域置顶, 在下滑的时候,又变为原来的位置哈! <huadong :class="{'hident':isFixed}" id=&q ...

  10. Why gRPC ?

    gRPC(gRPC Remote Procedure Call)是由 Google 开发的开源 RPC 框架,它基于 HTTP/2 标准,使用 Protocol Buffers 作为接口定义语言(ID ...