基本概念
服务雪崩:
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的”扇出”,如扇出的链路上某个微服务的调用响应式过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统雪崩,所谓的”雪崩效应”
Hystrix:
Hystrix是一个用于分布式系统的延迟和容错的开源库。在分布式系统里,许多依赖不可避免的调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。
断路器:
“断路器”本身是一种开关装置,当某个服务单元发生故障监控(类似熔断保险丝),向调用方法返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延。乃至雪崩。
服务熔断:
熔断机制是应对雪崩效应的一种微服务链路保护机制,
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务响应正常后恢复调用链路,在SpringCloud框架机制通过Hystrix实现,Hystrix会监控微服务见调用的状况,当失败的调用到一个阈值,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand
服务降级:
当某个服务出现异常之后,服务器将不再被调用,此时服务端可以自己准备一个本地的fallback回调,返回一个缺省值。
Hystrix与Feign集成,并实现降级与熔断:
准备一个准备一个服务提供端8001
- yml配置
server.port=8001
spring.application.name=cloud-provider-hystrix-payment
#eureka实例名称
eureka.instance.hostname=localhost
#表示向注册中心注册自己
eureka.client.register-with-eureka=true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
eureka.client.fetch-registry=false
#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址
eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
2.创建测试使用的service与controller
@Service
public class PaymentService {
/**
* 正常访问
*
* @param id
* @return
*/
public String paymentInfo_OK(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK:" + id;
}
/**
* @param id
* @return
*/
//执行此方法时当先线程将会休眠三秒,三秒之后才会返回结果
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 3;
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut:" + id + " 耗时:" + timeNumber + "秒";
}
- 创建controller
@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@GetMapping("/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id){
//int a = 10/0;
String s = paymentService.paymentInfo_OK(id);
log.info("result********"+s);
return s;
}
@GetMapping("/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id){
String s = paymentService.paymentInfo_TimeOut(id);
log.info("result********"+s);
return s;
}
}
准备一个消费者端
1.在配置文件中添加配置
server.port=80
spring.application.name=cloud-consumer-hystrix-order
#表示向注册中心注册自己
eureka.client.register-with-eureka=true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
eureka.client.fetch-registry=false
#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址
eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
#设置别名
#eureka.instance.instance-id=payment8001
#显示ip地址
#eureka.instance.prefer-ip-address=true
#开启feign对hystrix的支持
feign.hystrix.enabled=true
#feign连接时间
feign.client.config.default.connect-timeout=3000
#feign读取时间
feign.client.config.default.readTimeout=3000
2.在启动类中添加注解
@SpringBootApplication
//启用服务注册发现功能
@EnableEurekaClient
//启用Feign
@EnableFeignClients
//启动Hystrix
@EnableHystrix
//开启熔断器
@EnableCircuitBreaker
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
3.面向服务提供端8001提供的api创建接口,同时创建一个实现类。当服务提供端8001调用出现异常、超时、宕机等问题时,将会执行fallback备用方法
//value :在Eureka服务注册中心中注册的服务名,fallback :PaymentHystrixServiceApi 的实现类
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
@Component
public interface PaymentHystrixServiceApi {
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
}
4.fallback对PaymentHystrixServiceApi 进行实现
@Component
public class PaymentFallbackService implements PaymentHystrixServiceApi {
@Override
public String paymentInfo_Timeout(Integer id) {
return "PaymentFallbackService for back paymentInfo_Timeout, o(╥﹏╥)o";
}
@Override
public String paymentInfo_OK(Integer id) {
return "PaymentFallbackService for back paymentInfo_OK, o(╥﹏╥)o";
}
}
5.controller中对服务进行调用
@RestController
@RequestMapping("/consumer")
public class OrderHystrixController {
@Autowired
private PaymentHystrixServiceApi paymentHystrixServiceApi;
@GetMapping(value = "/payment/hystrix/timeout/{id}",produces = MediaType.APPLICATION_JSON_VALUE)
public String paymentInfo_Timeout(@PathVariable("id") Integer id){
String s = paymentHystrixServiceApi.paymentInfo_Timeout(id);
System.out.println("timeout:"+s);
return s;
}
@GetMapping(value = "/payment/hystrix/ok/{id}",produces = MediaType.APPLICATION_JSON_VALUE)
public String paymentInfo_OK(@PathVariable("id") Integer id){
String s = paymentHystrixServiceApi.paymentInfo_OK(id);
System.out.println("ok:"+s);
return s;
}
}
6.先启动Eureka服务注册中心,在启动服务提供端与消费者端,然后进行测试
- 当服务提供端线程睡眠时间设置没有超过feign的读取时间时,服务调用成功
- 当服务提供端线程睡眠时间设置超过feign的读取时间时,服务调用成功失败,调用这个服务的fallback方法
- 当服务多次调用失败时,将会进入熔断打开的状态,停止对服务提供端的调用,直接对服务进行降级,以防止服务的雪崩,在这里就不演示了,但是可以通过下面的配置进行熔断的属性设置
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")//失败率达到多少后跳闸
})
8.在Hystrix中有一个配置类HystrixCommandProperties,上面有更多的配置选择与描述,可自行翻阅