dapr 概要笔记,本文测试验证了官方 dapr 和阿里 dapr 的具体步骤,并通过 go、rust 程序化调用了最简单的 hsf(类似社区 dubbo) 接口。

dapr 社区版本

安装 dapr-cli

参考 dapr-cli 安装文档

$ brew install dapr/tap/dapr-cli

# 验证安装
$ darp -h

初始化

参考 本地初始化

# 如果本地为 colima 管理的 docker,需手动 export DOCKER_HOST 
$ export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"

# 初始化
$ dapr init
⌛  Making the jump to hyperspace...
ℹ️  Container images will be pulled from Docker Hub
ℹ️  Installing runtime version 1.16.3
✅  Downloading binaries and setting up components...
✅  Downloaded binaries and completed components set up.
...
ℹ️  dapr_placement container is running.
ℹ️  dapr_redis container is running.
ℹ️  dapr_zipkin container is running.
ℹ️  dapr_scheduler container is running.
ℹ️  Use `docker ps` to check running containers.
✅  Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started

启动并测试

参考 使用 dapr api

# 启动 dapr
# 默认的 componets 目录为 $HOME/.dapr/components
$ dapr run --app-id myapp --dapr-http-port 3500

# 使用 redis 存储状态,进行测试存储
$ curl -X POST -H "Content-Type: application/json" -d '[{ "key": "myname", "value": "pipe"}]' http://localhost:3500/v1.0/state/statestore

# 进行测试获取状态
$ curl http://localhost:3500/v1.0/state/statestore/myname
"pipe"% 

dapr 阿里版本

参考 本地启动Dapr

安装 ali-dapr

进入 dapr.io.alibaba-inc.com,获取二进制文件下载地址,比如下载 Mac M 系列的命令如下:

# 下载并重命名为 ali-daprd
$ wget -O ali-daprd http://pandora-repos.oss-cn-hangzhou-c.aliyuncs.com/publicfiles/dapr/v1.15.4.20/darwin_arm64/release/daprd

# 添加执行权限
$ chmod +x ./ali-daprd

配置并启动

参考 社区 dubbo

新建 hsf.yaml

相关的 subscribe 字段,可提前预热 hsf 接口,能有效提升首次调用时间,为简化逻辑,此处不做启动订阅

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: hsf.consumer
spec:
  type: bindings.hsf
  metadata:

启动 dapr

# 根据当前的 hsf 组件启动,指定为当前目录(上述 hsf.yaml 所在目录)
$ ./ali-daprd -app-id ali-daprd --resources-path ./

测试 hsf 调用

# 测试 hsf 调用
$ curl -X POST http://127.0.0.1:3500/v1.0/bindings/hsf.consumer \
  -H "Content-Type: application/json" \
  -d '{
      "operation": "invoke",
      "metadata": {
        "rpc-interface-name": "com.alibaba.hsf.mstest.service.hsf.HelloService",
        "rpc-method-name": "sayHello",
        "rpc-method-parameter-types": "java.lang.String",
        "rpc-version": "1.0.0.DAILY"

      },
      "data": ["pipe.zkk"]
    }'
"Hello, pipe.zkk"% 

程序调用

dapr 最大优势就是统一协议之后,支持跨语言调用,所以简单测试一下 go 与 rust 的调用。

Rust Dapr

初始化项目

# 新建 rust 项目
$ cargo new rust-dapr
$ cd rust-dapr

# 添加 dapr 库
$ cargo add dapr
# 添加异步库
$ cargo add tokio --features full

main 代码

dapr 默认的 HTTP 端口为 3500,gRPC 端口为 50001

use dapr::Client as DaprClient;
use std::collections::HashMap;

#[tokio::main]
async fn main() {
    let addr = "http://127.0.0.1".to_string();
    let port = "50001".to_string();

    let mut client = DaprClient::<dapr::client::TonicClient>::connect_with_port(addr, port)
        .await
        .expect("Failed to connect to Dapr");

    let data = "[\"pipe.zkk\"]".as_bytes().to_vec();
    let mut metadata = Some(HashMap::new());

    let _ = metadata.insert(HashMap::from([
        (
            "rpc-interface-name".to_string(),
            "com.alibaba.hsf.mstest.service.hsf.HelloService".to_string(),
        ),
        ("rpc-method-name".to_string(), "sayHello".to_string()),
        (
            "rpc-method-parameter-types".to_string(),
            "java.lang.String".to_string(),
        ),
        ("rpc-version".to_string(), "1.0.0.DAILY".to_string()),
    ]));

    let response = client
        .invoke_binding("hsf.consumer", data, "invoke", metadata)
        .await
        .expect("Failed to invoke binding");

    println!(
        "get_response: {:?}",
        String::from_utf8(response.data).expect("Failed to convert response to string")
    );
}

运行完程序后,输出如下:

# 编译并运行
$ cargo run 
   Compiling rust-dapr v0.1.0 (/Users/zhoukeke/workspace/grpc-note/rust-grpc/rust-dapr)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.80s
     Running `target/debug/rust-dapr`
get_response: "\"Hello, pipe.zkk\""

go dapr

初始化项目

$ mkdir go-dapr && cd go-dapr

# 初始化并新建 main 文件
$ go mod init hello-dapr
$ touch main.go

# 安装依赖
$ go get github.com/dapr/go-sdk/client

main 代码

package main

import (
	"context"
	"fmt"

	dapr "github.com/dapr/go-sdk/client"
)

func main() {
	client, err := dapr.NewClientWithAddress("127.0.0.1:50001")
	if err != nil {
		panic(err)
	}

  defer client.Close()

	response, err := client.InvokeBinding(context.Background(), &dapr.InvokeBindingRequest{
		Name:      "hsf.consumer",
		Operation: "invoke",
		Data:      []byte("[\"pipe.zkk\"]"),
		Metadata: map[string]string{
			"rpc-interface-name":         "com.alibaba.hsf.mstest.service.hsf.HelloService",
			"rpc-method-name":            "sayHello",
			"rpc-method-parameter-types": "java.lang.String",
			"rpc-version":                "1.0.0.DAILY",
		},
	})

	if err != nil {
		panic(err)
	}

	fmt.Println(string(response.Data))
}

运行结果如下

$ go run main.go 
dapr client initializing for: 127.0.0.1:50001
"Hello, pipe.zkk"

小结

从上述代码结果,能比较清楚地看出,其实 rust 并不适合写业务代码(相对比较冗余和复杂),go 会更适合一些,rust 会更适合偏低层或操作系统层面的。如果后续做 wasm server runtime 的上层语言选择,go 可能会更适合。