美文网首页
java版gRPC实战之七:基于eureka的注册发现

java版gRPC实战之七:基于eureka的注册发现

作者: 程序员欣宸 | 来源:发表于2021-08-10 06:26 被阅读0次

    欢迎访问我的GitHub

    https://github.com/zq2599/blog_demos

    内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

    《java版gRPC实战》全系列链接

    1. 用proto生成代码
    2. 服务发布和调用
    3. 服务端流
    4. 客户端流
    5. 双向流
    6. 客户端动态获取服务端地址
    7. 基于eureka的注册发现

    关于eureka

    前面咱们在开发客户端应用时,所需的服务端地址都是按如下步骤设置的:

    • 在application.yml中配置,如下图:
    在这里插入图片描述
    • 在用到gRPC的bean中,使用注解<font color="blue">GrpcClient</font>即可将Stub类注入到成员变量中:
    在这里插入图片描述
    • 上述操作方式的优点是简单易用好配置,缺点也很明显:服务端的IP地址或者端口一旦有变化,就必须修改application.yml并重启客户端应用;
    • 聪明的您一定想到了应对之道:注册中心!没错,有了注册中心,咱们的客户端只要能从注册中心取得最新的服务端地址,就不再需要手动配置了,以下是常规的eureka作用说明:
    在这里插入图片描述

    本篇概览

    • 如果您有Spring Cloud的开发经验,对resttemplate和feign等应该很熟悉,但是Spring Cloud环境下的gRPC调用却没有那么常用,本篇的目标是通过实战与大家一起掌握Spring Cloud环境下的gRPC调用,分为以下章节:
    1. eureka应用开发
    2. gRPC服务端开发
    3. gRPC客户端开发
    4. 验证
    5. 一点疑惑

    源码下载

    名称 链接 备注
    项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
    git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
    git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
    • 这个git项目中有多个文件夹,《java版gRPC实战》系列的源码在<font color="blue">grpc-tutorials</font>文件夹下,如下图红框所示:
    在这里插入图片描述
    • <font color="blue">grpc-tutorials</font>文件夹下有多个目录,本篇文章对应的eureka代码在<font color="blue">cloud-eureka</font>目录,服务端代码在<font color="blue">cloud-server-side</font>目录,客户端代码在<font color="blue">cloud-client-side</font>目录,如下图:
    在这里插入图片描述

    eureka应用开发

    • 在父工程grpc-turtorials下面新建名为<font color="blue">cloud-eureka</font>的模块,其build.gradle内容如下:
    // 使用springboot插件
    plugins {
        id 'org.springframework.boot'
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
        // 依赖eureka
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
        // 状态暴露需要的依赖
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        // 依赖自动生成源码的工程
        implementation project(':grpc-lib')
    }
    
    • 配置文件bootstrap.yml,设置自己的web端口号和应用名,另外eureka.client.serviceUrl.defaultZone的配置请改成自己的IP:
    server:
      port: 8085
    
    spring:
      application:
        name: cloud-eureka
    
    eureka:
      instance:
        hostname: localhost
        prefer-ip-address: true
        status-page-url-path: /actuator/info
        health-check-url-path: /actuator/health
        lease-expiration-duration-in-seconds: 30
        lease-renewal-interval-in-seconds: 30
      client:
        registerWithEureka: false
        fetchRegistry: false
        serviceUrl:
                defaultZone: http://192.168.50.5:8085/eureka/
      server:
        enable-self-preservation: false
    
    endpoints:
     shutdown:
      enabled: true
    
    • 这个模块只有一个类CloudEurekaApplication.java:
    package com.bolingcavalry.grpctutorials;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @EnableEurekaServer
    @SpringBootApplication
    public class CloudEurekaApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CloudEurekaApplication.class, args);
        }
    }
    
    • 以上就是一个简单通用的eureka服务了;

    gRPC服务端开发

    • 依赖eureka的gRPC服务端,其重点在于:第一,配置使用eureka,第二,不要指定端口;

    • 在父工程grpc-turtorials下面新建名为<font color="blue">cloud-server-side</font>的模块,其build.gradle内容如下,注意要引入gRPC服务端相关的starter:

    // 使用springboot插件
    plugins {
        id 'org.springframework.boot'
    }
    
    dependencies {
        implementation 'org.projectlombok:lombok'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter'
        // 作为gRPC服务提供方,需要用到此库
        implementation 'net.devh:grpc-server-spring-boot-starter'
        // 作为eureka的client
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        // 状态暴露需要的依赖
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        // 依赖自动生成源码的工程
        implementation project(':grpc-lib')
        // annotationProcessor不会传递,使用了lombok生成代码的模块,需要自己声明annotationProcessor
        annotationProcessor 'org.projectlombok:lombok'
    }
    
    • 配置文件application.yml,设置自己的应用名,另外值得注意的是<font color="blue">server.port</font>和<font color="blue">grpc.server.port</font>这两个配置的值都是0,这样两个端口就会被自动分配未被占用的值:
    spring:
      application:
        name: cloud-server-side
    
    server:
      port: 0
    grpc:
      server:
        port: 0
    eureka:
      instance:
        prefer-ip-address: true
        instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: http://192.168.50.5:8085/eureka/
    
    • 启动类CloudServerSideApplication.java:
    package com.bolingcavalry.grpctutorials;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient
    @EnableDiscoveryClient
    @SpringBootApplication
    public class CloudServerSideApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CloudServerSideApplication.class, args);
        }
    }
    
    • 提供gRPC服务的类GrpcServerService,和local-server模块中的一样:
    package com.bolingcavalry.grpctutorials;
    
    import com.bolingcavalry.grpctutorials.lib.HelloReply;
    import com.bolingcavalry.grpctutorials.lib.SimpleGrpc;
    import net.devh.boot.grpc.server.service.GrpcService;
    import java.util.Date;
    
    @GrpcService
    public class GrpcServerService extends SimpleGrpc.SimpleImplBase {
    
        @Override
        public void sayHello(com.bolingcavalry.grpctutorials.lib.HelloRequest request,
                             io.grpc.stub.StreamObserver<HelloReply> responseObserver) {
            HelloReply reply = HelloReply.newBuilder().setMessage("1. Hello " + request.getName() + ", " + new Date()).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
    
    • 以上就是服务端代码了,可见除了将gRPC端口设置为0,以及常规使用eureka的配置,其他部分和local-server模块是一样的;

    gRPC客户端开发

    • 依赖eureka的gRPC客户端,其重点在于:第一,配置使用eureka,第二,配置中的gRPC配置项的名字要等于gRPC服务端在eureka注册的名字,如下图红框所示:
    在这里插入图片描述
    • 在父工程grpc-turtorials下面新建名为<font color="blue">cloud-client-side</font>的模块,其build.gradle内容如下,注意要引入gRPC客户端相关的starter:
    // 使用springboot插件
    plugins {
        id 'org.springframework.boot'
    }
    
    dependencies {
        implementation 'org.projectlombok:lombok'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter'
        // 作为gRPC服务使用方,需要用到此库
        implementation 'net.devh:grpc-client-spring-boot-starter'
        // 作为eureka的client
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        // 状态暴露需要的依赖
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        // 依赖自动生成源码的工程
        implementation project(':grpc-lib')
        // annotationProcessor不会传递,使用了lombok生成代码的模块,需要自己声明annotationProcessor
        annotationProcessor 'org.projectlombok:lombok'
    }
    
    • 配置文件application.yml,设置自己的web端口号,另外值得注意的是gRPC配置项<font color="blue">cloud-server-side</font>的名字要等于gRPC服务端在eureka注册的名字,并且<font color="red">不需要address配置项</font>:
    server:
      port: 8086
    spring:
      application:
        name: cloud-client-side
    eureka:
      instance:
        prefer-ip-address: true
        status-page-url-path: /actuator/info
        health-check-url-path: /actuator/health
        instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: http://192.168.50.5:8085/eureka/
    grpc:
      client:
        # gRPC配置的名字,GrpcClient注解会用到
        cloud-server-side:
          enableKeepAlive: true
          keepAliveWithoutCalls: true
          negotiationType: plaintext
    
    • 启动类CloudClientSideApplication.java,使用了eureka相关的注解:
    package com.bolingcavalry.grpctutorials;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient
    @EnableDiscoveryClient
    @SpringBootApplication
    public class CloudClientSideApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CloudClientSideApplication.class, args);
        }
    }
    
    • 封装gRPC调用的服务类GrpcServerService,和local-server模块中的一样,GrpcClient注解对应配置中的gRPC配置项:
    package com.bolingcavalry.grpctutorials;
    
    import com.bolingcavalry.grpctutorials.lib.HelloReply;
    import com.bolingcavalry.grpctutorials.lib.HelloRequest;
    import com.bolingcavalry.grpctutorials.lib.SimpleGrpc;
    import io.grpc.StatusRuntimeException;
    import net.devh.boot.grpc.client.inject.GrpcClient;
    import org.springframework.stereotype.Service;
    
    @Service
    public class GrpcClientService {
    
        @GrpcClient("cloud-server-side")
        private SimpleGrpc.SimpleBlockingStub simpleStub;
    
        public String sendMessage(final String name) {
            try {
                final HelloReply response = this.simpleStub.sayHello(HelloRequest.newBuilder().setName(name).build());
                return response.getMessage();
            } catch (final StatusRuntimeException e) {
                return "FAILED with " + e.getStatus().getCode().name();
            }
        }
    }
    
    • 再做一个web接口类,这样我们就能通过web调用验证gRPC服务了:
    package com.bolingcavalry.grpctutorials;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class GrpcClientController {
    
        @Autowired
        private GrpcClientService grpcClientService;
    
        @RequestMapping("/")
        public String printMessage(@RequestParam(defaultValue = "will") String name) {
            return grpcClientService.sendMessage(name);
        }
    }
    
    • 客户端开发完毕,接下来可以验证了;

    验证

    • 启动cloud-eureka:
    在这里插入图片描述
    • 启动cloud-server-side,可见gRPC服务端口自动分配了65141,不过我们无需关心这个值,因为客户端可以从eureka获取到:
    在这里插入图片描述
    • 接下来启动cloud-client-side,启动成功后eureka上可见两个服务的注册信息:
    在这里插入图片描述
    • 浏览器访问cloud-client-side提供的web接口,响应如下,可见cloud-client-side成功调用了cloud-server-side的gRPC服务:
    在这里插入图片描述

    一点疑惑

    • 如果您对eureka有所了解,可能会产生一点疑惑:cloud-client-side从eureka取得的cloud-server-side信息,应该是http服务的地址和端口,不应该有gRPC的端口号,因为eureka的注册发现服务并不包含gRPC有关的!

    • 篇幅所限,这里不适合将上述问题展开分析,咱们来关注最核心的地方,相信聪明的您看上一眼就会豁然开朗;

    • DiscoveryClientNameResolver来自grpc-client-spring-boot-autoconfigure.jar,用来保存从eureka取得的服务端信息,该类的注释已经说得很清楚了,从metadata的gRPC.port配置项中取得gRPC端口号:

    在这里插入图片描述
    • 在DiscoveryClientNameResolver的代码中打上断点,查看成员变量instanceList,可见metadata中确实有gRPC端口的信息:
    在这里插入图片描述
    • 至于cloud-server-side如何将端口号提交到eureka,以及cloud-client-side为何会使用DiscoveryClientNameResolver来处理eureka的服务列表信息,就不在本文中讨论了,您要是有兴趣深入研究eureka,可以参考《程序员欣宸文章汇总(Spring篇)》中的<font color="blue">Eureka源码分析专题</font>,如下图:
    在这里插入图片描述
    • 至此,基于eureka的gRPC服务注册发现的开发和验证就完成了,希望本文可以给您带来一些参考,让您的服务在注册中心的加持下更加灵活和可靠;

    你不孤单,欣宸原创一路相伴

    1. Java系列
    2. Spring系列
    3. Docker系列
    4. kubernetes系列
    5. 数据库+中间件系列
    6. DevOps系列

    欢迎关注公众号:程序员欣宸

    微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
    https://github.com/zq2599/blog_demos

    相关文章

      网友评论

          本文标题:java版gRPC实战之七:基于eureka的注册发现

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