Spring Cloud learning - medium

1.Spring Cloud learning

  • Feign declarative service invocation
  • Hystrix fuse
  • Gateway gateway

2.Feign

2.1 feign general

• Feign is a declarative REST client, which uses interface based annotation to facilitate client configuration.
• Feign was originally provided by Netflix, but does not support spring MVC annotation. Later, it was encapsulated by spring cloud and supports spring MVC annotation
Solution, making it easier for users to accept

2.2-Feign-quick start

  1. Introduce open feign dependency on the consumer side
   <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  1. Write Feign call interface
package com.itheima.consumer.feign;


import com.itheima.consumer.config.FeignLogConfig;
import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 *
 * feign Declarative interface. To initiate a remote call.
 *
 String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
 Goods goods = restTemplate.getForObject(url, Goods.class);
 *
 * 1. Define interface
 * 2. Add the annotation @ FeignClient on the interface and set the value attribute to the application name of the service provider
 * 3. Write the calling interface, and the declaration rules of the interface shall be consistent with the provider interface.
 * 4. Inject the interface object and call the interface method to complete the remote call
 */
@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {
    @GetMapping("/goods/findOne/{id}")
    public Goods findGoodsById(@PathVariable("id") int id);
}

OrderController

package com.itheima.consumer.controller;


import com.itheima.consumer.domain.Goods;
import com.itheima.consumer.feign.GoodsFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private GoodsFeignClient goodsFeignClient;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){

        /*
        String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
        // 3. Call method
        Goods goods = restTemplate.getForObject(url, Goods.class);

        return goods;*/

        Goods goods = goodsFeignClient.findGoodsById(id);

        return goods;
    }


}

goodsFeignClient reports red, which does not affect the use

  1. Add the @ EnableFeignClients annotation in the startup class to enable the Feign function
package com.itheima.consumer;

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;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient // Activate DiscoveryClient
@EnableEurekaClient
@SpringBootApplication

@EnableFeignClients //Enable Feign's function
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

  1. Test call

2.3 feign timeout configuration

• Feign bottom layer relies on Ribbon to realize load balancing and remote call.
• Ribbon defaults to 1 second timeout.
• timeout configuration:

feign-consumer application.yml

# Set the timeout for the Ribbon
ribbon:
  ConnectTimeout: 1000 # The default connection timeout is 1s. The default unit is milliseconds
  ReadTimeout: 3000 # The timeout of logical processing is 1s by default, and the default unit is milliseconds

2.4 feign logging

• Feign can only record debug level log information.

feign-consumer application.yml

# Set the current log level to debug. feign only supports logging at the debug level
logging:
  level:
    com.itheima: debug

• define Feign log level Bean

FeignLogConfig

package com.itheima.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignLogConfig {
    /*
        NONE,No record
        BASIC,Record the basic request line and response status code data
        HEADERS,Record the basic request line, response status code data, and record the response header information
        FULL;Record the completed request response data
     */
    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

• enable the Bean:

package com.itheima.consumer.feign;


import com.itheima.consumer.config.FeignLogConfig;
import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 *
 * feign Declarative interface. To initiate a remote call.
 *
 String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
 Goods goods = restTemplate.getForObject(url, Goods.class);
 *
 * 1. Interface definition
 * 2. Add the annotation @ FeignClient on the interface and set the value attribute to the application name of the service provider
 * 3. Write the calling interface, and the declaration rules of the interface shall be consistent with the provider interface.
 * 4. Inject the interface object and call the interface method to complete the remote call
 */

@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {

    @GetMapping("/goods/findOne/{id}")
    public Goods findGoodsById(@PathVariable("id") int id);

}

3.Hystrix

3.1-Hystrix - General

• Hystix is an open-source delay and fault-tolerant Library of Netflix, which is used to isolate access to remote services and third-party libraries and prevent cascading failures (avalanches).
• avalanche: when a service fails, the service of the whole link fails

Main functions of Hystix
• isolation

​ Thread pool isolation
​ Semaphore isolation

• degradation: abnormal, timeout
• fusing
• current limiting

3.2-Hystrix-downgrade

3.2.1 - provider degradation

Hystix degradation: when the service has an exception or the call times out, the default data is returned

Service provider downgrade

  1. In the service provider, introduce hystrix dependency

            <!-- hystrix -->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
             </dependency>
    
  2. Define degradation method

 /**
     * Define the degradation method:
     *  1. The return value of the method needs to be the same as the original method
     *  2. The parameters of the method need to be the same as the original method
     */
    public Goods findOne_fallback(int id){
        Goods goods = new Goods();
        goods.setTitle("Demoted~~~");

        return goods;
    }
  1. Use the @ HystrixCommand annotation to configure the degradation method
/**
     * Downgrade:
     *  1. An exception occurred
     *  2. Service call timeout
     *      * Default 1s timeout
     *
     *  @HystrixCommand(fallbackMethod = "findOne_fallback")
     *      fallbackMethod: Specifies the name of the method that is called after downgrading.
     */
    @GetMapping("/findOne/{id}")
    @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
            //Set the timeout time of Hystrix, which is 1s by default
 @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public Goods findOne(@PathVariable("id") int id){

        //1. Make an exception
        int i = 3/0;
        try {
            //2. Sleep for 2 seconds
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Goods goods = goodsService.findOne(id);

        goods.setTitle(goods.getTitle() + ":" + port);//Set the port number to the product title
        return goods;
    }
  1. Start the Hystrix function on the startup class: @ enablercircuitbreaker
package com.itheima.provider;

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

/**
 * Startup class
 */
@EnableEurekaClient //This annotation can be omitted in the new version
@SpringBootApplication
@EnableCircuitBreaker // Turn on the Hystrix function
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

3.2.2 - consumer demotion

  1. feign component has integrated the hystrix component.

  2. Define feign call interface implementation class and copy method, that is, degradation method

    GoodsFeignClientFallback

package com.itheima.consumer.feign;

import com.itheima.consumer.domain.Goods;
import org.springframework.stereotype.Component;

/**
 * Feign Degradation processing class of client
 * 1. Define a class to implement Feign client interface
 * 2. Use the @ Component annotation to add the Bean of this class to the SpringIOC container
 */
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
    @Override
    public Goods findGoodsById(int id) {
        Goods goods = new Goods();
        goods.setTitle("Demoted again~~~");
        return goods;
    }
}

  1. Use the fallback attribute in the @ FeignClient annotation to set the degradation processing class.

    GoodsFeignClient

package com.itheima.consumer.feign;


import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {
    @GetMapping("/goods/findOne/{id}")
    public Goods findGoodsById(@PathVariable("id") int id);

}

  1. Configure and enable feign hystrix. enabled = true

    application.yml

# Enable feign's support for hystrix
feign:
  hystrix:
    enabled: true

3.3-Hystrix fuse

3.3.1 - fusing - concept

• Hystrix fuse mechanism is used to monitor the microservice call. When the failure reaches the predetermined threshold (20 failures in 5 seconds), it will be turned on
Circuit breaker, reject all requests until service returns to normal.

The circuit breaker has three states: open, half open, closed

3.3.2 - fusing - code demonstration

Modify the service provider's method and demonstrate the circuit breaker mechanism

Fuse configuration

• circuitBreaker.sleepWindowInMilliseconds: monitoring time
• circuitBreaker. Requestvolumthreshold: number of failures
• circuitBreaker.errorThresholdPercentage: failure rate

GoodsController

package com.itheima.provider.controller;

import com.itheima.provider.domain.Goods;
import com.itheima.provider.service.GoodsService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * Goods Controller service provider 
 */

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

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

    /**
     * Downgrade:
     *  1. An exception occurred
     *  2. Service call timeout
     *      * Default 1s timeout
     *
     *  @HystrixCommand(fallbackMethod = "findOne_fallback")
     *      fallbackMethod: Specifies the name of the method that is called after downgrading.
     */

 @GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
         //Set the timeout time of Hystrix, which is 1s by default
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //The monitoring time is 5000 milliseconds by default
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
            //Number of failures. Default 20 times
 @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
            //The default failure rate is 50%
 @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50") })
    public Goods findOne(@PathVariable("id") int id){
        //If id == 1, an exception occurs= 1 normal access
        if(id == 1){
            //1. Make an exception
            int i = 3/0;
        }
        /*try {
            //2. Sleep for 2 seconds
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        Goods goods = goodsService.findOne(id);

        goods.setTitle(goods.getTitle() + ":" + port);//Set the port number to the product title
        return goods;
    }


    /**
     * Define the degradation method:
     *  1. The return value of the method needs to be the same as the original method
     *  2. The parameters of the method need to be the same as the original method
     */
    public Goods findOne_fallback(int id){
        Goods goods = new Goods();
        goods.setTitle("Demoted~~~");

        return goods;
    }

}

3.3.3 - fuse monitoring

• Hystrix provides the function of Hystrix dashboard, which is used to monitor the running status of microservices in real time.
• however, the hystrix dashboard can only monitor one microservice.
• Netflix also provides Turbine for aggregation monitoring.

For fuse monitoring installation, please check the Turbine construction steps md

4.Gateway

4.1 gateway overview

  • Gateway aims to provide a simple and effective unified API routing management method for microservice architecture.

  • In the microservice architecture, different microservices can have different network addresses. Each microservice completes a user request by calling each other. The client may complete a user request by calling the interfaces of N microservices.

  • Existing problems:

	1.The client requests different microservices many times, which increases the complexity of the client
	2.Authentication is complex, and every service needs to be authenticated
	3.http The number of requests for different services increases, and the performance is not high
  • Gateway is the entrance of the system. It encapsulates the internal structure of the application and provides unified services for the client. Some public logic independent of the business function can be realized here, such as authentication, authentication, monitoring, caching, load balancing, traffic control, routing forwarding, etc

  • Among the current gateway solutions, there are Nginx+ Lua, Netflix Zuul, Spring Cloud Gateway and so on

4.2-Gateway-quick start

  1. Build gateway module

    Create API gateway server module

  2. Introduction dependency: Starter gateway

     <dependencies>
            <!--introduce gateway gateway-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <!-- eureka-client -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
        </dependencies>
    
  3. Write startup class

    package com.itheima.gateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class ApiGatewayApp {
    
        public static void main(String[] args) {
            SpringApplication.run(ApiGatewayApp.class,args);
        }
    
    }
    
    
  4. Write configuration file

    application.yml

    server:
      port: 80
    
    spring:
      application:
        name: api-gateway-server
    
      cloud:
        # Gateway configuration
        gateway:
          # Routing configuration: forwarding rules
          routes: #Gather.
          # id: unique identification. The default is a UUID
          # uri: forwarding path
          # Predictions: conditions used to request matching rules for gateway paths
    
    
          - id: gateway-provider
            uri: http://localhost:8001/
            predicates:
            - Path=/goods/**
    
  5. Start test

4.3-Gateway-static routing

application. Static routing is written in uri

server:
  port: 80

spring:
  application:
    name: api-gateway-server

  cloud:
    # Gateway configuration
    gateway:
      # Routing configuration: forwarding rules
      routes: #Gather.
      # id: unique identification. The default is a UUID
      # uri: forwarding path
      # Predictions: conditions used to request matching rules for gateway paths
      # Filters: to configure local filters
      - id: gateway-provider
        # Static routing
        uri: http://localhost:8001/
        predicates:
        - Path=/goods/**

4.4-Gateway-dynamic routing

Add @ EnableEurekaClient to the startup class (the new version can be added without)

package com.itheima.gateway;

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

@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {

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

}

Introduce Eureka client configuration

application. Modify uri attribute in YML: uri: lb: / / service name

server:
  port: 80

spring:
  application:
    name: api-gateway-server

  cloud:
    # Gateway configuration
    gateway:
      # Routing configuration: forwarding rules
      routes: #Gather.
      # id: unique identification. The default is a UUID
      # uri: forwarding path
      # Predictions: conditions used to request matching rules for gateway paths
      # Filters: to configure local filters

      - id: gateway-provider
      	# Static routing
        # uri: http://localhost:8001/
        # Dynamic routing
        uri: lb://GATEWAY-PROVIDER
        predicates:
        - Path=/goods/**

4.5 gateway microservice name configuration

application. Configuring microservice name in YML

      # Microservice name configuration
      discovery:
        locator:
          enabled: true # Set to true to add a microservice name before the request path
          lower-case-service-id: true # Lowercase allowed

4.6-Gateway-filter

4.6.1 - Filters - General

  • The Gateway supports the filter function to intercept requests or responses and complete some general operations.

  • Gateway provides two filter modes: "pre" and "post"

    The pre filter is implemented before forwarding. It can perform parameter verification, permission verification, traffic monitoring, log output, protocol conversion, etc.
    The post filter is executed before the response. It can modify the response content, response header, log output, traffic monitoring, etc.

  • Gateway also provides two types of filters
    Gateway filter: local filter for a single route
    GlobalFilter: Global filter for all routes

4.6.2 - local filter

  • Gateway filter is a local filter for a single route.
  • A large number of built-in local filters are provided in the Spring Cloud Gateway component to filter requests and responses.
  • Following the idea that the Convention is greater than the configuration, you only need to configure the local filter name in the configuration file and specify the corresponding value to make it effective.

Refer to gateway built-in filter factory for specific configuration md

Test configuration

api-gateway-server application.yml

server:
  port: 80
spring:
  application:
    name: api-gateway-server
  cloud:
    # Gateway configuration
    gateway:
      # Routing configuration: forwarding rules
      routes: #Gather.
      # id: unique identification. The default is a UUID
      # uri: forwarding path
      # Predictions: conditions used to request matching rules for gateway paths
      # Filters: to configure local filters

      - id: gateway-provider
        # Static routing
        # uri: http://localhost:8001/
        # Dynamic routing
        uri: lb://GATEWAY-PROVIDER
        predicates:
        - Path=/goods/**
        filters:
        - AddRequestParameter=username,zhangsan

Add the username parameter to findOne in GoodsController in gateway provider module

 public Goods findOne(@PathVariable("id") int id,String username){

        System.out.println(username);

        //If id == 1, an exception occurs= 1 normal access
        if(id == 1){
            //1. Make an exception
            int i = 3/0;
        }

        /*try {
            //2. Sleep for 2 seconds
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        Goods goods = goodsService.findOne(id);

        goods.setTitle(goods.getTitle() + ":" + port);//Set the port number to the product title
        return goods;
    }

4.6.3 - Global filter

  • GlobalFilter global filter, which does not need to be configured in the configuration file, is loaded during system initialization and acts on each route.

  • The core functions of Spring Cloud Gateway are also completed through the built-in global filter.

  • To customize a global filter:

    1. Define classes that implement GlobalFilter and Ordered interfaces
    2. Replication method
    3. Complete logical processing

MyFilter

package com.itheima.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("Custom global filter implemented~~~");

        return chain.filter(exchange);//Release
    }

    /**
     * Filter sorting
     * @return The smaller the value, the earlier the execution
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

Keywords: Java

Added by yakoup46 on Sun, 06 Mar 2022 08:48:10 +0200