在分布式系统中服务与服务之间的依赖错综复杂,一种不可避免的情况就是某些服务会出现故障,导致依赖于它们的其他服务出现远程调度的线程阻塞。某个服务的单个点的请求故障会导致用户的请求处于阻塞状态,最终的结果是整个服务的线程资源消耗殆尽。由于服务的依赖性,会导致依赖于该故障服务的其他服务也处于线程阻塞状态,最终导致这些服务的线程资源消耗殆尽,直到不可用,从而导致整个服务系统不可用,即雪崩效应。为了防止雪崩效应,产生了熔断器模型。
SpringCloud Netflix实现了断路器库的名字叫Hystrix,提供了熔断器功能,能阻止分布式系统中出现联动故障。Hystrix是通过隔离服务的访问点阻止联动故障的,并提供了故障解决方案,从而提高了整个分布式系统的弹性。
当服务的某个API接口的失败次数在一定时间内小于设定的阈值时,熔断器处于关闭状态,该API接口正常提供服务。当该API接口处理请求的失败次数大于设定的阈值时,Hystrix判定该API接口出现了故障,打开熔断器,这时请求该API接口会执行快速失败的逻辑(即fallback回退的逻辑),不执行业务逻辑,请求的线程不会处于阻塞状态。处于打开状态的熔断器,一段时间后会处于半打开状态,并将一定数量的请求执行正常逻辑,剩余的请求会执行快速失败,若执行正常逻辑的请求失败了,则熔断器继续打开,若成功了,则关闭熔断器。这样熔断器就具有了自我修复的能力。
图中的服务B因为某些原因失败,变得不可用,所有对服务B的调用都会超时。当对B的调用失败达到一个特定的阀值(5秒之内发生20次失败是Hystrix定义的缺省值), 链路就会被处于open状态,之后所有对服务B的调用都不会被执行, 取而代之的是由断路器提供的一个表示链路open的Fallback消息. Hystrix提供了相应机制,可以让开发者定义这个Fallbak消息。
open的链路阻断了瀑布式错误, 可以让被淹没或者错误的服务有时间进行修复。这个fallback可以是另外一个Hystrix保护的调用, 静态数据,或者合法的空值。Fallbacks可以组成链式结构,所以最底层调用其它业务服务的第一个Fallback返回静态数据。
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
加上@EnableHystrix注解,开启hystrix熔断器功能
package org.springcloud.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
在hi()方法上加上@HystrixCommand注解。有了该注解hi()方法就启用了Hystrix熔断器的功能,其中:
@HystrixCommand 表明该方法为hystrix包裹,可以对依赖服务进行隔离、降级、快速失败、快速重试等等hystrix相关功能
fallbackMethod为处理回退(fallback)逻辑的方法。在本例子,直接返回了一个字符串。在熔断器打开的状态下,会执行fallback逻辑。fallback的逻辑最好是返回一些静态的字符串,不需要处理复杂的逻辑,也不会远程调用其他服务,这样方便执行快速失败,释放线程资源。如果一定要在fallback逻辑中远程调用其他服务,最好在远程调用其他服务时,也加上熔断器。
package org.springcloud.ribbon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@Service
public class RibbonService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hi(String name){
return restTemplate.getForObject("http://springcloud-eureka-provider/hi?name="+name,String.class);
}
public String hiError(String name){
return "hi,"+name+", use Ribbon + hystrix, eureka-provider is down!";
}
}
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-ribbon
全部正常启动后,停止 springcloud-eureka-provider1 提供者,端口为:8001服务
访问命令窗口curl http://eureka-ribbon.com:8100/hi?name=zhaojq,断路器已经生效,提示:提供者服务挂了
Feign是自带断路器的,它没有默认打开。需要在配置文件中打开它。
spring:
application:
name: springcloud-feign
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8101
eureka:
instance:
hostname: eureka-feign.com
instance-id: eureka-feign
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
feign:
hystrix:
enabled: true
在@FeignClient注解的fallback配置加上快速失败的处理类。该处理类是作为Feign熔断器的逻辑处理类,必须实现被@FeignClient修饰的接口。
package org.springcloud.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Component
/*指定这个接口所要调用的提供者服务名称 */
@FeignClient(value = "springcloud-eureka-provider",configuration = FeignConfig.class,fallback = FeignHystrix.class)
public interface FeignConsumer {
@GetMapping(value = "/hi")
String sayHiFromEurekaProvider(@RequestParam(value = "name")String name);
}
package org.springcloud.feign;
import org.springframework.stereotype.Component;
@Component
public class FeignHystrix implements FeignConsumer {
@Override
public String sayHiFromEurekaProvider(String name) {
eturn "hi,"+name+", use Feign + hystrix, eureka-provider is down!";
}
}
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-feign
全部正常启动后,停止 springcloud-eureka-provider1 提供者,端口为:8001服务
访问命令窗口curl http://eureka-feign.com:8101/hi,断路器已经生效,提示:提供者服务挂了
Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界面。
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
启动actuator监控
spring:
application:
name: springcloud-ribbon
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8100
# 自定义配置负载均衡策略
Load_Balance:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
eureka:
instance:
hostname: eureka-ribbon.com
instance-id: eureka-ribbon
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
#actuator端口
management:
endpoints:
web:
#修改访问路径 2.0之前默认是/, 2.0默认是 /actuator
base-path: "/actuator"
#开放所有页面节点 默认只开启了health、info两个节点
exposure:
include: '*'
server:
port: 9001
servlet:
context-path: /
ssl:
enabled: false
endpoint:
health:
show-details: always
hystrix:
stream:
enabled: true
加上@EnableHystrixDashboard注解.
package org.springcloud.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-ribbon
在浏览器访问先访问http://eureka-ribbon.com:8100/hi,然后再访问http://eureka-ribbon.com:9001/actuator/hystrix.stream,浏览器会显示熔断器的数据指标
访问http://eureka-ribbon.com:8100/hystrix
该页面显示了熔断器的谷中数据指标,这些数据指标含义如图,该图来自于Hystrix官方文档,文档地址:https://github.com/Netflix/Hystrix/wiki
Feign自带的Hystrix依赖不是起步依赖,所以还需要在POM中加上起步依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
启动actuator监控
spring:
application:
name: springcloud-feign
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8101
eureka:
instance:
hostname: eureka-feign.com
instance-id: eureka-feign
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
feign:
hystrix:
enabled: true
management:
endpoints:
web:
base-path: "/actuator"
exposure:
include: "*"
server:
port: 9002
servlet:
context-path: /
ssl:
enabled: false
endpoint:
health:
show-details: always
hystrix:
stream:
enabled: true
加上@EnableHystrix和@EnableHystrixDashboard注解.
package org.springcloud.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-feign
在浏览器访问先访问http://eureka-feign.com:8101/hi,然后再访问http://eureka-feign.com:9002/actuator/hystrix.stream,浏览器会显示熔断器的数据指标
访问http://eureka-feign.com:8101/hystrix
点击 Moniter Stream