美文网首页
Dapr在Java中的实践 之 服务调用

Dapr在Java中的实践 之 服务调用

作者: 万猫学社 | 来源:发表于2023-06-05 08:23 被阅读0次

    服务调用

    通过服务调用(Service-to-service Invocation),服务可以使用 gRPC 或 HTTP 这样的标准协议来发现并可靠地与其他服务通信。

    Dapr采用边车(Sidecar)、去中心化的架构。 要使用Dapr来调用服务,可以在任意Dapr实例上使用invoke这个API。 边车编程模型鼓励每个服务与自己的Dapr实例对话。 Dapr实例会相互发现并进行通信。

    创建项目

    创建两个SpringBoot项目,分别命名为:invoke-serverinvoke-clientinvoke-server作为下游服务,被invoke-client调用,具体调用过程如下图:

    service-invocation-overview

    调用过程包括:

    1. invoke-client服务对invoke-server服务发起HTTP或gRPC调用的时候,访问invoke-client服务的Dapr实例。
    2. invoke-client服务的Dapr实例通过运行在给定托管平台上服务名解析组件(Name Resolution Component)发现了运行在此Dapr环境中的invoke-server服务。
    3. invoke-client服务的Dapr实例将消息转发到服务invoke-server服务的Dapr实例。Dapr实例之间的所有调用考虑到性能都优先使用gRPC。 仅服务与Dapr实例之间的调用可以是HTTP或gRPC。
    4. invoke-server服务的Dapr实例将请求转发至invoke-server服务上的特定端点或方法,随后运行其业务逻辑代码。
    5. invoke-server服务返回响应信息给invoke-client服务时,响应信息给将转至invoke-server服务的Dapr实例。
    6. invoke-server服务的Dapr实例消息转发至invoke-client服务的Dapr实例。
    7. invoke-client服务接收到其Dapr实例的响应信息。

    编写invoke-server的代码

    调用/send接口时,返回对应信息,主要代码如下:

    package one.more.society.invoke.server;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @Slf4j
    @RestController
    public class InvokeServerController {
    
        @RequestMapping(value = "/send", method = RequestMethod.POST)
        public InvokeResponse send(@RequestBody InvokeRequest request) {
            log.info("send - request:{}", request);
    
            InvokeResponse response = new InvokeResponse();
            response.setCode(1);
            response.setStatus("ok");
            response.setMsgId(System.nanoTime());
            response.setMsgContent("I konw you said: " + request.getMsgContent());
    
            return response;
        }
    }
    

    其中,InvokeRequestInvokeResponse的源码如下:

    package one.more.society.invoke.server;
    
    import lombok.Data;
    
    @Data
    public class InvokeRequest {
    
        private Long msgId;
        private String msgContent;
    }
    
    package one.more.society.invoke.server;
    
    import lombok.Data;
    
    @Data
    public class InvokeResponse {
    
        private int code;
        private String status;
        private Long msgId;
        private String msgContent;
    }
    

    application.properties中配置:

    server.port=30001
    

    编写invoke-client

    invoke-client项目的pom.xml文件中添加如下依赖:

    <dependency>
        <groupId>io.dapr</groupId>
        <artifactId>dapr-sdk-springboot</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.9.3</version>
    </dependency>
    

    注入一个DaprClient的bean:

    @Configuration
    public class DaprConfig {
    
        private static final DaprClientBuilder BUILDER = new DaprClientBuilder();
    
        @Bean
        public DaprClient buildDaprClient() {
            return BUILDER.build();
        }
    }
    

    调用invoke-server/send接口,主要代码如下:

    package one.more.society.invoke.client;
    
    import io.dapr.client.DaprClient;
    import io.dapr.client.domain.HttpExtension;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @Slf4j
    @RestController
    public class InvokeClientController {
    
        @Autowired
        private DaprClient client;
    
        private static final String SERVICE_APP_ID = "invoke-server";
        private static final String METHOD_NAME = "send";
    
        @RequestMapping(value = "/say", method = RequestMethod.GET)
        public InvokeResponse say(String message) {
            log.info("send - message:{}", message);
    
            InvokeRequest request = new InvokeRequest();
            request.setMsgId(System.nanoTime());
            request.setMsgContent(message);
    
            InvokeResponse response = client.invokeMethod(
                    SERVICE_APP_ID,
                    METHOD_NAME,
                    request,
                    HttpExtension.POST,
                    InvokeResponse.class).block();
    
            return response;
        }
    }
    

    其中,InvokeRequestInvokeResponse的源码与invoke-server中是一样的。

    application.properties中配置:

    server.port=30002
    

    启动服务

    在启动之前先用mvn命令打包:

    mvn clean package
    

    invoke-server项目的目录中执行以下命令,启动invoke-server服务:

    dapr run --app-id invoke-server --app-port 30001 --dapr-http-port 31001 -- java -jar target/invoke-server-0.0.1-SNAPSHOT.jar
    

    invoke-client项目的目录中执行以下命令,启动invoke-client服务:

    dapr run --app-id invoke-client --app-port 30002 --dapr-http-port 31002 -- java -jar target/invoke-client-0.0.1-SNAPSHOT.jar
    

    在Dapr Dashboard中看到:

    Dapr Dashboard

    两个服务都已经启动成功。

    访问http://localhost:30002/say?message=OneMoreSociety验证整个调用流程:

    http://localhost:30002/say?message=OneMoreSociety

    可以看到服务之间的调用没有问题,并返回了预想的结果。

    名称解析组件

    为了启用服务发现和服务调用,Dapr使用可插拔的名称解析组件。 Kubernetes名称解析组件使用Kubernetes DNS服务来解析集群中运行的其他服务的位置;自托管机器可以使用mDNS名称解析组件。

    Consul名称解析组件可以在任何托管环境中使用,包括Kubernetes或自托管环境。下面让我们来尝试一下,使用Consul作为名称解析组件。

    在用户目录下的.dapr文件夹中,找到config.yaml文件。在该文件中,添加一个nameResolutionspec ,并将component字段设置为consul,比如:

    apiVersion: dapr.io/v1alpha1
    kind: Configuration
    metadata:
      name: daprConfig
    spec:
      nameResolution:
        component: "consul"
        configuration:
          client:
            address: "127.0.0.1:8500"
          selfRegister: true
    

    重新启动服务,可以在日志中看到注册到了Consul上:

    time="14:28:54.4540593+08:00" level=info msg="service:invoke-client registered on consul agent" app_id=invoke-client instance=OneMoreSociety scope=dapr.contrib type=log ver=1.7.3
    time="14:28:54.4550937+08:00" level=info msg="Initialized name resolution to consul" app_id=invoke-client instance=OneMoreSociety scope=dapr.runtime type=log ver=1.7.3
    

    在Consul中也可以看到两个服务都已经注册上去了,如下图:

    Consul

    值得注意的是:Consul名称解析组件目前还处于Alpha状态,最好不要在生产环境使用。

    更详细的配置说明见下表:

    配置项 是否必填 数据类型 说明 示例
    client N Config 配置客户端与 Consul 代理的连接。 如果留空,将使用默认值,即127.0.0.1:8500 192.168.0.111:8500
    queryOptions N QueryOptions 配置用于解决健康服务的查询,默认为UseCache:true UseCache: false,
    Datacenter: "myDC"
    checks N AgentServiceCheck数组 当进行注册服务时,配置健康检查。默认到Dapr实例检测健康端点。
    tags N string数组 在注册服务服务时包含的额外标签 - "dapr"
    meta N string字典 在注册服务服务时包含的额外的元数据 DAPR_METRICS_PORT: "${DAPR_METRICS_PORT}"
    daprPortMetaKey N string 用于在服务解析过程中从Consul服务元数据中获取Dapr实例端口的 key,它也将用于在注册时在元数据中设置Dapr实例端口。 默认为 DAPR_PORT "DAPR_TO_DAPR_PORT"
    selfRegister N boolean 控制Dapr实例是否会向Consul注册服务,默认为 false true
    advancedRegistration N AgentServiceRegistration 通过配置完全控制服务注册结果。 如果配置此项,Checks、 Tags、 Meta 和 SelfRegister的任何配置将被忽略。

    配置示例:

    apiVersion: dapr.io/v1alpha1
    kind: Configuration
    metadata:
      name: appconfig
    spec:
      nameResolution:
        component: "consul"
        configuration:
          client:
            address: "127.0.0.1:8500"
          selfRegister: true
          checks:
            - name: "Dapr Health Status"
              checkID: "daprHealth:${APP_ID}"
              interval: "15s",
              http: "http://${HOST_ADDRESS}:${DAPR_HTTP_PORT}/v1.0/healthz"
            - name: "Service Health Status"
              checkID: "serviceHealth:${APP_ID}"
              interval: "15s",
              http: "http://${HOST_ADDRESS}:${APP_PORT}/health"
          tags:
            - "dapr"
            - "v1"
            - "${OTHER_ENV_VARIABLE}"
          meta:
            DAPR_METRICS_PORT: "${DAPR_METRICS_PORT}"
            DAPR_PROFILE_PORT: "${DAPR_PROFILE_PORT}"
          daprPortMetaKey: "DAPR_PORT"        
          queryOptions:
            useCache: true
            filter: "Checks.ServiceTags contains dapr"
    

    相关文章

      网友评论

          本文标题:Dapr在Java中的实践 之 服务调用

          本文链接:https://www.haomeiwen.com/subject/ormiedtx.html