ribbon load balancing and feign consumer call service

Microservice calls Ribbon

brief introduction
We talked about the registration and discovery of eureka services, but we didn't talk about the service call combined with eureka cluster.
In this case, we need to use the Ribbon, combined with eureka, to realize the service call;

Ribbon is a load balancer published by Netflix, which helps to control the behavior of HTTP and TCP clients. After the service provider address is configured for the ribbon, the ribbon can automatically help service consumers to request based on some load balancing algorithm. Ribbon provides us with many load balancing algorithms by default, such as polling, random, etc. Of course, we can also implement a custom load balancing algorithm for the ribbon.
In Spring Cloud, when the Ribbon is used with Eureka, the Ribbon can automatically obtain the service provider address list from Eureka Server, and request one of the service provider instances based on the load balancing algorithm. It shows the architecture of Ribbon when used with Eureka.

Preliminary application
Ribbon is the client side load balancing, so it must integrate the re consumer side, that is, the consumer side
We modify microservice-student-consumer-80
1. First, introduce dependency and add ribbon dependency to pom.xml

<!--ribbon Dependent dependence-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

2. Add configuration in application.yml file

server:
  port: 80
  context-path: /
eureka:
  client:
    service-url:
      defaultZone: http://eureka2001.su.com:2001/eureka/,http://eureka2002.su.com:2002/eureka/,http://eureka2003.su.com:2003/eureka/
    register-with-eureka: false


3. Add comments to the startup class

package com.su.microservicestudentconsumer80;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class MicroserviceStudentConsumer80Application {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentConsumer80Application.class, args);
    }

}


4. Add the load balancing annotation of ribbon in the configuration class (SpringCloudConfig.java)

package com.su.microservicestudentconsumer80.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;


@Configuration
public class SpringCloudConfig {

    @LoadBalanced   //Load balancing with ribbon
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}


5. Modify PRE_HOST in StudentConsumerController to the specified microservice application name

package com.su.microservicestudentconsumer80.controller;

import com.su.microservicecommon.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;


@RestController
@RequestMapping("/student")
public class StudentConsumerController {

    private final static String SERVER_IP_PORT = "http://MICROSERVICE-STUDENT";

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping(value="/save")
    private boolean save(Student student){
        return restTemplate.postForObject(SERVER_IP_PORT+"/student/save", student, Boolean.class);
    }

    @GetMapping(value="/list")
    public List<Student> list(){
        return restTemplate.getForObject(SERVER_IP_PORT+"/student/list", List.class);
    }

    @GetMapping(value="/get/{id}")
    public Student get(@PathVariable("id") Integer id){
        return restTemplate.getForObject(SERVER_IP_PORT+"/student/get/"+id, Student.class);
    }

    @GetMapping(value="/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id){
        try{
            restTemplate.getForObject(SERVER_IP_PORT+"/student/delete/"+id, Boolean.class);
            return true;
        }catch(Exception e){
            return false;
        }
    }
}


6. You also need to change the configuration under the application.yml file in microservice-student-provider-1001. (note hierarchy)

application:
    name: microservice-student

7. After the test, start the registration center eureka, then the service provider provider, and finally the service consumer
Display effect:

2, ribbon load balancing

According to microservice-student-provider-1001, build a microservice-student-provider subproject

1. Import related pom dependencies in the new module (all of them are dependencies in 1001module)

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.su</groupId>
        <artifactId>sumicroservice</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>microservice-student-provider</artifactId>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!--  Effective immediately after modification, hot deployment  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>com.su</groupId>
            <artifactId>microservice-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <!--Add registry Eureka Related configuration-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!-- actuator Monitoring introduction -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

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

</project>


2. Add the annotation of the startup class in 1001module to the new module

package com.su.microservicestudentprovider;

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

@EntityScan("com.su.*.*")
@EnableEurekaClient
@SpringBootApplication
public class MicroserviceStudentProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentProviderApplication.class, args);
    }

}


3. Add yml file configuration

---
server:
  port: 1001
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  application:
    name: microservice-student
  profiles: provider-1001

eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1001
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.su.com:2001/eureka/,http://eureka2002.su.com:2002/eureka/,http://eureka2003.su.com:2003/eureka/

info:
  groupId: com.su.testSpringcloud
  artifactId: microservice-student-provider-1001
  version: 1.0-SNAPSHOT
  userName: http://su.com
  phone: 123456

---
server:
  port: 1002
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  application:
    name: microservice-student
  profiles: provider-1002

eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1002
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.su.com:2001/eureka/,http://eureka2002.su.com:2002/eureka/,http://eureka2003.su.com:2003/eureka/

info:
  groupId: com.su.testSpringcloud
  artifactId: microservice-student-provider-1002
  version: 1.0-SNAPSHOT
  userName: http://su.com
  phone: 123456

---
server:
  port: 1003
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  application:
    name: microservice-student
  profiles: provider-1003

eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1003
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.su.com:2001/eureka/,http://eureka2002.su.com:2002/eureka/,http://eureka2003.su.com:2003/eureka/

info:
  groupId: com.su.testSpringcloud
  artifactId: microservice-student-provider-1003
  version: 1.0-SNAPSHOT
  userName: http://su.com
  phone: 123456


4. Add methods to StudentProviderController.java to better reflect the effect of load balancing

@Value("${server.port}")
private String port;

@RequestMapping("/ribbon")
public String ribbon(){
    return "Job number ["+port+"]Serving you";
}


5. At the same time, add methods to the consumer
StudentConsumerController.java

@RequestMapping("/ribbon")
public String ribbon(){
    return restTemplate.getForObject(SERVER_IP_PORT + "/student/ribbon", String.class);
}

6. Test
Start in turn


3, Brief introduction and application of feign
Introduction:
Feign is a declarative Web Service client, which makes it easier to write a Web Service client. We just need to use feign to create an interface and configure it with annotations. It has pluggable annotation support, including feign annotation and JAX-RS annotation. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotation to feign, and integrates Ribbon and Eureka to provide load balanced HTTP client implementation.
This seems rather muddled. Let's talk about the actual use. The previous Ribbon calls the service provider through restTemplate. The disadvantage is that the same request needs to be written multiple times, which is not convenient for unified maintenance. When Feign comes, it's directly to make a service as FeignClient, and then other calls to the Controller need to be used directly Connect the injection service and call the service method directly; meanwhile, Feign integrates the Ribbon and Eureka, so if you want to configure the load balance, you can configure the Ribbon directly, without any other special place; of course, Fiegn also integrates the service fault-tolerant protection, breaker Hystrix, later on.

Application:

Build a service in the common project (the actual project must be multiple services) as Feign client, use Feign client to call the server provider, of course, you can configure load balancing; the purpose of Feign client definition is to facilitate the call to other projects; modify microservice common

1. Introducing Feign dependency into pom.xml:

<!--Introduce Feign rely on-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

2. Create service interface
StudentClientService.java

package com.su.microservicecommon.service;

import com.su.microservicecommon.entity.Student;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;


@FeignClient(value="MICROSERVICE-STUDENT")
public interface StudentClientService {

    /**
     * Query student information according to id
     * @param id
     * @return
     */
    @GetMapping(value="/student/get/{id}")
    public Student get(@PathVariable("id") Integer id);

    /**
     * Query student information
     * @return
     */
    @GetMapping(value="/student/list")
    public List<Student> list();

    /**
     * Add or modify student information
     * @param student
     * @return
     */
    @PostMapping(value="/student/save")
    public boolean save(Student student);

    /**
     * Delete student information according to id
     * @return
     */
    @GetMapping(value="/student/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id);

    @RequestMapping("/student/ribbon")
    public String ribbon();
}


3. Create a Feign consumer project; refer to microservice-student-consumer-80 to create a microservice-student-consumer-feign-80
Copy all the codes

pom dependence

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.su</groupId>
        <artifactId>sumicroservice</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>microservice-student-consumer-feign-80</artifactId>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <!--  Effective immediately after modification, hot deployment  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>com.su</groupId>
            <artifactId>microservice-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <!--ribbon Dependent dependence-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!--Introduce Feign rely on-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>

    </dependencies>

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

</project>


4. Add configuration class
SpringCloudConfig.java

package com.su.microservicestudentconsumerfeign80.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RetryRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;


@Configuration
public class SpringCloudConfig {

    @LoadBalanced  // Introducing ribbon load balancing
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    /**
     * Custom call rules (the service provider will not call after dropping the line to solve the polling problem)
     * @return
     */
    @Bean
    public IRule myRule(){
        return new RetryRule();
//        return new RandomRule();
    }
}


5. Add yml profile configuration

server:
  port: 80
  context-path: /
eureka:
  client:
    service-url:
      defaultZone: http://eureka2001.su.com:2001/eureka/,http://eureka2002.su.com:2002/eureka/,http://eureka2003.su.com:2003/eureka/
    register-with-eureka: false



6. Add comments to the consumer startup class

package com.su.microservicestudentconsumerfeign80;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableEurekaClient
@EnableFeignClients(value = "com.su.*.*")
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class MicroserviceStudentConsumerFeign80Application {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentConsumerFeign80Application.class, args);
    }

}


7. Write the controller method. Because Fiegn is used now, the restTemplate is removed, and the rest template is injected into the service. The service method is called to implement the service call

package com.su.microservicestudentconsumerfeign80.controller;

import com.su.microservicecommon.entity.Student;
import com.su.microservicecommon.service.StudentClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;


@RestController
@RequestMapping("/student")
public class StudentConsumerController {

    @Autowired
    private StudentClientService studentClientService;

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping(value = "/save")
    private boolean save(Student student) {
        return studentClientService.save(student);
    }

    @GetMapping(value = "/list")
    public List<Student> list() {
        return studentClientService.list();
    }

    @GetMapping(value = "/get/{id}")
    public Student get(@PathVariable("id") Integer id) {
        return studentClientService.get(id);
    }

    @GetMapping(value = "/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id) {
        try {
            studentClientService.delete(id);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @RequestMapping("/ribbon")
    public String ribbon(){
        return studentClientService.ribbon();
    }
}

8. Test

Hang up 1002 in the background and refresh the page

Then the problem of whether there is a possibility of downtime in load balancing will be solved, and restarting the just hung class will automatically continue to access without any impact

Published 61 original articles, won praise 8, visited 1675
Private letter follow

Tags: Spring Java MySQL Maven

Posted on Sat, 11 Jan 2020 08:13:42 -0500 by pella.d