五、Hystrix断路器
1. 概念
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间等待或抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
服务雪崩
多个微服务之间调用时,若微服务A调用B、C,而B、C又调用其他微服务,这就是所谓的“扇出”。若扇出的链路上某个微服务的调用响应时间过长或不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,即所谓的“雪崩效应”。
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败,比如超时、异常等。Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
Hystrix提供服务熔断与服务降级等方式实现故障处理。
2. 服务熔断
2.1 概念
服务熔断机制,是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或长时间未响应时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的相应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
在SpringCloud框架中,Hystrix会监控微服务间的调用状况,当失败的调用达到一定阈值(缺省:15秒内20次调用失败),就会启动熔断机制,通过@HystrixCommand
注解实现。
2.2 代码实现(Service Provider)
2.2.1 新建项目
在工程spring-cloud-demo下,新建module,名为service-member-hystrix-8010(参考service-member-8010)。
2.2.2 引入依赖
引入spring-cloud-starter-hystrix依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 监控信息完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
</dependencies>
2.2.3 添加yml文件
eureka:
client: #将客户端注册进Eureka服务列表内
serviceUrl:
defaultZone: http://eureka7777.com:7777/eureka/,http://eureka8888.com:8888/eureka/,http://eureka9999.com:9999/eureka/
instance:
instance-id: service-member-hystrix-8010 #自定义Eureka微服务管理页面的显示别名
prefer-ip-address: true #访问路径可以显示IP地址,默认为false 不显示
server:
port: 8010
spring:
application:
name: service-member
info:
app.name: charver-springclouddemo-servicemember
company.name: www.chavaer.com
contact.name: chavaer
contact.phone: 188-3288-3388
contace.email: chavaer@super.com.cn
2.2.4 添加Controller
- 新建MemberController,将service-member-8010项目中的MemberController复制过来。
- 对获取会员列表方法进行改造,若出现查询数据库异常,则进行异常处理。通过@HystrixCommand注解指定异常情况下需执行的方法processGetMember()。
- 一旦调用方法失败并抛出异常信息后,会自动调用@HystrixCommand标注好的fallbackMethod方法。类似于Spring的异常通知。
- 添加processGetMember()方法,返回提示内容。
@Controller
@RequestMapping("/member")
public class MemberController {
@Autowired
private DiscoveryClient client;
@RequestMapping("/list")
@ResponseBody
@HystrixCommand(fallbackMethod = "processGetMember")
public Map<String, String> getAllMember() {
//构造异常
throw new RuntimeException("查询数据库异常");
}
public Map<String, String> processGetMember() {
HashMap<String, String> map = new HashMap<>(1);
map.put("9999", "系统异常,请稍后访问!");
return map;
}
@RequestMapping("/discovery")
@ResponseBody
public Object discovery() {
System.out.println("Current client : " + client.description());
List<String> services = client.getServices();
System.out.println("Current service list : " + services);
for (String service : services) {
List<ServiceInstance> instances = client.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println(instance.getServiceId() + "\t" + instance.getHost() + "\t"
+ instance.getPort() + "\t" + instance.getUri());
}
}
return client;
}
}
2.2.5 修改启动类
通过@EnableCircuitBreaker
开启对hystrix熔断机制的支持。
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册到Eureka服务列表中
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker //对hystrix熔断机制的支持
public class MemberHystrix8010App {
public static void main(String[] args) {
SpringApplication.run(MemberHystrix8010App.class, args);
}
}
2.2.6 效果测试
分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Service Consumer:service-order
在浏览器访问:http://localhost:8002/order/getMemberList ,获取会员列表,即可立即展示错误信息:
3. 服务降级
3.1 概念
服务降级,简单来说,就是在系统资源紧张时,将某些资源暂时关闭,待系统正常,再重新开启。
服务熔断,是在方法上加上@HystrixCommand注解,然后添加一个fallback方法,这会带来两个问题:① 每个方法都需要有一个对应的fallback方法,最终会造成方法膨胀;② 处理具体业务的方法,要配合fallback方法一起使用,耦合度太高。
基于此,借鉴Spring AOP思想,要实现业务逻辑方法与错误响应方法解耦分离,可以使用一个类,专门用于处理异常响应,与具体的业务逻辑分离开。服务降级的处理方式,就是这种思想。
- 服务降级:是在客户端(服务消费者)完成,与服务端没有关系,配合@FeignClient注解使用,一般是对服务提供者关闭的情况做出备选响应。
- 服务熔断:是在服务端(服务提供者)完成,配合@HystrixCommand注解使用,一般是一个业务逻辑方法对应一个响应处理方法。
3.2 代码实现(Service Consumer)
3.2.1 新建异常处理类
在客户端(服务消费者)service-order-feign工程中,针对OrderClientService
,新增一个异常处理的类OrderClientServiceFallbackFactory
,实现FallbackFactory接口,泛型给定OrderClientService类型,重写方法create,返回匿名内部类(OrderClientService接口的实现类,重写接口的方法,内容为服务降级提示外界的信息)。
OrderClientService接口中的方法都是调用服务端,服务端关闭,因此可以针对OrderClientService接口,覆写该接口中的所有方法,以达到服务降级提示外界的目的。
@Component
public class OrderClientServiceFallbackFactory implements FallbackFactory<OrderClientService> {
@Override
public OrderClientService create(Throwable throwable) {
return new OrderClientService() {
@Override
public Map<String, String> getMemberList() {
return (Map<String, String>)getShowInfo();
}
@Override
public Object discovery() {
return getShowInfo();
}
private Object getShowInfo() {
HashMap<String, String> map = new HashMap<String, String>(1);
map.put("9999", "暂停服务!");
return map;
}
};
}
}
在OrderClientService接口中,有一个@FeignClient
注解,可以指定值fallbackFactory为刚才新增的类OrderClientServiceFallbackFactory.class
。
//@FeignClient(value = "service-member")
@FeignClient(value = "service-member", fallbackFactory = OrderClientServiceFallbackFactory.class)
public interface OrderClientService {
@RequestMapping("/member/list")
Map<String, String> getMemberList();
@RequestMapping("/member/discovery")
Object discovery();
}
3.2.2 修改yml文件
由于我们在service-order-feign的OrderClientService中,异常响应的处理类借助于@FeignClient,因此需要开启Feign对Hystrix的支持。
eureka:
client:
serviceUrl:
defaultZone: http://eureka7777.com:7777/eureka/,http://eureka8888.com:8888/eureka/,http://eureka9999.com:9999/eureka/
registerWithEureka: false #Service-order服务作为Eureka Client,不向注册中心注册
server:
port: 8002
feign:
hystrix:
enabled: true
3.2.3 效果测试
分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Service Consumer:service-order-feign
- 正常情况下:
测试服务发现接口:http://localhost:8002/order/memberDiscovery
- 手动停止service-member-hystrix-8010服务:
测试服务发现接口:http://localhost:8002/order/memberDiscovery
3.2.4 注意事项
- 异常响应处理类OrderClientServiceFallbackFactory必须@Component被Spring容器管理;
- @FeignClient注解的属性为
fallbackFactory
,若不慎写成fallback,会抛出创建bean失败的异常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'orderClientService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.charver.cloud.service.OrderClientService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Incompatible fallback instance. Fallback/fallbackFactory of type class com.charver.cloud.service.OrderClientServiceFallbackFactory is not assignable to interface com.charver.cloud.service.OrderClientService for feign client service-member
解决方式有两种:
① 第一种是将fallback修改为fallbackFactory。
② 第二种是将异常响应处理类OrderClientServiceFallbackFactory直接实现OrderService接口,而非实现FallbackFactory接口。
4. 服务监控
4.1 概念
除隔离依赖服务的调用外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续的记录所有通过Hystrix发起的请求执行信息,并统计报表和图表的形式展示给用户,包括每秒执行多少次,成功与失败次数等。
Netflix通过hystrix-metrics-event-stream项目实现对以上指标的监控,SpringCloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。
4.2 代码实现
4.2.1 新建项目
在工程spring-cloud-demo下新建一个module,名为service-hystrix-dashboard。
4.2.2 引入依赖
<!-- hystrix与hystrix-dashboard相关-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
4.2.3 修改yml文件
server:
port: 9001
4.2.4 修改启动类
@EnableHystrixDashboard
注解开启对Hystrix-Dashboard的支持。
@SpringBootApplication
@EnableHystrixDashboard
public class DashboardApp {
public static void main(String[] args) {
SpringApplication.run(DashboardApp.class, args);
}
}
4.2.5 服务提供方添加监控依赖配置
服务提供者引入监控依赖,service-member-8010、service-member-8011、service-member-8012、service-member-hystrix-8010之前已引入依赖;
<!-- 监控信息完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
4.3 效果测试
分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Hystrix Dashboard:service-hystrix-dashboard
- 访问url:http://localhost:9001/hystrix,出现豪猪标志,说明Hystrix Dashboard服务监控配置启动成功。
Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000ms,可以通过配置该属性来降低客户端的网络与CPU消耗。
Title:该参数对应头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。
- 现要实现service-hystrix-dashboard服务监控service-member-hystrix-8010服务的信息,访问url:http://localhost:8010/hystrix.stream
可发现,url在被不断自动刷新,且页面出现ping、data数据,这说明service-member-hystrix-8010服务已经在持续被监控了。 - 为了直观的看到效果,可以在豪猪页面的url区域填写监控的目标url:
http://localhost:8010/hystrix.stream
,输入完成后,点击”Monitor Stream“按钮,可出现如下页面:
可看出目前正在监控着service-member-hystrix-8010服务的MemberController中的getAllMember方法,有Success | Short-Circuited | Timeout | Rejected | Failure | Error
七种颜色表示其中状态。
方法左边区域的实心圆,共有两种含义:① 通过颜色变化代表实例的健康程度,健康度从绿色→黄色→橙色→红色依次降低;② 通过大小变化代表实例的请求流量变化,流量越大,实心圆越大。通过实心圆的外观变化,快速的从大量实例中发现故障与高压力实例。 - 在浏览器测试调用MemberController中的getAllMember方法,效果如下:
-
【上一篇】四、Feign负载均衡
【下一篇】六、Zuul路由网关