【SpringCloud】12 服务降级 Hystrix 断路器 Part1 概述和案例搭建
分布式应用系统面临的问题?
服务调用即接口调用,有一级链路调用,就会产生N级链路调用
例如:
A1服务接口是最初提供的服务接口,被A2接口调用
A2接口被A3调用,A3接口被A4调用,A4接口被A5调用,如此往下继续。。。。
An -> A5 -> A4 -> A3 -> A2 -> A1
每一个接口就都有可能会出现错误或者等等不可抗力的原因,无法向下调用
那么整个链路的调用就无效了
An -> A5 × A4 -> A3 -> A2 -> A1
当然,除了单链路服务接口调用,还有多链路调用的可能(扇出)
An -> A5 -> A4 -> A3 -> A2 -> A1 | Bn -> B2 -> B1 | Cn -> C3 -> C2 -> C1 . . . . . .
多链路也有这种情况:
An -> A5 -> A4 × A3 -> A2 -> A1 | Bn -> B2 -> B1 | Cn -> C3 × C2 -> C1 . . . . . .
如果响应时间过长或者服务本身不可用,就会造成服务崩溃
系统资源占用过多,俗称雪崩效应
Hystrix解决的就是保证一个整体的服务维持正常,提高分布式系统的弹性
断路器就是一个跳闸,该服务不可用时,Hystrix马上换到备用服务顶替上去
总之就是为了避免系统全体瘫痪
服务降级、服务熔断、服务限流
演示案例构建:
在之前的案例中有配置IP地址,由于自己重装了系统的原因,重新配置一下:
Hosts文件位置:
C:\Windows\System32\drivers\etc\hosts
然后在尾部追加你自己配置的Eureka服务地址:
127.0.0.1 eureka7001.cn 127.0.0.1 eureka7002.cn
回到Cloud工程中的7001服务中的Yaml配置:
server: port: 7001 eureka: instance: hostname: eureka7001 client: fetch-registry: false register-with-eureka: false service-url: # defaultZone: http://eureka7002.cn:7002/eureka/ defaultZone: http://eureka7001.cn:7001/eureka/ server: enable-self-preservation: false # 关闭自我保护 不可用的服务立即移除 eviction-interval-timer-in-ms: 2000 # 默认一个30秒,一个90秒
然后创建Hystrix的提供者8001服务模块
Cloud-Provider-Hystrix-Payment-8001
所需要的依赖坐标:
<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>cn.dzz.springcloud</groupId> <artifactId>API-Commons</artifactId> <version>${project.version}</version> <!--<version>1.0-SNAPSHOT</version>--> </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.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </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> </dependencies>
yaml配置:
server:
port: 8001
eureka:
instance:
hostname: eureka7001
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.cn:7001/eureka/
spring:
application:
name: cloud-provider-hystrix-payment
编写业务层接口和实现类:这里就不搞麻烦直接写类了
package cn.dzz.service;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* @author Administrator
* @file IntelliJ IDEA SpringCloud-ATGG-2020
* @create 2020 10 04 21:49
*/
@Service
public class PaymentService {
// 正常访问
public String paymentInfoOk(Integer id) {
return "线程池: " + Thread.currentThread().getName() + " payment-info:ok, id = " + id + " 支付成功!";
}
// 访问超时
public String paymentInfoTimeout(Integer id) {
try {
int sleepTime = 3;
TimeUnit.SECONDS.sleep(sleepTime);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
return "线程池: " + Thread.currentThread().getName() + " payment-info:timeout, id = " + id + " 请求超时!";
}
}
控制器的接口编写:
package cn.dzz.springcloud.controller;
import cn.dzz.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author Administrator
* @file IntelliJ IDEA SpringCloud-ATGG-2020
* @create 2020 10 04 21:58
*/
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@RequestMapping("payment/hystrix/info/ok/{id}")
public String paymentInfoOk(@PathVariable("id") Integer id) {
String paymentInfoOk = paymentService.paymentInfoOk(id);
log.info(paymentInfoOk);
return paymentInfoOk;
}
@RequestMapping("payment/hystrix/info/timeout/{id}")
public String paymentInfoTimeout(@PathVariable("id") Integer id) {
String paymentInfoTimeout = paymentService.paymentInfoTimeout(id);
log.info(paymentInfoTimeout);
return paymentInfoTimeout;
}
}
编写启动类:
package cn.dzz.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author Administrator
* @file IntelliJ IDEA SpringCloud-ATGG-2020
* @create 2020 10 04 21:48
*/
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrix8001Application {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrix8001Application.class, args);
}
}
启动服务:
访问接口:
http://localhost:8001/payment/hystrix/info/ok/1

访问超时接口:
http://localhost:8001/payment/hystrix/info/timeout/1

Eureka7001注册中心:
http://eureka7001.cn:7001/
出现红字警告:
RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
发现没有服务实例注册到Eureka中...
原因是因为8001没有更改为True
server:
port: 8001
eureka:
instance:
hostname: eureka7001
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.cn:7001/eureka/
spring:
application:
name: cloud-provider-hystrix-payment
这样Hystrix工程搭建完成了

浙公网安备 33010602011771号