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