分布式微服务学习总结——Hystrix
文章目录
一、前言
最近刚看完springcloud、dubbo的学习视频,但感觉不是那么扎实,所以打算写一个系列的博客来巩固自身所学。
当然有些内容是参考了别的博客,毕竟我也是初探分布式微服务的,并不是所谓的大神,只是一个新手在初探分布式微服务后写下的一些自己的理解和总结。
注:以下简述部分来自官方文档翻译(官方文档写的已经很好了,所以直接搬运)
官方文档地址:https://github.com/Netflix/hystrix/wiki
二、简述
什么是 Hystrix?
在分布式环境中,不可避免地会遇到所依赖的服务挂掉的情况,Hystrix 可以通过增加 延迟容忍度 与 错误容忍度,来控制这些分布式系统的交互。Hystrix 在服务与服务之间建立了一个中间层,防止服务之间出现故障,并提供了失败时的 fallback 策略,来增加你系统的整体可靠性和弹性。
Hystrix 做了那些事情?
Hystrix 提供了以下服务
引入第三方的 client 类库,通过延迟与失败的检测,来保护服务与服务之间的调用(网络间调用最为典型)
阻止复杂的分布式系统中出现级联故障
快速失败与快速恢复机制
提供兜底方案(fallback)并在适当的时机优雅降级
提供实时监控、报警与操作控制
Hystrix 解决了什么问题?
在复杂的分布式架构中,服务之间都是相互依赖的,任何一个节点都不可避免会宕机。如果主节点不能从这些宕机节点中独立出来,那主节点将会面临被这些宕机的节点拖垮的风险。举个例子,如果一个应用依赖了 30 个服务,每个服务保证 99.99% 的时间是正常的,那可以计算出
99.9930 = 99.7% uptime
0.3% of 1 billion requests = 3,000,000 failures
2+ hours downtime/month even if all dependencies have excellent uptime.
实际情况往往更糟糕
完好情况下,请求流如下:
当一个依赖的节点坏掉时,将阻塞整个的用户请求:
流量高峰时,一个单节点的宕机或延迟,会迅速导致所有服务负载达到饱和。应用中任何一个可能通过网络访问其他服务的节点,都有可能成为造成潜在故障的来源。更严重的是,还可能导致服务之间的延迟增加,占用队列、线程等系统资源,从而导致多系统之间的级联故障。
更严重的是,当网络请求是通过第三方的一个黑盒客户端来发起时,实现细节都被隐藏起来了,而且还可能频繁变动,这样发生问题时就很难监控和改动。如果这个第三方还是通过传递依赖的,主应用程序中根本没有显示地写出调用的代码,那就更难了。
网络连接失败或者有延迟,服务将会产生故障或者响应变慢,最终反应成为一个 bug。
所有上述表现出来的故障或延迟,都需要一套管理机制,将节点变得相对独立,这样任何一个单节点故障,都至少不会拖垮整个系统的可用性。
Hystrix 的设计原则是什么?
Hystrix 通过以下设计原则来运作:
防止任何一个单节点将容器中的所有线程都占满
通过快速失败,取代放在队列中等待
提供在故障时的应急方法(fallback)
使用隔离技术 (如 bulkhead, swimlane, 和 circuit breaker patterns) 来限制任何一个依赖项的影响面
提供实时监控、报警等手段
提供低延迟的配置变更
防止客户端执行失败,不仅仅是执行网络请求的客户端
Hystrix 如何时间它的目标?
如下:
将远程请求或简单的方法调用包装成 HystrixCommand 或者 HystrixObservableCommand 对象,启动一个单独的线程来运行。
你可以为服务调用定义一个超时时间,可以为默认值,或者你自定义设置该属性,使得99.5%的请求时间都在该时间以下。
为每一个依赖的服务都分配一个线程池,当该线程池满了之后,直接拒绝,这样就防止某一个依赖的服务出问题阻塞了整个系统的其他服务
记录成功数、失败数、超时数以及拒绝数等指标
设置一个熔断器,将所有请求在一段时间内打到这个熔断器提供的方法上,触发条件可以是手动的,也可以根据失败率自动调整。
实时监控配置与属性的变更
当你启用 Hystrix 封装了原有的远程调用请求后,整个流程图变为下图所示。
接下来让我们学习如何使用它吧
三、快速入门
注解方式
此种方式最为简便,适用于大部分情况,但无法进行动态配置
1.导入依赖(服务提供者端)
<!--熔断机制-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.在需要添加熔断机制的类上加上fallback方法并进行注解(服务提供者端)
如下:
package com.dreamchaser.springcloud.controller;
import com.dreamchaser.pojo.Tag;
import com.dreamchaser.springcloud.service.TagService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class TagController {
@Autowired
TagService tagService;
@GetMapping(value = "/tag",produces = "application/json;charset=UTF-8")
//添加熔断注解
@HystrixCommand(fallbackMethod = "hystrixGet")
public @ResponseBody List<Tag> findTags(){
List<Tag> list=tagService.findTagAll();
if (list==null){
throw new RuntimeException("不存在该标签,id未找到!");
}
list.get(0).setId(8005);
return list;
}
@PostMapping("/tag")
@HystrixCommand(fallbackMethod = "hystrixGet")
public @ResponseBody String insertTag(Tag tag){
if (tagService.insertTag(tag)==1){
return "添加新标签成功!";
}else {
return "添加新标签失败!";
}
}
//备选方案
public @ResponseBody List<Tag> hystrixGet(){
Tag tag=new Tag();
tag.setId(1).setName("没有对应的信息!").setDate(new Date()).setNumber(0);
List<Tag> list=new ArrayList<>();
list.add(tag);
return list;
}
}
需要自己写个fallback方法,并且在需要加熔断机制的方法上加上@HystrixCommand(fallbackMethod = “hystrixGet”)注解,fallbackmethod表示回调的方法。
即当服务发生超时、异常或者线程已满等服务不可用的情况时,hystrix会记录,并直接执行fallback方法。当服务健康状况达到一定程度,会触发服务降级。
服务的健康状况=请求失败数/请求总数
3.开启熔断支持(服务提供者端)
在启动类上加上@EnableCircuitBreaker注解来开启熔断支持。
至此我们便已经开启了熔断机制,如果还想进行流量监控则还需以下几步。
4.注册一个servlet来作为检测地址(服务提供者端)
可以在启动类中加入一个方法
//增加一个servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean=new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setLoadOnStartup(1);
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
这表示在项目中加上一个servlet,这样访问该地址时会返回一个stream流,用来hystrix对服务进行流监控。
5.加入依赖并开启流监控(服务消费者端)
添加依赖
<!--dashboard流监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
开启流监控
@EnableHystrixDashboard
6.测试运行
启动完进程,打开http://localhost:81/hystrix(就是消费端地址后加上hystrix)
我们看到了一只豪猪。。。
访问一下业务
正常!
访问我们刚设置的servlet地址
可以看到它每隔一秒发送一段字符串
把这个地址输入hystrix页面
输入地址后点击右下角的按钮,我们可以看到这样一个画面
绿色表示服务访问成功的次数,每次刷新业务的接口地址,上面的数字就会+1。
这样就相当于与仪表盘一样来监测服务的实时状态,达到实时监控的效果。
如果想要更加详细的配置,具体可以参考这篇文章Hystrix在项目中的使用(一)-注解方式
命令式编程方式
这种方式就比较麻烦了,对代码的修改程度就比较大,一般不建议采用,不过它可以实现动态配置,如果实在要用可采用aop切面来减少对代码的影响。
具体可以参考这篇Hystrix在项目中的使用(二)-基于AOP实现命令式编程(动态配置)
四、总结
hystrix是一款功能强大的中间件,用来解决某个服务节点宕机导致服务雪崩的问题。
同时还可以用来实时监控服务的流量情况。
如果随着我的学习发现自己所写的有所纰漏或者错误,我会第一时间来修正博客,当然如果有什么错误,欢迎大家评论区评论指正,不胜感激。
愿我们都能以梦为马,不负人生韶华!
以此为记,与君共勉!