SpringCloud knowledge summary (Part 2): Hystrix circuit breaker + Gateway + Config distributed configuration center + Bus message bus + Stream message driver + Sleuth distributed request link tracking

3. Intermediate

10. Hystrix circuit breaker

10.1 What is Hystrix

10.2 Hystrix stops updating and entering dimension

Learning materials: https://github.com/Netflix/Hystrix/wiki/How-To-Use

Home page suspension instructions: https://github.com/Netflix/Hystrix

10.3 A preliminary introduction to the concept of service degradation and current limiting in Hystrix

Service downgrade: When the other party's system is unavailable, a comprehensive solution will be provided (returning to friendly prompts).

Service circuit breaker: After the server reaches the maximum access, it directly denies access and then calls the service downgrade method. Similar to a fuse.

Service current limiting: In scenarios such as flash killing and high concurrency, the traffic is higher than the server load, so certain access flows are restricted (for example, N per second, ordered access).

10.4 Hystrix payment microservice construction

module:cloud-provider-hystrix-payment8081

see:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.atguigu.springcloud</groupId>
        <artifactId>cloud-api-common</artifactId>
        <version>${project.version}</version>
    </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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

yml:

server:
  port: 8081

spring:
  application:
    name: cloud-provider-hystrix-payment

eureka:
  client:
    register-with-eureka: true
    fetchRegistry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

Main startup:

com.atguigu.springcloud.PaymentHystrixMain8001:

@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
      SpringApplication.run(PaymentHystrixMain8001.class,args);
        }
}

Build service under springcloud and create class PaymentService:

@Service
public class PaymentService {
    public String paymentInfo_OK(Integer id){
        return "线程池:  "+Thread.currentThread().getName()+"  paymentInfo_OK,id:  "+id+"\t"+"O(∩_∩)O哈哈~";
    }
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 3;
        try{
            TimeUnit.SECONDS.sleep(timeNumber);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return "线程池:  "+Thread.currentThread().getName()+"  paymentInfo_Timeout,id:  "+id+"\t"+"O(∩_∩)O哈哈~"+"耗时3秒钟";
    }
}

Key controller package PaymentController

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;
    @Value("${server.port}")
    private String serverPort;
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentService.paymentInfo_OK(id);
        log.info("****result:"+result);
        return result;
    }
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("****result:"+result);
        return result;
    }
}

test:

localhost:8081/payment/hystrix/ok/31

localhost:8081/payment/hystrix/timeout/31

10.5 JMeter freezes after high concurrency stress test

Download Jmeter

After opening Jmeter, 20,000 concurrent requests overwhelmed 8001, and 20,000 requests all accessed payment.

At this time, visit again: localhost:8081/payment/hystrix/ok/31 and find that there will be lag.

10.6 There is a lag when the order microservice calls the payment service.

module:cloud-consumer-feign-hystrix-order81

see:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.atguigu.springcloud</groupId>
    <artifactId>cloud-api-common</artifactId>
    <version>${project.version}</version>
</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>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

YML:

server:
  port: 81

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

Main startup:

@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain81 {
    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain81.class,args);
    }
}

Create the PaymentHystrixService interface under service:

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}

Create the OrderHystrixController class under the controller:

@RestController
@Slf4j
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;
    @GetMapping("/consumer/payment/hytrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }
    @GetMapping("/consumer/payment/hytrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
}

启动cloud-provider-hystrix-payment8081,cloud-consumer-feign-hystrix-order81,7001

Visit localhost:81/consumer/payment/hystrix/ok/31

Test: OrderHystrixMain81, PaymentHystrixMain8081, EurekaMain7001. Stress test address: http//localhost:8081/payment/hystrix/timeout/31.

Appearance effect: Waiting in circles.

10.7 Dimension requirements for downgrade fault tolerance solution

10.7 Hystrix service downgrade payment side fallback

Add the following code to the service of cloud-provider-hystrix-payment8081:

@Service
public class PaymentService {
    public String paymentInfo_OK(Integer id){
        return "线程池:  "+Thread.currentThread().getName()+"  paymentInfo_OK,id:  "+id+"\t"+"O(∩_∩)O哈哈~";
    }
    @HystrixCommand(fallbackMethod="paymentInfo_TimeOutHandler",commandProperties={
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    })
    public String paymentInfo_TimeOut(Integer id){
        int timeNumber = 5;
        try{TimeUnit.SECONDS.sleep(timeNumber);}catch (InterruptedException e){e.printStackTrace();}
        return "线程池:  "+Thread.currentThread().getName()+"  paymentInfo_Timeout,id:  "+id+"\t"+"O(∩_∩)O哈哈~"+"耗时"+timeNumber+"秒";
    }
    public String paymentInfo_TimeOutHandler(Integer id){
        return "线程池:  "+Thread.currentThread().getName()+"  系统繁忙或者运行报错,请稍后再试,id:  "+id+"\t"+"o(╥﹏╥)o";
    }
}

Add the @HystrixCommand annotation. paymentInfo_TimeOutHandler is the method below that is used to output comforting words. The @HystrixProperty annotation is followed by the time, which is set to 3000 milliseconds. That is, if the message is not received within 3 seconds, the message will be judged as unsuccessful. The delay defined in paymentInfo_TimeOut is 5 seconds, so it will definitely time out.

Add the following annotation to main: 

@EnableCircuitBreaker

Test: localhost:8081/payment/hystrix/timeout/31

If you add int m = 10/0 to the paymentInfo_Timeout method, an error will occur. Normally, a comforting statement will also appear.

10.8 Hystrix service downgrade order side fallback

For 80 downgrade protection, service degradation is generally placed on the client.

Modify the cloud-consumer-feign-hystrix-order81 module:

Add the following code to YML:

feign:
  hystrix:
    enabled: true

Add @EnableHystrix to the startup class OrderHystrixMain.

OrderHystrixController class under the controller package:

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    String result = paymentHystrixService.paymentInfo_TimeOut(id);
    return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
    return "我是消费者81,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,/(ㄒoㄒ)/~~";
}

Logic: The server reports an error if it exceeds 5 seconds, set 3 seconds. 1.5 seconds on the client side. At this time, the client cannot access and an error is reported.

测试:localhost:81/consumer/payment/hystrix/timeout/31

Adding an error to 81 has the same effect:

10.9 Hystrix global service downgrade DefaultProperties

Write in the controller of 81:

public String payment_Global_FallbackMethod(){
    return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
}

 OrderHystrixController under the controller package

@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")

Comment out the long list of @HystrixCommand annotations above and rewrite a @HystrixCommand annotation. 

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
/*@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})*/
@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    int age = 10/0;
    String result = paymentHystrixService.paymentInfo_TimeOut(id);
    return result;
}

10.10 Hystrix wildcard service downgrade FeignFallback

Solve the coupling problem of global service degradation

Create the PaymentFallbackService class in the service under cloud-consumer-feign-hystrix-order81, and inherit the PaymentHystrixService interface:

@Component
public class PaymentFallbackService implements PaymentHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "------PaymentFallbackService fall back-paymentInfo_OK,o(╥﹏╥)o";
    }
    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "------PaymentFallbackService fall back-paymentInfo_TimeOut,o(╥﹏╥)o";
    }
}

Add fallback = PaymentFallbackService.class to @FeignClient. PaymentFallbackService is the class name of the implementation class:

@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)

test:

Visit localhost:81/consumer/payment/hystrix/ok/31

Microservice 8001 is deliberately closed. At this time, access is no longer possible, the service is degraded, and a comfort statement is returned:

10.11 Hystrix value service circuit breaker theory

First the service is degraded, then the circuit breaker is broken, and finally the calling link is slowly restored. This is very important.

10.12 Hystrix service circuit breaker case (Part 1)

Save the following dependencies to cloud-api-commons

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.1.0</version>
</dependency>

The confused toolkit generates serial numbers.

Write the following code in the PaymentService class in the service package of cloud-provider-hystrix-payment8081:

@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name="circuitBreaker.enabled",value="true"), //是否开启断路器
        @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),
        @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000"),
        @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="60"),
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    if(id<0){
        throw new RuntimeException("****id 不能负数");
    }
    String serialNumber = IdUtil.simpleUUID();
    return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    return "id 不能负数,请稍后再试,o(╥﹏╥)o   id:"+id;
}

10.13 Hystrix service circuit breaker case (Part 2)

Add the following code to the PaymentController class in the controller package of cloud-provider-hystrix-payment8081:

//服务熔断
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result"+result);
    return result;
}

test:

http://localhost:8081/payment/circuit/31

A positive number means the call was successful:

A negative number means the call failed:

If you click negative numbers wildly and request N times, the circuit will break after failure. At this time, if you enter a positive number again, the error will still occur. When the error rate drops, wait for a while and it will recover.

10.14 Hystrix service circuit breaker summary

The following is an interpretation of the above program code: 

Fusing process: 

The following are some commonly used attributes: 

10.15 Final summary of Hystrix workflow

10.16 Hystrix graphical Dashboard construction

Module:cloud-consumer-hystrix-dashboard9001

POM:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

YML:

server:
  port: 9001

Main startup:

Create HystrixDashboardMain9001 and add the new annotation @EnableHystrixDashboard

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardMain9001.class,args);
    }
}

All Provider microservice classes (8001/8002/8003) need to monitor dependency configuration, that is, there must be an actuator in the POM file.

Test: Start 9001. Enter the address: localhost:9001/hystrix

10.17 Hystrix graphical Dashboard monitoring practice

Note that you need to add an @EnableCircuitBreaker annotation:

Add the following method code in PaymentHystrixMain8081 of 8081:

@Bean
public ServletRegistrationBean getServlet(){
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

Test: Start EurekaMain7001 and HystrixDashboardMain9001

Fill in the address of http://localhost:8081/hystrix.stream into the url column:

Start PaymentHystrixMain8081

localhost:8081/payment/circuit/31 is the correct address

localhost:8081/payment/circuit/-31 is the wrong address

First, click the address below multiple times:

Then click Monitor:

Each color below corresponds to a fault:

The following is the number of occurrences:

The meaning of circle:

The more points you click, the larger the circle will become. Circuit is the opening and closing status of the fuse, and Closed indicates that traffic is allowed to pass:

If you enter

12. Gateway new generation gateway

12.1 What is GateWay?

12.2 GateWay non-blocking asynchronous model

12.3 GateWay workflow

Core: routing forwarding + execution filter chain

Route route

Predicate assertion: match condition

Filter filter

12.4 GateWay9527 build

建POM:cloud-gateway-gateway9527

POM:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.atguigu.springcloud</groupId>
        <artifactId>cloud-api-common</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

YML:

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh
          uri: http://localhost:8081 #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**

        - id: payment_routh2
          uri: http://localhost:8081
          predicates:
            - Path=/payment/lb/**
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

Startup class:

@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class,args);
    }
}

Test: start 7001, start cloud-provider-payment8081, 9527 gateway

First try localhost:8081/payment/get/31 to see if you can access it.

Then enter localhost:9527/payment/get/31 to access through the gateway

localhost:9527/payment/lb

Be careful to clear all the code in dependencies in the parent POM in advance, otherwise there will be dependency transfer effects.

12.5 Two ways to configure routing with GateWay

Business requirements: Access the Baidu News website on the external network through the 9527 gateway.

http://news.baidu.com/guonei

http://news.baidu.com/guoji

Create the config package under com/atguigu in 9527 and create the GateWayConfig configuration class:

@Configuration
@Import({RouteLocatorBuilder.class})
public class GateWayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_route_atguigu",
                r -> r.path("/guonei")
                        .uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
    @Bean
    public RouteLocator customRouteLocator2(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_route_atguigu2",
                r -> r.path("/guoji")
                        .uri("http://news.baidu.com/guoji")).build();
        return routes.build();
    }
}

Test: localhost:9527/guonei, localhost:9527/guonei, will jump to the corresponding page (failed).

12.6 GateWay configures dynamic routing

Implement load and balancing on the gateway side

start up:

One eureka7001 + two service providers 8081 and 8082

 POM:

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

YML makes the following modifications based on the above:

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enable: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
uri: lb://cloud-payment-service #匹配后提供服务的路由地址

Test: http://localhost:9527/payment/lb

Implement switching between 8081 and 8083.

 

12.7 Commonly used Predicates in GateWay

Create the T2 class in java under test:

public class T2 {
    public static void main(String[] args){
        ZonedDateTime zbj = ZonedDateTime.now();
        System.out.println(zbj);
    }
}

Run the test class first to get the current time, such as: 2023-11-03T18:02:51.473+08:00[Asia/Shanghai].

Modify YML:

Test: localhost:9527/payment/lb

Change the time, add 1 hour to the current time, access fails:

Below is Between:

test:

Use curl to send commands with cookies in cmd to access:

Here is the regular expression:

test:

12.8 GateWay Filter

Create the filter package in com.atguigu.springcloud under cloud-gateway-gateway9527, and create MyLogGateWayFilter under the package

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
        log.info("********come in MyLogGateWayFilter:   "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if(uname==null){
            log.info("*****用户名为null,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder(){
        return 0;
    }
}

test:

Those with uname can be accessed normally:

Cannot be accessed without uname (failed, accessible)

Guess you like

Origin blog.csdn.net/RuanFun/article/details/134179425