The author | | we source alibaba cloud native public number

Cloud computing has become the critical infrastructure underpinning the growth of the digital economy. Cloud computing infrastructure also continues to evolve, from IaaS, to Container as a Service (CaaS), to Serverless containers and function PaaS (fPaaS or FaaS), with new forms of computing emerging. Cloud native technologies, represented by containers and Serverless, are reshaping the entire application life cycle.

In Gartner’s analysis report, the development path of cloud computing infrastructure is also a process of increasing cloud native characteristics. Its specific performance is as follows:

  • Increasing modularity – more fine-grained computing units, such as containers and Serverless functions, are better suited for application delivery in microservice architectures, leveraging the power of the cloud and improving architectural agility.

  • Increasing programmability – Automated management and operation through declarative apis and policies, and Immutable Infrastructure to further enhance the certainty of distributed application operations.

  • Increasing elastic efficiency – VM can achieve minute-level expansion; Containers and Serverless containers can achieve second-level expansion. With scheduling optimization, the function can be expanded in milliseconds.

  • Increasingly resilient – Kubernetes provides powerful automated orchestration capabilities to improve application self-healing. Serverless further sinks system-level complexity such as stability, scalability, and security into the infrastructure, allowing developers to focus only on their own business application logic, further unleashing productivity and improving system resilience.

Distributed cloud is another important trend in the development of cloud computing. Public cloud services can be extended to different physical locations, bringing computing closer to customers. Distributed cloud enables customers to enjoy the convenience of cloud computing and meet their demands for real-time computing and security compliance. This is also driving changes in enterprise application architectures – applications that can be deployed and migrated across different environments to provide services in an optimized manner.

Further, with the emergence of new technologies such as mobile Internet, AI and IoT, ubiquitous computing has become a reality. At the same time, this is also promoting the diversity of computing power. The era of X86 architecture is gone, and new chip forces such as ARM/RISC-V are not only dominating mobile communications and embedded devices, but also attacking edge computing and data center markets. Developers even need to support different CPU architectures. For example, we can deploy an image recognition application to run on devices with different architectures in different environments, such as edge or IoT.

In the new cloud computing scenarios such as distributed cloud, edge computing and cloud integration, what are the characteristics of the next generation of cloud native applications?

Next generation cloud native application runtime

1. Ubiquitous computing spawns the next generation of portable, high-performance, lightweight security sandboxes

Container applications use a self-contained packaging method called container image, which contains application code and dependent system components. It decouples applications from infrastructure and enables applications to be deployed, operated and maintained in different operating environments, such as public and private clouds, in a consistent manner, simplifying flexibility and migration. In addition, Docker image specification supports multi-arch images, which can simplify the construction and distribution of application images of different CPU architectures (such as x86, ARM, etc.).

Functional applications contain only code packages for event response, which elevates the application delivery format from native binaries to high-level language levels. This also opens up the possibility of application portability and, in theory, even hides differences in the CPU architecture of the execution environment. For example, scripts such as Python/NodeJS or Java applications that do not rely on native code can run on different CPU architectures such as x86 or ARM without modification.

However, the ideal is full and the reality is very thin. Portability and vendor lock-in are the obstacles to the development of functional PaaS.

  • Many scripts still call native code for data processing and middleware (such as database drivers), but compiling native code requires the build environment to be consistent with the target execution environment to ensure compatibility. For example, AWS Lambda/Ali cloud functions require binary native code to rely on the specified kernel and LIBC version. Therefore, more and more function PaaS services support container images as carriers to simplify function application packaging and dependency management.

  • Function applications usually rely on BaaS (Backend as a Service) for data access and computing processing. Since BaaS does not have any standard, it is difficult to transplant function applications developed on AWS Lambda to function computing Service of Aliyun.

In Serverless computing, the existing mainstream technology is to use sandbox container technology, such as AWS Firecraker or Ali Cloud sandbox, to achieve strong isolation of the safe execution environment, but also bring greater resource consumption. Although ali Cloud sandbox can realize the cold startup speed of 300ms after optimization, which is close to the startup speed of OS containers like Docker, it still cannot meet the startup requirements of function PaaS at millisecond level. The current scheduling policy that needs to be passed can only be satisfied by reserve certain standby instances. But it also introduces more resource consumption.

WebAssembly (WASM) is a new W3C specification that is a common, open, efficient, and secure abstraction for underlying virtual machines. It is designed to address the performance issues of JavaScript so that Web applications can approach the performance of native applications. Existing programming language applications such as C/C++, Rust, etc., can be compiled into WASM bytecode and run in a sandbox environment in the browser.

WASM decouples application development technology from the runtime environment, greatly facilitating code reuse. Mozilla also launched WebAssembly System Interface (WASI) in 2019, which provides a standard API like POSIX to standardize the abstraction of WebAssembly interactions with System resources, such as file System access, Memory management, etc. The emergence of WASI has expanded the application scenario of WASM to allow it to run various types of server applications as a virtual machine. WASM/WASI is a new hope for app portability. To further the WebAssembly ecosystem, Mozilla, Fastly, Intel and Red Hat have launched the Bytecode Alliance. Co-lead WASI standards, WebAssembly runtime, tools, etc.

WebAssembly’s features of security, portability, high efficiency and lightweight bring a new idea to the development of application sandbox. WASM can easily achieve millisecond cold start times and extremely low resource consumption. WASM bytecode also has a higher level of security than native machine code. In addition, WASI implements a fine-grained capability-based security model that follows the principle of minimum permissions. During execution, WASI applications can only access the exact set of resources specified by dependency injection, which further converges the security attack surface compared to traditional coarse-grained operating system-level isolation.

Because of this, WASM/WASI is getting a lot of attention from communities like Serverless, IoT/ Edge computing. Developers such as Fastly and Cloudflare have released Serverless services that are lightweight and based on WebAssembly technology.

However, the path to server-side adoption of WebAssembly is still fraught with challenges. First WASI ability is still in very early state, still missing some key ability, the first is the lack of standardization of network access: https://github.com/WebAssembly/WASI/issues/315.

At present, WASI application can only do some computing tasks, and basically cannot realize distributed application, nor can it call diversified back-end services and application middleware such as Redis, MySQL and Kafka. This greatly limits the application scenarios for WASI.

When ideals collide with reality, head broken and bleeding or desperate survival?

2. Next generation portable application runtime accelerated programming interface moving up, application infrastructure capacity sinking

Dapr is Microsoft’s open source distributed application runtime for cloud native applications. The goal is to enable all developers to easily build resilient, event-driven, portable microservices applications using any language and any framework.

Dapr implements a set of design patterns for building high-performance, scalable, and highly available distributed applications, such as service discovery and service invocation capabilities, as well as a simple, consistent programming model to support event-driven application architectures.

In addition, Dapr shields applications from the technical details of accessing back-end services, such as resource binding, security management, observability, and so on, through infrastructure. This is important for Serverless applications, on the one hand, to decouple development and deployment, allowing developers and operations teams to simplify system complexity through separation of concerns; On the one hand, the short life cycle, stateless Serverless application logic can be decoupled from the long running, stateful middleware access ability such as database connection pool management, which improves the scalability and running efficiency of Serverless applications.

“Any language, Any Framework, anywhere” is an important design goal of Dapr. Dapr provides a Sidecar layer of abstraction between applications and back-end services, and provides portability of applications and replaceable back-end services through standardized HTTP/gRPC apis.

Toward poetry and beyond

We can combine WebAssembly and Dapr to achieve a portable, strongly isolated, lightweight microservice application architecture. Dapr Sidecar is deployed with the WASM VIRTUAL machine. WASI applications access local Dapr service endpoints through HTTP/gRPC, and Dapr proxies connect to various back-end services or communicate between services.

This architecture design makes the security boundaries of WASI applications very clear and conforms to the WASI security model. WASI applications can only be accessed by external services through Dapr Sidecar. Meanwhile, only the WASM VIRTUAL machine and Dapr run in native machine code as trusted environment dependencies in this architecture. The application is portable WASM bytecode, which greatly improves the portability and security of the architecture.

Radu Matei from Microsoft Deis Labs recently offered a pilot project to add HTTP support to WASI. See: _https: / / deislabs. IO/posts/wasi – experimental – HTTP / _.

On this basis, we build a minimum prototype to verify the technical feasibility of combining WebAssembly and Dapr.

1. Dapr environment preparation

We first according to the process of https://docs.dapr.io/getting-started/ :

$dapr init ⌛ Making the jump to hyperspace... ✅ Downloading binaries and setting up Components... ✅ Downloaded binaries and completed components set up. ℹ️ daprd binary has been installed to /Users/yili/.dapr/ bin.ℹ️ ℹ️ dapr_redis container is running. ℹ️ dapr_zipkin container is running. ℹ️ Use 'Docker ps' to check running containers. ✅ Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started $ dapr run --app-id myapp --dapr-http-port 3500 WARNING: No application Command found. ℹ️ Starting Dapr with id myapp. HTTP Port: 3500. gRPC Port: 63734 ℹ️ Checking if Dapr sidecar is listening on HTTP port 3500... ℹ️ Checking if Dapr Sidecar is listening on GRPC port 63734 ℹ️ Dapr Sidecar is up and running. ✅ You're up and running! Dapr logs will appear here.Copy the code

2. Use Redis as the state storage of WASI application

Let’s use the Dapr Get Started example to use Redis as the state store for THE WASI application. The specific logic is shown in the following figure.

Note: The following applications require the Rust and AssemblyScript environment configuration, please complete yourself.

We fork a version of the Radu project, download the code first, and build it.

$ git clone https://github.com/denverdino/wasi-experimental-http
$ cd wasi-experimental-http
$ cargo build
...
    Finished dev [unoptimized + debuginfo] target(s) in 3m 02s
Copy the code

AssemblyScript is used to implement this test application. The test code is as follows:

$ cat tests/dapr/index.ts // @ts-ignore import { Console } from "as-wasi"; import { DaprClient, StateItem } from "./dapr"; import { JSON } from "assemblyscript-json"; Console.log("Testing Dapr API ...." ) let dapr = new DaprClient() dapr.saveState("statestore", "weapon", JSON.Value.String("Death Star")) let o = JSON.Value.Object() o.set("name", "Tatooine") o.set("test", 123) let item = new StateItem("planets", o) let items: StateItem[] = [item] dapr.saveBulkState("statestore", items) let testObj = dapr.getState("statestore", "planets") let testStr = dapr.getState("statestore", "weapon") if (testStr.toString() == "Death Star" && testObj.isObj && (<JSON.Integer>(<JSON.Obj>testObj).getInteger("test")).valueOf() == 123) { Console.log("Test successfully!" ) } else { Console.log("Test failed!" )}Copy the code

The logic is simple: create a Dapr client and manage Dapr state through the REST API. We can verify that very quickly.

$cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.19s Running `target/debug/wasi-experimental-http-wasmtime-sample` Testing Dapr API .... POST http://127.0.0.1:3500/v1.0/state/statestore with [{" key ":" weapon ", "value" : "Death Star"}] POST http://127.0.0.1:3500/v1.0/state/statestore with [{" key ":" planets ", "value" : {" name ":" Tatooine ", "test" : 123}}] GET http://127.0.0.1:3500/v1.0/state/statestore/planets GET http://127.0.0.1:3500/v1.0/state/statestore/weapon Test successfully! The module instantiation time: 333.16637 msCopy the code

3. Analysis of key points

The WASI-experimental-HTTP project extends the Wasmtime virtual machine (a WASM implementation from Bytecode Alliance) to support access to HTTP services within WASI applications. It also provides an HTTP Client implementation of AssemblyScript.

Wasi – experimental project – HTTP: https://github.com/deislabs/wasi-experimental-http/.

On top of this, we provide a package of Dapr for AssemblyScript, see: https://github.com/denverdino/wasi-experimental-http/blob/main/tests/dapr/dapr.ts.

// @ts-ignore import { Console } from "as-wasi"; import { Method, RequestBuilder, Response } from ".. /.. /crates/as"; import { JSONEncoder, JSON } from "assemblyscript-json"; export class StateItem { key: string value: JSON.Value etag: string | null metadata: Map<string, string> | null constructor(key: string, value: JSON.Value) { this.key = key this.value = value this.etag = null this.metadata = null } } ... export class DaprClient { port: i32 address: } stateURL(storeName: string constructor() {this.address = "127.0.0.1" this.port = 3500} stateURL(storeName: string): String {return "http://" + this.address + ":" + this.port.tostring () + "/v1.0/state/" + storeName} saveState(storeName: string, key: string, value: JSON.Value): boolean { let item = new StateItem(key, value) let items: StateItem[] = [item] return this.saveBulkState(storeName, items) } saveBulkState(storeName: string, items: StateItem[]): boolean { // Handle field let encoder = new JSONEncoder(); // Construct necessary object encoder.pushArray(null); for (let i = 0, len = items.length; i < len; i++) { let item = items[i] encoder.pushObject(null); encoder.setString("key", item.key) encodeValue(encoder, "value", item.value) if (item.etag ! = null) { encoder.setString("etag", <string>item.etag) } encoder.popObject() }; encoder.popArray(); // Or get serialized data as string let jsonString = encoder.toString(); let url = this.stateURL(storeName); Console.log("POST " + url + " with " + jsonString); let res = new RequestBuilder(url) .method(Method.POST) .header("Content-Type", "application/json") .body(String.UTF8.encode(jsonString)) .send(); let ok = res.status.toString() == "200" res.close(); return ok } getState(storeName: string, key: string): JSON.Value { let url = this.stateURL(storeName) + "/" + key; Console.log("GET " + url); let res = new RequestBuilder(url) .method(Method.GET) .send(); let ok = res.status.toString() == "200" let result = <JSON.Value> new JSON.Null() if (ok) { let body = res.bodyReadAll(); result = <JSON.Value>JSON.parse(body) } res.close(); return result } };Copy the code

The main function of the test application creates a Wasmtime runtime environment, adds it as an HTTP extension, and loads the WASM bytecode for executing the test application: https://github.com/denverdino/wasi-experimental-http/blob/main/src/main.rs.

fn main() { let allowed_domains = Some(vec! [" http://127.0.0.1:3500 ". To_string (),]); let module = "tests/dapr/build/optimized.wasm"; create_instance(module.to_string(), allowed_domains.clone()).unwrap(); } /// Create a Wasmtime::Instance from a compiled module and /// link the WASI imports. fn create_instance( filename: String, allowed_domains: Option<Vec<String>>, ) -> Result<Instance, Error> { let start = Instant::now(); let store = Store::default(); let mut linker = Linker::new(&store); let ctx = WasiCtxBuilder::new() .inherit_stdin() .inherit_stdout() .inherit_stderr() .build()? ; let wasi = Wasi::new(&store, ctx); wasi.add_to_linker(&mut linker)? ; // Link `wasi_experimental_http` let http = HttpCtx::new(allowed_domains, None)? ; http.add_to_linker(&mut linker)? ; let module = wasmtime::Module::from_file(store.engine(), filename)? ; let instance = linker.instantiate(&module)? ; let duration = start.elapsed(); println! ("module instantiation time: {:#? }", duration); Ok(instance) }Copy the code

When the path is long and obstructed, it will come

WASM/WASI provides a good foundation for lightweight, portable, and default secure application runtimes, and WebAssembly has been widely used in areas such as blockchain. However, the gap between WASM/WASI and general-purpose server-side applications is still significant. Due to the lack of standardized network programming interfaces such as Berkeley sockets, the WASM VIRTUAL machine can only be extended to complement. In addition, the multithreading capability of WASM has not been standardized, and the current HTTP calls use blocking synchronous calls, which can not achieve efficient and stable network communication.

In addition, another shortcoming of WASM/WASI is development efficiency and ecological construction. While many programming languages are beginning to offer WebAssembly support, scripting languages like AssemblyScript are a better choice for the average developer. AssemblyScript reuses TypeScript syntax, reduces the learning curve compared to Rust/C++, and provides a great IDE tool experience such as VS Code. But unlike TypeScripty, which is translated into JavaScript execution, AssemblyScript applications are compiled into WASM bytecode execution. AssemblyScript is essentially a statically typed compiled language, very different in nature from dynamically typed interpreted languages such as JS/TS. AssemblyScript also lacks support for common features such as closures and Regex, which makes developing WASM applications a bit of a technical hurdle.

The AssemblyScript community is also young compared to NPM’s strong ecosystem. Many functions need to be built from scratch, such as serialization and deserialization of JSON. We chose _github.com/nearprotoco… The JSON class library has some gaps. Of course, we’ve also seen the rapid growth of AssemblyScript, with more and more developers starting to contribute to the AssemblyScript library, such as regex support.

The advent of Dapr brings another ray of light for WASM/WASI to develop general-purpose distributed applications, especially portable, Serverless applications. However, Dapr is not perfect: API standardization improves the portability of back-end services while hindering the ability to differentiate. The Sidecar architecture increases deployment and management complexity while increasing flexibility.

As a rational optimist, every technology has its green days, and I expect the community to work together to make computing ubiquitous and innovation at your fingertips a reality.