WebAssembly 是一种新的W3C规范,无需插件可以在所有现代浏览器中实现近乎原生代码的性能。同时由于 WebAssembly 运行在轻量级的沙箱虚拟机上,在安全、可移植性上比原生进程更加具备优势。同时资源消耗小、启动速度快的特点也非常适合Serverless的场景。开发者们开始探索WebAssembly在Serverless的应用场景。

WebAssembly 101

WebAssembly (WASM) 是一种可以在Web浏览器上运行的编译语言(如C/C++, Rust, Go)的技术方案。WebAssembly采用二进制字节码格式,运行在基于堆栈的虚拟机上。2017年2月28日,四大主流浏览器Chrome, Firefox, Safari和IE共同宣布 WebAssembly 的最小可行产品(MVP)已经完成。

相比JavaScript, 使用WebAssembly可以更高效地在Web浏览器中运行代码逻辑。

  1. 下载更快:相比类似功能的JavaScript代码,WebAssembly文件体积更小
  2. 解析更快:由于WebAssembly采用二进制的中间表示(Intermediate Representation),可以类比JVM的byte code。无需代码解析过程,可以实现毫秒级解码加载。
  3. 执行更快:由于 JavaScript 使用动态类型,编译器很难对代码实现深度优化;而WebAssembly采用静态类型,编译器可以高效优化;同时JavaScript采用垃圾回收机制,而WebAssembly指令更接近机器码,需要程序自己控制垃圾回收策略,相比自动垃圾回收效率可以更高。通常而言,WASM与JavaScript相比,可以实现30%性能提升,在复杂的计算逻辑中,会有更高的性能提升。同时由于减少了语言的动态性和采用静态内存处理,WebAssembly也更加适合要求可预测性能的计算场景。

WebAssembly作为社区标准,具有良好的可移植性。WebAssembly代码逻辑可以一致地运行在不同浏览器实现中,并与JavaScript或浏览器对象进行交互调用。WebAssembly也可以运行在非浏览器环境下。此外WebAssembly运行在一个沙箱化的执行环境中,严格遵守浏览器安全策略,具有良好的安全性。

函数计算 + WebAssembly 模块

Function as a Service(FaaS)是Serverless Computing的重要计算形态,它提供了事件驱动的编程模型,开发者只需编写和上传事件响应代码,而平台则会负责计算资源的弹性伸缩。

FaaS主要支持了 Node.js, Python, PHP等解释型语言,也支持Java, C#等编译型语言。由于在Node.js 8.0版本以后已经内置了WebAssembly运行时,在主流的FaaS环境可以通过Node.js实现调用WebAssembly模块的能力,比如在AWS LambdaCloudflare Worker

在FaaS中利用Node.js调用WebAssembly 模块,有以下优点

  1. 更好的性能 - 尤其是计算密集型任务
  2. 可移植性 - 为NPM编译原生代码是一个大坑,在FaaS中运行的原生代码则需要针对目标执行环境进行构建来保障兼容性。比如AWS Lambda中的原生代码需要依赖Amazon Linux构建;阿里云函数计算要求二进制代码基于Linux 4.4构建。而WebAssembly代码可以保证在不同的目标环境运行有一致的结果。
  3. 多语言支持 - 类似C/C++, Rust, Golang这样的已有业务代码可以通过编译成WebAssembly进行复用,比如可以直接将C编写的图像处理应用运行在函数计算中,而不受函数计算支持的现有运行时的限制。

我们也将做一个小实验,结合Rust和AssemblyScript两种语言在阿里云函数计算(FunctionCompute, FC)场景中体验WebAssembly。

环境准备

  • 安装并配置阿里云函数计算的 Serverless 应用部署的工具 Fun
  • 下载示例代码,git clone https://github.com/denverdino/fun-wasm
  • (可选) Rust环境需要安装 wasm-pack

利用Rust构建Serverless WebAssembly应用

Rust是Mozilla的一个新的系统级编程语言。Mozilla同时也是WebAssembly技术最重要的推动者,它基于WebAssembly发布了wasm-bindgen,目的提升 JavaScript 和 Rust 之间的互操作性,可以让 Rust代码能够与JavaScript一起使用。

本节参考了Scott Logic的文章,我们将利用wasm-bindgen,在FunctionCompute的Node.js运行时中运行基于Rust编译的WebAssembly代码。

$ cd rust-wasm

# 一个简单的Rust Hello World应用,利用wasm_bindgen声明与JavaScript代码的绑定
$ cat src/lib.rs
use wasm_bindgen::prelude::*; #[wasm_bindgen]
pub fn hello_world() -> String {
let mut string = String::new();
string.push_str("Hello, rust-wasm!");
return string;
} # 编译生成WebAssembly和NodeJS绑定
$ wasm-pack build --target nodejs # 简单的函数计算事件响应代码,在NodeJS中调用WebAssembly逻辑
$ cat index.js
const wasm = require("./pkg/rust_wasm");
var getRawBody = require('raw-body')
module.exports.handler = function (request, response, context) {
// get request body
getRawBody(request, function (err, body) {
response.setStatusCode(200);
response.send(wasm.hello_world());
});
} # Serverless应用部署模板,利用HTTP Trigger进行访问
$ cat template.yml
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
fun:
Type: 'Aliyun::Serverless::Service'
rust-wasm:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
CodeUri: ./
Description: 'http trigger demo!'
Runtime: nodejs8
Events:
http-test:
Type: HTTP
Properties:
AuthType: ANONYMOUS
Methods: ['GET', 'POST', 'PUT']

部署并测试

$ fun deploy
... Waiting for service fun to be deployed...
Waiting for function rust-wasm to be deployed...
Waiting for packaging function rust-wasm code...
package function rust-wasm code done, the number of files you have packaged is:11
Waiting for HTTP trigger http-test to be deployed...
methods: [ 'GET', 'POST', 'PUT' ]
url: https://xxxxxxx.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fun/rust-wasm/
function http-test deploy success
function rust-wasm deploy success
service fun deploy success $ curl https://xxxxxxx.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fun/rust-wasm/
Hello, rust-wasm!

利用AssemblyScript构建Serverless WebAssembly应用

AssemblyScript可以将一个 TypeScript 严格的子集编译成 WebAssembly。AssemblyScript 使用与 TypeScript 相同的语法,但使用了自己的标准库来支撑 WebAssembly 的功能,这意味着开发者不必为了编写 WebAssembly 而去学习新的编程语言,这是一个巨大的优点。而且AssemblyScript是针对WebAssembly设计的语言,它可以生成更加简练的WebAssembly代码,并更加简单地与JavaScript集成交互。

$ cd assemblyscript

# 下面是一个简单的Fibonacci数列的递归实现
$ cat assembly/index.ts
// The entry file of your WebAssembly module. export function fib(n: i32): i32 {
let t: i32;
let a: i32 = 0;
let b: i32 = 1;
for (let i: i32 = 0; i < n; i++) {
t = a + b;
a = b;
b = t;
}
return b;
} # 生成WebAsssembly目标代码
$ npm run asbuild # 如下是AssemblyScript自己生成的胶水代码,用于加载WebAssembly模块
$ cat wasm.js
const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {
env: {
abort(_msg, _file, line, column) {
console.error("abort called at index.ts:" + line + ":" + column);
}
}
};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
}); # 事件响应代码,在NodeJS中调用WebAssembly逻辑,根据query string输入参数计算Fibonacci结果
$ cat index.js
const { fib } = require('./wasm');
var getRawBody = require('raw-body')
module.exports.handler = function (request, response, context) {
// get request body
getRawBody(request, function (err, body) {
let strValue = request.queries.n
let n = 10 // Default value
if (strValue) {
n = parseInt(strValue)
}
response.setStatusCode(200);
result = fib(n)
response.send(result.toString());
});
}; # Serverless应用部署模板,利用HTTP Trigger进行访问
$ cat template.yml
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
fun:
Type: 'Aliyun::Serverless::Service'
assemblyscript:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
CodeUri: ./
Description: 'http trigger demo!'
Runtime: nodejs8
Events:
http-test:
Type: HTTP
Properties:
AuthType: ANONYMOUS
Methods: ['GET', 'POST', 'PUT']

部署并测试

$ fun deploy
...
Waiting for service fun to be deployed...
Waiting for function assemblyscript to be deployed...
Waiting for packaging function assemblyscript code...
package function assemblyscript code done, the number of files you have packaged is:1040
Waiting for HTTP trigger http-test to be deployed...
methods: [ 'GET', 'POST', 'PUT' ]
url: https://xxxxxx.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fun/assemblyscript/
function http-test deploy success
function assemblyscript deploy success
service fun deploy success $ curl https://xxxxxx.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fun/assemblyscript/\?n\=10
89 $ curl https://xxxxxx.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fun/assemblyscript/\?n\=40
165580141

展望未来

WebAssembly还是一个非常年轻的技术,大量的功能有待完善,但是它已经展现出巨大的潜力,逐渐在非Web领域得到应用,如区块链的智能合约实现。Mozilla在19年3月推出了一个标准化的 WebAssembly System Interface(WebAssembly系统接口,简称 WASI),来定义WASM与系统资源的交互,比如文件系统访问,内存管理,网络连接等。软件开发商可以针对具体的操作系统和运行环境提供不同的接口实现。它的目标是在不同设备和操作系统上运行相同的 WebAssembly 代码,这与Java 提出的 “build once run anywhere” 目标有些类似,但是WebAssembly + WASI完全基于开放生态,并提供更好的可移植性和安全性。

未来随着WebAssembly自身技术和工具链的成熟,WebAssembly将有机会成为一个跨语言、跨平台的Serverless runtime,进一步推动云原生应用的进化。社区也开始在相关领域进行探索,比如Fastly公司为其边缘计算平台推出 Lucet 项目,它针对Serverless场景提供了优化的WebAssembly编译器和运行时,可以将实例化 WebAssembly 模块的时间降低到数十微妙,内存开销降低到只需几KB。

WebAssembly和WASI等技术远非完美,它们还在快速迭代演进中,期待它给我们带来更多惊喜。

本文作者:易立

原文链接

本文为云栖社区原创内容,未经允许不得转载。

荷畔微风 - 在函数计算FunctionCompute中使用WebAssembly的更多相关文章

  1. python之使用heapq()函数计算列表中数值大小

    # heapq函数:计算列表最大几个值和最小几个值 # 语法:heapq.nlargest(n, list,[key]) # n表示最大或最小的几个: list为分析的对象: key为排序关键字,非必 ...

  2. 编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127)。不在范围内的不作统计。

    题目描述 编写一个函数,计算字符串中含有的不同字符的个数.字符在ACSII码范围内(0~127).不在范围内的不作统计. 输入描述: 输入N个字符,字符在ACSII码范围内. 输出描述: 输出范围在( ...

  3. sql server2005版本中,len函数计算了字符串末尾的空格

    sql server2005版本中,len函数计算了字符串末尾的空格的长度,以下是测试脚本: print @@version declare @v varchar(max) set @v = 'hp, ...

  4. Numpy.frompyfunc()将计算单个值的函数转化为计算数组中每个元素的函数

    Numpy.frompyfunc()将计算单个值的函数转化为计算数组中每个元素的函数 不再通过遍历,对数组中的元素进行运算,利用frompyfunc()将计算单个值的函数转化为计算数组中每个元素的函数 ...

  5. 开发函数计算的正确姿势 —— 使用 Fun Local 本地运行与调试

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  6. 阿里云函数计算 VSCode 使用,及部署 Docusaurus

    代码: https://github.com/ikuokuo/start-serverless 使用简介 产品页开通服务.使用流程,如下: 新手示例,如下: 创建函数 阿里云提供了如下几种方式创建函数 ...

  7. 如何迁移 Spring Boot 到函数计算

    作者 | 田小单 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上 ...

  8. 开发函数计算的正确姿势——OCR 服务

    作者 | 杜万(倚贤) 阿里云技术专家 简介 首先介绍下在本文出现的几个比较重要的概念: OCR(光学字符识别):光学字符识别(Optical Character Recognition, OCR)是 ...

  9. 函数可重入问题reentrant functions(函数执行过程中可以被中断,允许多个副本)

    最近经常听到这个名词,以前也听到过,不过接触更多的是“线程安全问题”,而且本人也一直理解的是两个名字的含义是一样的.今天仔细总结一下这个名词相关的概念. 引用博文:可重入函数和不可重入函数 (http ...

随机推荐

  1. 01.visual studio 2017添加菜单

    创建项目 文件--新建项目 如果新建项目 左侧没有扩展菜单,请安装即可 添加菜单 右键--添加新项 菜单设置 菜单设置文件: MyCommandPackage.vsct <Buttons> ...

  2. iOS开发之IMP和SEL(方法和类的反射)

    1.SEL:类方法的指针,相当于一种编号,区别与IMP! IMP:函数指针,保存了方法的地址! SEL是通过表取对应关系的IMP,进行方法的调用! 2.获取SEL和IMP方法和调用: SEL meth ...

  3. 05_springmvc参数绑定

    一.参数绑定的过程 从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上.springmvc中,接收页面提交的数据是通过方法形参来接收.而不 ...

  4. 删除文件夹时提示“You need permission to perform this action。。。”,如何解决?

    Win10系统,有时,要删除某个文件夹,却提示“You need permission to perform this action...” 以下是我Google之后找到的解决方案 1.创建一个文本文 ...

  5. Referenced assembly does not have a strong name

    Step 1 : Run visual studio command prompt and go to directory where your DLL located. For Example my ...

  6. elasticsearch 中文API river

    river-jdbc 安装 ./bin/plugin --install jdbc --url http://xbib.org/repository/org/xbib/elasticsearch/pl ...

  7. InceptionV3代码解析

    InceptionV3代码解析 参考博文:https://blog.csdn.net/superman_xxx/article/details/65451916 读了Google的GoogleNet以 ...

  8. /etc/sysctl.conf配置文件

    # vi /etc/sysctl.conf # add by digoal.zhou fs.aio-max-nr = fs. kernel.core_pattern= /data01/corefile ...

  9. 全栈之路-微信小程序-架构总览

    第一阶段是用来学习小程序开发的,这个就相当于PC端的网站吧,只不过现在依靠微信强大的流量来将业务搬移到小程序中,对于企业来说,这是一种很好的发展方向,既减少了开发成本,又减少了推广成本,小程序是很被人 ...

  10. HZOI20190813 B,任(duty)

    题面:去一个神奇的网页:https://www.cnblogs.com/Juve/articles/11352426.html 听说打O(nmq)有70 但是显然博主只有50分 考点:前缀和的综合应用 ...