Summary of SpringCloud study notes (4)

Git code address: https://gitee.com/it-sherlock/java-project-template .

1. Introduction to OpenFeign


OpenFeign official address: https://spring.io/projects/spring-cloud-openfeign/

OpenFeign Github official address: https://github.com/spring-cloud/spring-cloud-openfeign

feign English translation: pretend, pretend.

Feign is a declarative WebService client that makes writing a Web service client very easy, just create an interface and add annotations to the interface.

Previously, it was encapsulated by ribbon + restTemplate to form a set of templated calling methods.

Now, feign integrates ribbon. Feign only needs to define the service binding interface and implement service invocation elegantly and simply in a declarative way.

Now OpenFeign has replaced Feign:
insert image description here

2. Service call on the consumer side of OpenFeign


Feign is defined on the consumer side.

Simply put, it's easier: you only need the microservice call interface + @FeignClient annotation to achieve it.


Step 1: Add OpenFeign dependencies:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

The second step: the main startup class, add the annotation @EnableFeignClients that activates feign:

package com.itholmes.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients//使用feign,激活开启feign
public class OrderFeignMain80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}

Step 3: Write a service interface and configure the corresponding @FeignClient annotation.

package com.itholmes.springcloud.service;

import com.itholmes.springcloud.entities.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    
    
    /**
     * 这时候就是去注册中心找一个CLOUD-PAYMENT-SERVICE名称的微服务加上对应地址。
     */
    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id);
}

insert image description here

3. OpenFeign timeout control


OpenFeign waits for 1 second by default, and reports an error read time out after that.
insert image description here

# 设置feign 客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  # 指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  # 指的是进建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

4. Log enhancement of OpenFeign


Feigon provides a log printing function. We can adjust the log level through configuration to understand the details of Http requests in Feign. Monitor and output the invocation of the Feign interface.

Log level for OpenFeign:
insert image description here


The configuration class sets the log level:

package com.itholmes.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    
    

    //设置日志级别
    @Bean
    Logger.Level feignLoggerLevel(){
    
    
        return Logger.Level.FULL;
    }

}

At what level does the feign log monitor that interface:

server:
  port: 80

eureka:
  client:
    # 表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    # 入驻地址是哪个
    service-url:
      #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      #defaultZone: http://localhost:7001/eureka #单机版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  #集群版

# 设置feign 客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  # 指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  # 指的是进建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.itholmes.springcloud.service.PaymentFeignService: debug

The log is as follows:
insert image description here

5. Important Concepts of Hystrix


Problems faced by distributed systems:

  • They are all microservice calls. A process may involve many microservice systems. If one of the microservice systems has a problem, the whole process is equivalent to failure.

Service Avalanche:

  • When multiple microservices interact with each other 依赖调用, microservice A calls microservice B, microservice B calls microservice C, and microservice C calls other microservices, that is 扇出效果(像一把扇子,不断张开).
  • If there is a problem with a microservice (timeout, downtime, etc.), for example: microservice C is down, then microservice B will continue to accumulate requests (requested threads are blocked), and microservice B occupies more and more System resources, and then the microservice B system also collapses, the microservice B collapses, and the same A will continue to accumulate and then collapse. This is the avalanche effect.

In order to solve the above problems, there is 熔断降级an idea.

Hystrix is ​​an open source library for dealing with latency and fault tolerance in distributed systems.

In a distributed system, many dependencies will inevitably fail, such as timeouts, exceptions, etc.

Hystrix can ensure that in the case of a dependency problem, the overall service will not fail, avoid cascading failures, and improve the elasticity of distributed systems.


Circuit breaker: (blown fuse)
insert image description here

Official address: https://github.com/Netflix/Hystrix


Service downgrade:

  • It is to return a friendly prompt (fallback), for example: the server is busy, please try again later; do not let the client wait and return a friendly prompt (fallback) immediately.

Downgrades are triggered in those cases:

  • The program is running abnormally.
  • time out.
  • Service fuse triggers service downgrade.
  • A full thread pool/semaphore can also cause service degradation.

Service fuse:

  • After the analog fuse reaches the maximum service access, it directly refuses access, turns off the power supply, and then calls the service downgrade method and returns a friendly prompt.
  • Fusing process: service downgrade - "and then fuse - "restore the call link

Service current limit:

  • For operations such as spikes, high concurrency, etc., it is strictly forbidden to rush over to crowd, everyone queues up, N per second, and orderly, this is the service current limit.

6. jmeter common service test


Use jmeter to test.

insert image description here
In the thread group, set 200 threads, send requests within 1 second, and loop 100 times. After that, when accessing both interfaces through the browser again, there is a serious lag.

The reason is: the default number of worker threads of tomcat is full, and there are no extra threads to share the pressure and processing.

insert image description here
This is the avalanche effect.

7. Hystrix's service provision and service consumption environment construction


Step 1: Import hystrix dependencies:

<!--添加eureka-client客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--添加openFeign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--添加hystrix依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

Step 2: Build the SpringBoot project.

Step 3: Use openFeign to link calls between consumers and providers.

Step 4: Use Jmeter to test high concurrent requests.

  • Through the test, it is not difficult to see that once a high concurrent request comes in, it will cause serious freezes.

Solution ideas:
insert image description here

How to solve the above problem:
insert image description here

8. Hystrix service downgrade consumer and server


The official github documentation is used through the program:
insert image description here


The @HystrixCommand annotation is used here:

The processing process after @HystrixCommand reports an exception:

  • Once the service method fails to be called and an error message is thrown, the fallbackMethod marked by @HystrixCommand will be automatically called to call the specified method in the class.

The server downgrade code is as follows:

The first step: service layer logic code:

package com.itholmes.springcloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class PaymentService {
    
    

    public String paymentInfo_OK(Integer id){
    
    
        return "线程池: " + Thread.currentThread().getName() + "paymentInfo_OK,id:"+id+"\t"+"hello,world";
    }

    //一旦调用服务方法失败,并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法。
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
    
    
        // 超过3秒走兜底的错误方法。
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id){
    
    
        int timeNumber = 5;
        //无论是异常还是其他的,都会引起指定的兜底方法执行。
		//int age = 10/0;
        try {
    
    
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池: " + Thread.currentThread().getName() + "paymentInfo_OK,id:"+id+"\t"+"hello,world。"+"耗时(秒)"+timeNumber+"秒钟";
    }

	// 被上面指定兜底的方法
    public String paymentInfo_TimeOutHandler(Integer id){
    
    
        return "线程池: " + Thread.currentThread().getName() + "8001系统繁忙,请稍后再试,id:"+id+"\t"+"GG.";
    }
    
}

Step 2: The main startup class, add the annotation @EnableCircuitBreaker.

package com.itholmes.springcloud;

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

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

In this way, when we access this service provider, there will be a bottom-up method to help us deal with timeouts, exceptions, etc.


The client service downgrade code is as follows:

  • Generally, we perform service downgrade on the client side!

Step 1: Because the client is called through openfeign, hystrix should be enabled in feign.

server:
  port: 80

eureka:
  client:
    # 表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    # 入驻地址是哪个
    service-url:
      #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka #单机版
      # defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  #集群版
ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

# 在feign中开启hystrix
feign:
  hystrix:
    enabled: true

Step 2: Add the @EnableHystrix annotation to the main startup class.

package com.itholmes.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

Step 3: For the consumer (client), openfeign is generally used to call the server, and the annotation @HystrixCommand is also configured in the controller layer.

package com.itholmes.springcloud.controller;

import com.itholmes.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
public class PaymentHystrixController {
    
    
    @Resource
    private PaymentHystrixService paymentHystrixService;

    /**
     * 这里与服务端不同!
     *  服务端在service层添加的@HystrixCommand注解。
     *  在openfeign的消费端,是在controller层添加@HystrixCommand注解。
     */
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
    
    
            // 超过3秒走兜底的错误方法。
            @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 "我是消费者80,对方支付系统繁忙或自身运行出错!";
    }
}

9. Hystrix global service downgrade @DefaultProperties


If you want to have a unified code to deal with, that is, the effect of global service degradation.

Use @DefaultProperties(defaultFallback = "") to achieve this.
insert image description here


The @DefaultProperties(defaultFallback = "") annotation is used as follows:

package com.itholmes.springcloud.controller;

import com.itholmes.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
//指名全局
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class PaymentHystrixController {
    
    

    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
    
    
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    //对于有@HystrixCommand注解指定的fallbackMethod,就走指定的服务降级兜底的方法。
    @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;
    }

    @GetMapping("/consumer/payment/hystrix/timeout2/{id}")
    //使用全局的fallback
    @HystrixCommand
    public String paymentInfo_TimeOut2(@PathVariable("id") Integer id){
    
    
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

    public String paymentTimeOutFallbackMethod(@PathVariable("id")Integer id){
    
    
        return "我是消费者80,对方支付系统繁忙或自身运行出错!";
    }

    //全局fallback方法
    public String payment_Global_FallbackMethod(){
    
    
        return "Global 全局的服务降级,返回信息。系统方法请稍后重试。";
    }

}

10. Hystrix wildcard service downgrade


Configured by the fallback parameter in the @FeignClient annotation.

Step 1: Create 当前使用OpenFeign对应的service接口an implementation class that implements .

package com.itholmes.springcloud.service;

import org.springframework.stereotype.Component;

//实现了PaymentHystrixService,该类就是使用的OpenFeign远程调用。
//不要忘记装配到ioc容器中。
@Component
public class PaymentFallbackService implements PaymentHystrixService{
    
    
    @Override
    public String paymentInfo_OK(Integer id) {
    
    
        return "paymentInfo_OK fallback";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
    
    
        return "paymentInfo_TimeOut fallback";
    }
}

Step 2: Configure fallback, which is the corresponding PaymentFallbackService implementation class.

package com.itholmes.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
//配置fallback,配置的就是对应的PaymentFallbackService实现类。
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
    
    

    @GetMapping("/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id);

}

In this way, the service degradation will take the return value of the corresponding implementation class method.

11. Hystrix service fuse


insert image description here
After the circuit breaker mechanism starts, it will detect whether the node microservice is normal, and then restore the calling link.


// Controller层:调用Service层的服务熔断。
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    
    
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result: "+result);
    return result;
}



//Service层:断路器实现。
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
    
    
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
        /**
         * 以下的意思就是:在10s的时间里的10次访问,如果超过百分之60失败,就跳闸限电。
         */
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), // 请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间窗口期
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸
})
public String paymentCircuitBreaker(Integer id){
    
    
    if (id < 0){
    
    
        throw new RuntimeException("********id 不能负数");
    }

    //IdUtil.simpleUUID(); 的源代码就是 UUID.random().toString(); 这是hutool糊涂jar包里面的工具类。
    String serialNumber = IdUtil.simpleUUID();
    return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
}

public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    
    
    return "id 不能负数,请稍后再试,id: "+id;
}

The corresponding properties are as follows:
insert image description here

In this way, in the above code, if more than 60% of the accesses fail in 10s, the power supply will be tripped. After the fuse mechanism is triggered, the bottom-up method will be triggered for a period of time, and then the link mechanism will be restored slowly (that is, the fuse is half-open).

Fusing has three states:
insert image description here

Three important parameters for judging circuit breakers:
insert image description here


Official hystrix architecture diagram:

  • HystrixObservableCommand is another method of HystrixCommand with the same effect.
    insert image description here

11. Hystrix's graphical dashboard (graphical monitoring)


Step 1: Create a project and import dependencies.

<!--导入hystrix-dashboard包-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

<!--所有图形化监控检测,都依赖actuator(监控信息完善,bean的状态等)-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Precautions:

  • Sometimes, when there are too many projects, application.yml will become a grid, which idea does not recognize.
    insert image description here
    Solution:
    insert image description here

Step 2: Add the @EnableHystrixDashboard annotation to the main startup class.

package com.itholmes.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
//开启hystrix dashboard图形化监控
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(HystrixDashboardMain9001.class,args);
    }
}

Step 3: Start the project and visit http://localhost:port/hystrix address.
insert image description here

12. Hystrix's graphical dashboard practical demonstration


The monitored system, the main startup class configuration is as follows:

package com.itholmes.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
    
    

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

    /**
     * 此配置是为了服务监控而配置,与服务容错本身无关SpringCloud升级后的坑。
     *  ServletRegistrationBean因为springboot的默认路径不是“/hystrix.stream”,
     *  只要在自己的项目配置上下面的servlet就可以了。
     *
     *  如果不配置就会报如下的一个错误:
     *      Unable to connect to Command Metric Stream 404 的错误。
     */
    @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;
    }

}

The web monitoring configuration of the Dashboard monitoring system is as follows:
insert image description here
insert image description here

The effect of the circuit breaker:
insert image description here

How to see the graphical interface:

  • Seven colors:
    insert image description here
  • Solid circle:
    insert image description here
  • 1 line
    insert image description here

Demonstration of the entire figure:
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/IT_Holmes/article/details/125446746