Background: In an actual microservice system, there are many services, and often one service needs to depend on another service. For example, in a large e-commerce system, the divided order service and payment service will be interdependent. situation, and if one of the services hangs up and the other service keeps requesting, it will definitely not get a response. In this way, long-term requests will accumulate, causing the service to collapse, which will paralyze the entire system. Such an architecture is quite More unstable than traditional architecture. In order to solve and deal with this problem, the fuse Hystrix appeared.
Table of contents
(1) Introduction
Netflix created a library called Hystrix that implements the circuit breaker pattern . In a microservice architecture, there are usually multiple layers of service calls.
Service failures in lower-level services can lead to user cascading failures. When calls to a specific service reach a certain threshold (the default in Hystrix is 20 failures in 5 seconds), the circuit is opened and no calls are made. Developers can provide fallbacks in case of bugs and open circuits.
Open circuits stop cascading failures and allow unnecessary or failed service time to heal. The fallback can be another Hystrix-protected call, static data, or a normal null value. Fallbacks may be chained, so the first fallback makes some other business call back to static data.
(2) Implementation method
In springCloud, fuses can be implemented in two ways: Ribbon and Feign. The following are still based on the previous project: eureka implementation , Ribbon implementation , feign implementation
1.Ribbon
Add Hystrix dependency to the previous Ribbon project pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Add the hystrix annotation @EnableHystrix to the ribbon startup class
package com.cloud.ribbonservice;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class RibbonserviceApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonserviceApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new RandomRule(); //这里配置策略,和配置文件对应
}
}
Then add the @HystrixCommand(fallbackMethod = "portFallback") annotation to the calling method, and add the callback method portFallback after circuit breaking.
package com.cloud.ribbonservice.service;
import com.cloud.ribbonservice.controller.Controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@Service
public class RibbonService implements IRibbonService {
private static final Logger logger = LoggerFactory.getLogger(IRibbonService.class);
@Autowired
RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
@HystrixCommand(fallbackMethod = "portFallback")
public String port() {
this.loadBalancerClient.choose("SPRING-CLIENT-01");
String info = restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
return restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
}
private String portFallback()
{
logger.error("The service is Down");
System.err.println("The service is Down");
return "Service down";
}
}
The basics are now configured.
Then start the registration center, SPRING-CLIENT-01 service, and ribbon service.
Enter in the browser or postman
http://localhost:11000/getInfo/hellol
Close the SPRING-CLIENT-01 service and refresh the browser
The circuit breaker was triggered successfully.
2. How to use feign
1. Add Hystrix dependency to pom.xml in the previous feign project
2. Turn on the Hystrix switch feign.hystrix.enabled=true in feign's configuration file application.properties file
server.port = 10010
eureka.client.serviceUrl.defaultZone= http://localhost:12345/eureka/
spring.application.name= SPRING-FEIGN-SERVICE
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testmysql
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
feign.hystrix.enabled=true
Add a fuse class to the calling interface. This class must implement the interface that previously called other services.
package com.springcloudfeign.feign.service;
import org.springframework.stereotype.Component;
@Component
public class ErrorHystrix implements FeignDemoService {
@Override
public String getPort() {
return "sorry, it's error!";
}
@Override
public String getPortTwo() {
return "sorry, it's also error!";
}
}
Then add the annotation of the fuse callback class to the FeignDemoService interface annotation @FeignClient(value = "SPRING-CLIENT-01", fallback = ErrorHystrix.class)
package com.springcloudfeign.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(value = "SPRING-CLIENT-01" ,fallback = ErrorHystrix.class)
public interface FeignDemoService {
@RequestMapping(value = "port" , method = RequestMethod.GET)
String getPort();
@RequestMapping(value = "getInfo/show" , method = RequestMethod.GET)
String getPortTwo();
}
that's it.
SPRING-SERVICE-01 has nothing to do with the method of calling the interface in feign and the return is:
Enter in the browser:
http://localhost:10010/getInfoTwo
return:
Disconnect the SPRING-SERVICE-01 service, refresh the browser and return:
Indicates that the fuse call is successful.
Github address of the above code: Source code address