openplanning

Tìm hiểu về Spring Cloud Discovery Eureka Client với ví dụ

  1. Mục tiêu của bài học
  2. Tạo dự án Spring Boot
  3. @EnableEurekaClient
  4. Controller
  5. Chạy ứng dụng trên Eclipse
  6. Chạy các bản sao (replica)
  7. Test Discovery

1. Mục tiêu của bài học

Trong một hệ thống phân tán (Distributed System), các dịch vụ (ứng dụng) cần phải đăng ký với "Service Registration" (Dịch vụ đăng ký) để chúng có thể khám phá ra nhau.
Trong bài học trước chúng ta đã tạo ra một "Service Registration" sử dụng công nghệ của Netflix (Spring Cloud Netflix Eureka Server). Bạn có thể xem bài học này theo đường dẫn dưới đây:
OK, Trong bài học này chúng ta sẽ thảo luận làm thế nào để cấu hình cho một dịch vụ (ứng dụng) trong hệ thống phân tán để nó trở thành một Eureka Client. Có nghĩa là nó sẽ được đăng ký với "Serivce Registration" (Eureka Server).
Các Eureka Client sẽ có được danh sách các Eureka Client khác trong hệ thống, chúng ta sẽ thao tác với các danh sách này với mã Java.

2. Tạo dự án Spring Boot

Trên Eclipse tạo một dự án Spring Boot.
  • Name: SpringCloudDiscoveryEurekaClient
  • Group: org.o7planning
  • Artifact: SpringCloudDiscoveryEurekaClient
  • Description: Spring Cloud Discovery (Eureka Client)
  • Package: org.o7planning.eurekaclient
Project đã được tạo ra:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.o7planning</groupId>
    <artifactId>SpringCloudDiscoveryEurekaClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringCloudDiscoveryEurekaClient</name>
    <description>Spring Cloud Discovery (Eureka Client)</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

3. @EnableEurekaClient

Sử dụng @EnableEurekaClient để chú thích (annotate) lên ứng dụng, bạn sẽ biến ứng dụng này trở thành một Eureka Client.
SpringCloudDiscoveryEurekaClientApplication.java
package org.o7planning.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication
public class SpringCloudDiscoveryEurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudDiscoveryEurekaClientApplication.class, args);
    }
    
}
application.yml
spring:
  application:
    name: ABC-SERVICE # ==> This is Service-Id
    

---
# Items that apply to ALL profiles:   
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
#      defaultZone: http://my-eureka-server.com:9000/eureka
      defaultZone: http://my-eureka-server-us.com:9001/eureka
#      defaultZone: http://my-eureka-server-fr.com:9002/eureka
#      defaultZone: http://my-eureka-server-vn.com:9003/eureka
server:
  port: 8000  
 
---
spring:
  profiles: abc-service-replica01
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka  
server:
  port: 8001   
    
---
spring:
  profiles: abc-service-replica02
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8002
 
---
spring:
  profiles: abc-service-replica03
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8003
 
---
spring:
  profiles: abc-service-replica04
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8004  
 
---
spring:
  profiles: abc-service-replica05
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8005

4. Controller

Khi các Eureka Client đăng ký với Eureka Server (Service Registration), nó có thể lấy được danh sách các Eureka Client khác đã đã ký với Eureka Server.
@Autowired
private DiscoveryClient discoveryClient;

...

// Get All Service Ids
List<String> serviceIds = this.discoveryClient.getServices();


// (Need!!) eureka.client.fetchRegistry=true
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);


for (ServiceInstance serviceInstance : instances) {
    System.out.println("URI: " + serviceInstance.getUri();
    System.out.println("Host: " + serviceInstance.getHost();
    System.out.println("Port: " + serviceInstance.getPort();
}
MainController.java
package org.o7planning.eurekaclient.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @ResponseBody
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home() {

        return "<a href='showAllServiceIds'>Show All Service Ids</a>";
    }

    @ResponseBody
    @RequestMapping(value = "/showAllServiceIds", method = RequestMethod.GET)
    public String showAllServiceIds() {

        List<String> serviceIds = this.discoveryClient.getServices();

        if (serviceIds == null || serviceIds.isEmpty()) {
            return "No services found!";
        }
        String html = "<h3>Service Ids:</h3>";
        for (String serviceId : serviceIds) {
            html += "<br><a href='showService?serviceId=" + serviceId + "'>" + serviceId + "</a>";
        }
        return html;
    }

    @ResponseBody
    @RequestMapping(value = "/showService", method = RequestMethod.GET)
    public String showFirstService(@RequestParam(defaultValue = "") String serviceId) {

        // (Need!!) eureka.client.fetchRegistry=true
        List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);

        if (instances == null || instances.isEmpty()) {
            return "No instances for service: " + serviceId;
        }
        String html = "<h2>Instances for Service Id: " + serviceId + "</h2>";

        for (ServiceInstance serviceInstance : instances) {
            html += "<h3>Instance: " + serviceInstance.getUri() + "</h3>";
            html += "Host: " + serviceInstance.getHost() + "<br>";
            html += "Port: " + serviceInstance.getPort() + "<br>";
        }

        return html;
    }

    // A REST method, To call from another service.
    // See in Lesson "Load Balancing with Ribbon".
    @ResponseBody
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {

        return "<html>Hello from ABC-SERVICE</html>";
    }

}

5. Chạy ứng dụng trên Eclipse

Trước hết phải đảm bảo rằng bạn đã chạy Eureka Server:
Xem bài học trước để chạy một Eureka Server:
Sau đó bạn có thể chạy Eureka Client trực tiếp trên Eclipse, nó sẽ được đăng ký với Eureka Server.
Truy cập vào URL dưới đây, và bạn có thể nhìn thấy các Eureka Client đã đăng ký với Eureka Server.

6. Chạy các bản sao (replica)

Sử dụng chức năng "Maven Install" để tạo ra tập tin jar từ project. Nhấn phải chuột vào project chọn:
  • Run As/Maven Install
Và bạn có một tập tin jar trong thư mục target của project.
Copy tập tin jar vừa được tạo ra vào một thư mục nào đó, và tạo 2 tập tin BAT:
  • abc-service-replica01.bat
  • abc-service-replica02.bat
  • abc-service-replica03.bat
  • abc-service-replica04.bat
  • abc-service-replica05.bat
abc-service-replica01.bat
java -jar -Dspring.profiles.active=abc-service-replica01 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica02.bat
java -jar -Dspring.profiles.active=abc-service-replica02 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica03.bat
java -jar -Dspring.profiles.active=abc-service-replica03 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica04.bat
java -jar -Dspring.profiles.active=abc-service-replica04 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica05.bat
java -jar -Dspring.profiles.active=abc-service-replica05 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
Chạy 2 tập tin BAT:
Trên Eureka Monitor bạn có thể nhìn thấy các Eureka Client đã được đăng ký với Eureka Server.

7. Test Discovery

OK, sau khi chạy Eureka Client, bạn có thể xem cách nó khám phá các Eureka Client khác.
Truy cập URL dưới đây (Chú ý, đợi 30 giây để đảm bảo Eureka ServerEureka Client đã cập nhập đầy đủ các trạng thái của nhau).