This is the 13th day of my participation in the More text Challenge. For details, see more text Challenge

Hystrix

An overview,

Hystrix is an open source library for delay and fault tolerance in distributed systems. In distributed systems, many dependency calls inevitably fail. Hystrix ensures that if a dependency fails, it will not affect the overall service failure, avoiding cascading failures and improving the resilience of the system.

Questions lead

Calls between multiple microservices will form a link. When a microservice on the link fails (timeout, exception, etc.), the faulty module will call other modules. In this way, cascading failure, also called avalanche, will occur.

To solve the problem

‘circuit breaker is a kind of switch device, when a service failure occurs, through the circuit breaker fault monitoring, returned to the caller a in line with expectations, treatment alternatives, rather than waiting for a long time or an exception is thrown, to ensure the service call to put the thread is not unnecessary to take up for a long time, to avoid the spread of fault in the distributed system, and even the avalanche.

Hystrix features:

  • Service degradation: Fallback is triggered when the program runs abnormally, times out, or the thread pool/semaphore is full, giving the client a friendly message.
  • Service fuse: similar to a fuse, the access is denied directly after reaching the maximum number of visits, and then the call access is degraded to give friendly hints.
  • Service flow limiting: kill high concurrent operations, prevent a swarm of access, set to execute more than one request per second, exceeded requests are queued.
  • Real-time monitoring

Second, service degradation

1. Unilateral demotion

Rely on

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Copy the code

configuration

server:
  port: 80

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

feign:
  hystrix:
    enabled: true
Copy the code

The Order80 service invokes the service provided by 8001, which has a delayed interface

@Service
public class PaymentService {
    public String paymentInfoSuccess(Integer id){
        return "Thread pool:" + Thread.currentThread().getName() + "PaymentInfoSuccessId." + id;
    }

    public String paymentInfoFailed(Integer id){
        // Create timeout error
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Thread pool:" + Thread.currentThread().getName() + "PaymentInfoFailedId."+ id; }}Copy the code

Since OpenFeign has a default wait time of 1 second, any call to an interface that is longer than 1 second will throw an exception, and any subsequent service may fail due to the delay. Service degradation will be added to resolve the problem. Downgrade the configuration and set up a pocket scheme.

Provide fallback service after module 8001 is abnormal

@Service
public class PaymentService {
    //fallbackMethod: specifies the fallbackMethod. CommandProperties specifies which exceptions to use fallbackMethod
    @hystrixCommand (fallbackMethod = "paymentInfoFailedHandler",commandProperties = {// Execute fallbackMethod if it times out 3 seconds @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") })
    public String paymentInfoFailed(Integer id){
        // Create timeout error
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Thread pool:" + Thread.currentThread().getName() + "PaymentInfoFailedId." + id;
    }

    public String paymentInfoFailedHandler(a){
        return "Payment8001's paymentInfoFailed fallbackMethod performed"; }}Copy the code

The consumer Order80 is configured fallback, usually on the consumer side

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

    @HystrixCommand(fallbackMethod = "paymentInfoFailedHandler",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") })
    @GetMapping(value = "/consumer/paymentInfoFailed/{id}")
    public String paymentInfoFailed(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfoFailed(id);
    }

    @GetMapping(value = "/consumer/paymentInfoSuccess/{id}")
    public String paymentInfoSuccess(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfoSuccess(id);
    }

   public String paymentInfoFailedHandler(a){
       return "Order80 paymentInfoFailed fallbackMethod performed"; }}Copy the code

2. Global degradation

In this case, the fallback code is coupled to the business code, and each method has a separate fallback method, which is not convenient to use. Use the global fallback to improve.

Using global degradation

@RestController
// Specify the fallback method for global degradation
@DefaultProperties(defaultFallback = "payment_Global_RollbackMethod")
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

    If fallback is specified, fallback is used. If fallback is not specified, fallback is used globally
    @HystrixCommand     
    @GetMapping(value = "/consumer/paymentInfoFailed/{id}")
    public String paymentInfoFailed(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfoFailed(id);
    }


    public String payment_Global_RollbackMethod(a) {
        return "Order80 paymentInfoFailed payment_Global_RollbackMethod performed"; }}Copy the code

3. Wildcard service is degraded

The consumer degrades the interface that provides the service when it is invoked remotely, and can also degrade if the server that provides the service goes down.

Create a class that implements the interface for remote calls

@Component
public class PaymentFallbackService implements PaymentHystrixService {
    @Override
    public String paymentInfoFailed(Integer id) {
        return "PaymentFallbackService Fallback method of PaymentFallbackService";
    }

    @Override
    public String paymentInfoSuccess(Integer id) {
        return "PaymentInfoSuccess Fallback method of PaymentFallbackService"; }}Copy the code

Note the degraded class on the interface of the remote call

@Component
@FeignClient(name = "CLOUD-PAYMENT-HYSTRIX-SERVICE",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
    @GetMapping(value = "/paymentInfoFailed/{id}")
    String paymentInfoFailed(@PathVariable("id") Integer id);
    @GetMapping(value = "/paymentInfoSuccess/{id}")
    String paymentInfoSuccess(@PathVariable("id") Integer id);
}
Copy the code

3. Service circuit breaker

Circuit breaker is a micro – service link protection mechanism to deal with avalanche effect. When a microservice on the fan out link is faulty or unavailable, the service will be degraded, and then the call of the microservice on the node will be fuses, and the response information will be returned quickly. When the microservice response of the node is normal, the link call is recovered. SpringCloud uses Hystrix to implement circuit breakers. Hystrix monitors calls between microservices and enables circuit breakers when failed calls reach a certain y threshold.

Configure tests in the Payment8001 Service and fuse breaks in the Service

@Service
public class PaymentService {
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), / / open the fuse @ HystrixProperty (name = "circuitBreaker. RequestVolumeThreshold", value = "10"), / / request times @ HystrixProperty (name = "circuitBreaker. SleepWindowInMilliseconds", value = "10000"), / / time window @ HystrixProperty (name = "circuitBreaker. ErrorThresholdPercentage", value = "60"), / / what is the failure rate after fusing})
    public String paymentCircuitBreaker(Integer id){
        if (id < 0) {
            throw new RuntimeException("Id cannot be less than 0");
        }
        String uuid = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "\t" + "SUCCESS,code:" + uuid;
    }
    public String paymentCircuitBreaker_fallback(Integer id){
        return "Id cannot be negative, please try again later!"+ id; }}Copy the code

If the number of accesses reaches more than 10 in 10 seconds and the failure rate reaches 60 percent, and the id is negative, the fallback mechanism will be activated (the fuse is fully on), even if the id sent is an integer, the fallback method will continue (the fuse is half-open). The normal call will resume in a moment (the fuse is closed). Fuse status:

  • Fuse open: the request no longer calls the current service, the internal set clock (mean time for troubleshooting), when the open time reaches the time set by the clock to enter the half-open state.
  • Circuit breaker is half on: some requests invoke the current service according to the rules. If the requests are successful and comply with the rules, the current service is recovered and the circuit breaker is disabled.
  • Circuit breaker off: The service will not be circuit breaker

4. Service monitoring

In addition to the above functions, Hystrix also provides quasi-real-time call monitoring. Hystrix continuously records the execution information of all requests initiated through Hystrix and displays the statistics and graphs to users, including the number of successful and failed requests per second.

1. Set up the Dashboard9001 service

Rely on

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<! -- Note: this dependency is required whenever web graphics are used -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code

The main start

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

Starting 9001, visit http://localhost:9001/hystrix can see Hystrix Dashboard’s home page

2. Use the Dashboard monitoring service

Note: the monitored 8001 primary boot class needs a configuration, which is caused by the springCloud upgrade

 @SpringBootApplication
 @EnableEurekaClient
 @EnableCircuitBreaker
 public class PaymentHystrixMain8001 {
     public static void main(String[] args) {
         SpringApplication.run(PaymentHystrixMain8001.class,args);
     }
 
     @Bean
     public ServletRegistrationBean getServlet(a){
         HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
         ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
         registrationBean.setLoadOnStartup(1);
         registrationBean.addUrlMappings("/hystrix.stream");
         registrationBean.setName("HystrixMetricsStreamServlet");
         returnregistrationBean; }}Copy the code

Monitor the 8001 service

Enter monitor address http://localhost:8001/hystrix.stream in hystrix home page