目录

-
模块化越来越高 – 更加细粒度的计算单元,如容器和 Serverless 函数,更加适于微服务架构的应用交付,可以更加充分利用云的能力,提升架构敏捷性。
-
可编程性越来越高 – 可以通过声明式 API 和策略进行实现自动化管理与运维,可以通过 Immutable Infrastructure (不可变基础设施)进一步提升分布式应用运维的确定性。
-
弹性效率越来越高 – VM 可以实现分钟级扩容;容器与 Serverless 容器可以实现秒级扩容;借助调度优化,函数可以做到毫秒级扩容。
-
韧性越来越高 – Kubernetes 提供了强大自动化编排能力,提升应用系统自愈性。而 Serverless 进一步将稳定性、可伸缩性和安全等系统级别复杂性下沉到基础设施,开发者只需关注自身业务应用逻辑,进一步释放了生产力,提升系统的可恢复能力。

$ 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_placement container is running.
ℹ️ 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.
$ git clone https://github.com/denverdino/wasi-experimental-http
$ cd wasi-experimental-http
$ cargo build
...
Finished dev [unoptimized + debuginfo] target(s) in 3m 02s
$ 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!")
}
$ 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!
module instantiation time: 333.16637ms
// @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: 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
}
};
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)
}