2, Service call

1, RestTemplate service interface call

RestTemplate

  • getForEntity: the returned object is the object converted from the data in the response body, which can be basically understood as Json;
  • getForObject: the returned object is the ResponseEntity object, which contains some important information in the response, such as response header, response status code, response body, etc;
  • postForEntity: getBody() is required to obtain body data;
  • postForObject: directly return body data;

1. Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing

2, Ribbon load balancing service call

1. What is it

Netflix/ribbon

  • Spring Cloud Ribbon is a set of client-side load balancing tools based on Netflix Ribbon;
    In short, Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms and service calls on the client.
  • The Ribbon client component provides a series of complete configuration items, such as connection timeout, Retry, etc;
    Simply put, list all the machines behind the Load Balancer (LB) in the configuration file. The Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). We can easily use Ribbon to implement a custom load balancing algorithm.
1.1 Ribbon architecture description
  • Ribbon works in two steps:
  1. The first step is to select Eureka Server, which gives priority to servers with less load in the same region;
  2. The second step is to select an address from the service registration list obtained from the Server according to the policy specified by the user;
  • Ribbon provides a variety of strategies: such as polling, random, and weighting according to response time.
  • Summary: Ribbon is actually a client component of soft load balancing. It can be used in combination with other clients requiring requests. The combination with Eureka is just one example.
1.2 Eureka client integrated ribbon
<!--eureka-client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--eureka-client Integrated ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2. What can I do

2.1 what is load balancing
  • Simply put, the user's requests are evenly distributed to multiple services, so as to achieve the HA (high availability) of the system;
  1. Centralized load balancing
    That is, an independent LB facility (either hardware such as F5 or software such as Nginx) is used between the service consumer and the service provider, and the facility is responsible for forwarding the access request to the service provider through some policy;
  2. In process load balancing
    Integrate LB logic into the consumer. The consumer knows which addresses are available from the service registry, and then selects an appropriate server from these addresses;
  • Common load balancing software includes Nginx, LVS, hardware F5, etc;
2.2 client load balancing VS server load balancing
  • Ribbon local load balancing, when calling the micro service interface, will obtain the registration information service list in the registry and cache it to the local JVM, so as to realize the RPC remote service call technology locally.
  • Nginx is server load balancing. All client requests will be handed over to nginx, and then nginx will forward the requests; That is, load balancing is realized by the server.

3. Ribbon core component IRule

IRule: select a service to be accessed from the service list according to a specific algorithm;

3.1 polling

com.netflix.loadbalancer.RoundRobinRule

3.2 random

com.netflix.loadbalancer.RandomRule

3.3 first obtain the service according to the roundrobin rule policy. If the service acquisition fails, it will retry within the specified time to obtain the available service

com.netflix.loadbalancer.RetryRule

3.4 for the extension of roundrobin rule, the faster the response speed, the greater the instance selection weight, and the easier it is to be selected

WeightedResponseTimeRule

3.5 first filter out the services in the circuit breaker tripping state due to multiple access faults, and then select a service with the least concurrency

BestAvailableRule

3.6 filter out fault instances first, and then select smaller concurrent instances

AvailabilityFilteringRule

3.7 the default rule is to judge the performance of the region where the Server is located and the availability of the Server, and select the Server

ZoneAvoidanceRule

4. Modify random strategy

cloud-consumer-order-eureka80

4.1 modifying RestTemplate

RestTemplate annotated @ LoadBalanced

@Configuration
public class ApplicationContextBean {

    // applicationContext.xml > <bean id="" class="" />
    @Bean
    // Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing
    // Customize the load balancing policy without @ LoadBalanced annotation
	@LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
4.2 create a new class - com.qs.rule.MySelfRule

The official document clearly gives a warning: this custom configuration class cannot be placed under the current package and sub package scanned by @ ComponentScan, otherwise our custom configuration class will be shared by all Ribbon clients and the purpose of special customization will not be achieved.

@Configuration
public class MySelfRule {

    @Bean
    public IRule myRule() {
        // Modify random strategy
        return new RandomRule();
    }
}
4.3 main startup

Annotate @ RibbonClient

@SpringBootApplication
// Enable EurekaClient
@EnableEurekaClient
// When the microservice is started, we can load our custom Ribbon configuration class to make the configuration take effect
@RibbonClient(name = "PROVIDER-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain80 {

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

http://localhost/order/get/1

5. Polling algorithm

  • The Rest interface count starts from 1 after each service restart
    Number of requests for Rest interface% total number of server clusters = actual call server location subscript
List<ServiceInstance> instances = discoveryClient.getInstances("PAYMENT-SERVICE-SERVICE");
List [0] instances = 127.0.0.1:8002;
List [1] instances = 127.0.0.1:8001;

8001 + 8002 They are combined into clusters. There are 2 machines in total, and the total number of clusters is 2. According to the principle of polling algorithm:
When the total number of requests is 1: 1 % 2 =1 If the corresponding subscript position is 1, the service address is 127.0.0.1:8001
 When the total request digit is 2: 2 % 2 =0 If the corresponding subscript position is 0, the service address is 127.0.0.1:8002
 When the total request digit is 3: 3 % 2 =1 If the corresponding subscript position is 1, the service address is 127.0.0.1:8001
 When the total request digit is 4: 4 % 2 =0 If the corresponding subscript position is 0, the service address is 127.0.0.1:8002
 And so on......

6. Customize polling policy

cloud-consumer-order-eureka80

6.1 modifying RestTemplate

RestTemplate remove annotation @ LoadBalanced

@Configuration
public class ApplicationContextBean {

    // applicationContext.xml > <bean id="" class="" />
    @Bean
    // Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing
    // Customize the load balancing policy without @ LoadBalanced annotation
//    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
6.2 new interface - com.qs.springcloud.lb.LoadBalancer
public interface LoadBalancer {

    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
6.3 create a new class - com.qs.springcloud.lb.MyLoadBalancer
@Component
@Slf4j
public class MyLoadBalancer implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement() {
        int current, next;
        do {
            current = atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1;
            // Spin lock
        } while (!atomicInteger.compareAndSet(current, next));
        log.info("next: " + next);
        return next;
    }

    /**
     * Load balancing algorithm:
     * The Rest interface count starts from 1 after each service restart
     * Rest Number of interface requests% total number of server clusters = actual call server location subscript
     */
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}
6.4 main startup
@SpringBootApplication
// Enable EurekaClient
@EnableEurekaClient
public class OrderMain80 {

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

http://localhost/order/lb

3, OpenFeign service interface call

1. What is it

Official website explanation ,GitHub

  1. Feign is a declarative web service client. Using feign can make it easier to write a web service client;
  2. Its usage method is to define a service interface and then add annotations on it. Feign also supports pluggable encoders and decoders;
  3. Spring Cloud encapsulates Feign to support Spring MVC standard annotations and HttpMessageConverters;
  4. Feign can be used in combination with Eureka and Ribbon to support load balancing.

2. What can I do

  1. Feign aims to make it easier to write Java Http clients;
  2. When Ribbon+RestTemplate is used earlier, a set of template calling methods is formed by encapsulating Http requests with RestTemplate. However, in actual development, because there may be more than one invocation of service dependencies, and often one interface will be invoked in multiple places, some client classes are usually encapsulated for each micro service to package the invocation of these dependent services;
  3. Therefore, Feign made further encapsulation on this basis to help us define and implement the definition of dependent service interfaces. Under the implementation of Feign, we only need to create an interface and configure it by annotation (previously, the Dao interface was marked with Mapper annotation, but now it is a micro service interface marked with Feign annotation), so as to complete the interface binding to the service provider, which simplifies the development of automatically encapsulating the service call client when using the Spring cloud Ribbon.
2.1 Feign integrates Ribbon
  • The Ribbon is used to maintain the service list information of Payment, and the load balancing of the client is realized through polling;
  • Unlike Ribbon, Feign only needs to define the service binding interface, and implements the service invocation gracefully and simply in a declarative way.

3. Differences between feign and OpenFeign

3.1 Feign
  1. Feign is a lightweight RESTful HTTP service client in the Spring Cloud component;
  2. Feign has built-in Ribbon, which is used for client load balancing to call the service of the service registry;
  3. Feign is used by using feign's annotation to define an interface. By calling this interface, you can call the service of the service registry.
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
3.2 OpenFeign
  1. OpenFeign is a Spring Cloud that supports spring MVC annotations based on Feign, such as @ RequesMapping;
  2. OpenFeign's @ FeignClient can parse the interface under the @ RequestMapping annotation of spring MVC, generate implementation classes through dynamic proxy, implement load balancing in the classes and call other services.
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

4. Steps for using openfeign

4.1 create a new module cloud consumer order feign80
4.2 POM
<?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">
    <parent>
        <artifactId>cloud-2020</artifactId>
        <groupId>com.qs.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order80-feign</artifactId>

    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

        <!--custom API General package-->
        <dependency>
            <groupId>com.qs.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--Hot deployment-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
4.3 YML
server:
  port: 80

eureka:
  client:
    # false indicates whether to register yourself with EurekaServer. The default is true
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka
4.4 main startup
@SpringBootApplication
// Open @ FeignClient annotation
@EnableFeignClients
public class OrderFeignMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class, args);
    }
}
4.5 new interface PaymentFeignService
@Component
@FeignClient("PROVIDER-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping("/payment/get/{id}")
    CommonResult get(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feignTimeOut")
    String feignTimeOut();
}
4.6 new class - OrderFeignController
@RestController
@RequestMapping("order")
@Slf4j
public class OrderFeignController {

    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping("get/{id}")
    public CommonResult get(@PathVariable("id") Long id) {
        CommonResult commonResult = paymentFeignService.get(id);
        log.info("commonResult = " + commonResult);
        return commonResult;
    }

    @GetMapping("feignTimeOut")
    public String feignTimeOut() {
        return paymentFeignService.feignTimeOut();
    }
}
4.7 testing

http://localhost/order/get/1

4.8 modifying PaymentController

Thread pause for 3 seconds (Feign default timeout of 1 second)

@RestController
@RequestMapping("payment")
@Slf4j
public class PaymentController {
	/**
     * Test Feign connection timeout
     * @return
     */
    @GetMapping("feignTimeOut")
    public String feignTimeOut() {
        // Thread pause for 3 seconds (Feign default timeout of 1 second)
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("serverPort = " + serverPort);
        return serverPort;
    }
}
4.9 timeout test

http://localhost/order/feignTimeOut

5. OpenFeign timeout control

  • OpenFeign will wait for 1 second by default, and an error will be reported after it is exceeded;
  • By default, the Feign client only waits for 1 second, but the server processing takes more than 1 second. As a result, the Feign client does not want to wait and directly returns an error.
    To avoid this situation, sometimes we need to set the timeout control of Feign client.
## OpenFeign timeout control
## Set Feign client timeout (OpenFeign supports Ribbon by default)
ribbon:
  # It refers to the time taken to establish a connection, which is applicable to the time taken to connect both ends under normal network conditions
  ReadTimeout: 5000
  # It refers to the time taken to read available resources from the server after the connection is established
  ConnectTimeout: 5000

6. OpenFeign log printing function

  • Feign provides the log printing function. We can adjust the log level through configuration to understand the details of Http requests in feign;
  • To put it bluntly, it is to monitor and output the call of Feign interface;
  • Log level:
  1. NONE: default, no logs are displayed;
  2. BASIC: only record the request method, URL, response status code and execution time;
  3. HEADERS: in addition to the information defined in BASIC, there are also header information of request and response;
  4. FULL: in addition to the information defined in HEADERS, there are also the body and metadata of the request and response.
6.1 create FeignConfig
@Configuration
public class FeignConfig {

    /**
     * OpenFeign Log printing function
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
6.2 YML
## OpenFeign log printing function
logging:
  level:
    # At what level does Feign log monitor which interface
    com.qs.springcloud.service.PaymentFeignService: debug
6.3 testing

http://localhost/order/get/1

Tags: Spring Cloud ribbon RestTemplate

Posted on Wed, 13 Oct 2021 12:46:26 -0400 by charlestide