gRPC in java version 7: Registration discovery based on eureka

Links to the full series of "java version gRPC actual combat"

  1. Generate code with proto
  2. Service publishing and invocation
  3. Server stream
  4. Client stream
  5. Bidirectional flow
  6. The client dynamically obtains the server address
  7. Registration discovery based on eureka

About eureka

When we develop the client application, the required server address is set according to the following steps:

  • Configure in application.yml, as shown in the following figure:
  • In the bean using gRPC, the Stub class can be injected into the member variable by using the annotation GrpcClient:
  • The advantages of the above operation methods are easy to use and good configuration, and the disadvantages are also obvious: once the IP address or port of the server changes, you must modify application.yml and restart the client application;
  • Smart, you must have thought of the way to deal with it: Registration Center! Yes, with the registry, as long as our client can get the latest server address from the registry, there is no need to manually configure it. The following is the general description of eureka:

Overview of this article

  • If you have Spring Cloud development experience, you should be familiar with resttemplate and feign, but gRPC calls in Spring Cloud environment are not so common. The goal of this article is to master gRPC calls in Spring Cloud environment through practical combat. It is divided into the following chapters and sections:
  1. eureka application development
  2. gRPC server development
  3. gRPC client development
  4. verification
  5. A little doubt

Source download

  • The complete source code in this actual combat can be downloaded from GitHub. The address and link information are shown in the table below( https://github.com/zq2599/blog_demos):

name

link

remarks

Project Home

https://github.com/zq2599/blog_demos

The project is on the GitHub home page

git warehouse address (https)

https://github.com/zq2599/blog_demos.git

The warehouse address of the source code of the project, https protocol

git warehouse address (ssh)

git@github.com:zq2599/blog_demos.git

The project source code warehouse address, ssh protocol

  • There are multiple folders in the git project. The source code of the gRPC practical combat series for java is in the gRPC tutorials folder, as shown in the red box below:
  • There are multiple directories under the grpc tutorials folder. The eureka code corresponding to this article is in the cloud eureka directory, the server code is in the cloud server side directory, and the client code is in the cloud client side directory, as shown in the following figure:

eureka application development

  • Create a new module named cloud Eureka under the parent project grpc tutorials, and its build.gradle content is as follows:
// Using the springboot plug-in
plugins {
    id 'org.springframework.boot'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    // Rely on eureka
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
    // Dependencies required for state exposure
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    // Projects that rely on automatic source code generation
    implementation project(':grpc-lib')
}
  • Set your own web port number and application name in the configuration file bootstrap.yml. In addition, please change the configuration of eureka.client.serviceUrl.defaultZone to your own 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
  • This module has only one class 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);
    }
}
  • The above is a simple and general eureka service;

gRPC server development

  • The gRPC server that relies on eureka focuses on: first, configure to use eureka; second, do not specify the port;
  • Create a new module named cloud server side under the parent project gRPC tutorials. Its build.gradle content is as follows. Note that the starter related to gRPC server should be introduced:
// Using the springboot plug-in
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'
    // As a gRPC service provider, you need to use this library
    implementation 'net.devh:grpc-server-spring-boot-starter'
    // As eureka's client
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    // Dependencies required for state exposure
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    // Projects that rely on automatic source code generation
    implementation project(':grpc-lib')
    // The annotation processor will not be passed. Modules that use lombok generated code need to declare the annotation processor themselves
    annotationProcessor 'org.projectlombok:lombok'
}
  • Set your own application name in the configuration file application.yml. In addition, it is worth noting that the values of server.port and grpc.server.port are both 0, so the two ports will be automatically assigned unoccupied values:
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/
  • Start class 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);
    }
}
  • The GrpcServerService class that provides gRPC service is the same as that in the local server module:
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();
    }
}
  • The above is the server code. It can be seen that other parts are the same as the local server module except that gRPC port is set to 0 and eureka is normally used;

gRPC client development

  • The key points of the GRC client that relies on eureka are: first, the configuration uses eureka; second, the name of the GRC configuration item in the configuration should be equal to the name registered by the GRC server in eureka, as shown in the red box below:
  • Create a new module named cloud client side under the parent project gRPC tutorials. Its build.gradle content is as follows. Note that the starter related to gRPC client should be introduced:
// Using the springboot plug-in
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'
    // As a gRPC service user, you need to use this library
    implementation 'net.devh:grpc-client-spring-boot-starter'
    // As eureka's client
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    // Dependencies required for state exposure
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    // Projects that rely on automatic source code generation
    implementation project(':grpc-lib')
    // The annotation processor will not be passed. Modules that use lombok generated code need to declare the annotation processor themselves
    annotationProcessor 'org.projectlombok:lombok'
}
  • Set your own web port number in the configuration file application.yml. In addition, it should be noted that the name of the GRC configuration item cloud server side should be equal to the name registered by the GRC server in eureka, and the address configuration item is not required:
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:
    # The name of gRPC configuration. GrpcClient annotation will be used
    cloud-server-side:
      enableKeepAlive: true
      keepAliveWithoutCalls: true
      negotiationType: plaintext
  • Start the class CloudClientSideApplication.java, using eureka related annotations:
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);
    }
}
  • The service class GrpcServerService encapsulating gRPC calls is the same as that in the local server module. The GrpcClient annotation corresponds to the gRPC configuration item in the configuration:
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();
        }
    }
}
  • Create another web interface class, so that we can verify the gRPC service through web call:
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);
    }
}
  • After the client is developed, it can be verified next;

verification

  • Start cloud Eureka:
  • Start the cloud server side. It can be seen that the gRPC service port is automatically assigned 65141. However, we don't need to care about this value, because the client can get the following information from eureka:
  • Next, start cloud client side. After successful startup, the registration information of two services can be seen on eureka:
  • The browser accesses the web interface provided by cloud client side, and the response is as follows. It can be seen that cloud client side successfully invoked the GRC service of cloud server side:

A little doubt

  • If you know something about eureka, you may have some doubts: cloud client side the cloud server side information obtained from eureka should be the address and port of http service, and there should be no gRPC port number, because eureka's registration discovery service does not contain gRPC related information!
  • Due to space constraints, it is not suitable to analyze the above problems here. Let's focus on the core. I believe you will be enlightened at a glance;
  • DiscoveryClientNameResolver comes from grpc-client-spring-boot-autoconfigure.jar and is used to save the server information obtained from eureka. The annotation of this class has been made clear. Obtain the gRPC port number from the gRPC.port configuration item of metadata:
  • Put a breakpoint in the code of DiscoveryClientNameResolver and check the member variable instanceList. It can be seen that there is gRPC port information in the metadata:
  • How cloud server side submits the port number to eureka and why cloud client side uses DiscoveryClientNameResolver to process eureka's service list information are not discussed in this article. If you are interested in studying eureka in depth, you can refer to Programmer Xinchen article summary (Spring) Eureka source code analysis topic in, as shown in the following figure:
  • So far, the development and verification of gRPC service registration discovery based on eureka has been completed. I hope this paper can bring you some references to make your service more flexible and reliable with the support of the registry;

Posted by ashebrian on Tue, 07 Dec 2021 00:56:26 -0800