Hystrix
简介Hystrix
是 Netlifx
开源的一款容错框架,防雪崩利器,具备服务降级,服务熔断,依赖隔离,监控 Hystrix Dashboard
等功能
官网:https://github.com/Netflix/Hystrix/wiki/How-To-Use
Hystrix
服务熔断产生的背景分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应
BUG
:如程序逻辑导致内存泄漏,JVM
长时间 FullGC
等Hystrix
Hystrix
设计目标,作用Hystrix
如何实现这些设计目标HystrixCommand
或HystrixObservableCommand
对象中,并将该对象放在单独的线程中执行Hystrix
入门Hystrix
的使用(不整合 Feign
)在使用 Feign
组件作为接口调用远程服务时,是不需要添加 Hystrix
的依赖的。因为 Feign
默认已经集成了 Hystrix
和 Ribbon
。如果单独使用 Hystrix
组件时,可以导入以下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Hystrix-study-user
服务的主启动类@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker // 开启断路器
@EnableHystrixDashboard // 开启 Hystrix 的监控仪表盘
public class UserApplication {
private static final Logger log = LoggerFactory.getLogger(UserApplication.class);
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
log.info("===============springcloud user启动了=================");
}
// 解决 hystrix-dashBoard 仪表盘不能访问
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
Hystrix-study-user
服务的 Feign
的客户端接口@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {
@RequestMapping(path = { "/activity/getCoupon" }, method = RequestMethod.POST)
String getCoupon(@RequestBody Integer id);
@RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
String getCouponTimeOut(@RequestBody Integer id);
@RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
String timeOut(@RequestParam Integer mills);
@RequestMapping(path = { "/timeOut" }, method = RequestMethod.POST)
String tripTest(@RequestParam Integer mills);
}
Hystrix-study-user
服务的服务降级类@Component
public class UserFeignFallback implements UserFeign {
@Override
public String getCoupon(Integer id) {
return null;
}
@Override
public String getCouponTimeOut(Integer id) {
return "------超过2000毫秒时,直接进入服务降级处理------";
}
@Override
public String timeOut(Integer mills) {
return "---------------您的请求【超时】或【失败】,已进入服务降级模式了----------------";
}
@Override
public String tripTest(Integer mills) {
return "-------------请求未通过-----------";
}
}
Hystrix-study-user
服务的 Service
实现类@Service
public class UserServiceImpl implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
private UserFeign userFeign;
// 使用注解 @HystrixCommand 指定服务熔断的回退方法
@HystrixCommand(fallbackMethod = "firstLoginError")
@Override
public String firstLogin(Integer id) {
// 采用 Feign 客户端来调用服务 Hystrix-study-activity
String result = userFeign.getCoupon(id);
log.info("===================result的值为:" + result + "======================");
return result;
}
// 当服务 Hystrix-study-activity 不可用时,这时让其回调回退方法
public String firstLoginError(Integer id) {
return "---------您请求的服务暂时不可用,请稍后再试--------------";
}
}
Hystrix-study-user
服务的配置文件server.port=8080
spring.application.name=study-user
eureka.client.service-url.defaultZone=http://eureka7001.com:8761/eureka/
#事实上,springcloud默认已为Feign整合了Hystrix,要想为Feign打开Hystrix支持,只需要设置feign.hystrix.enabled=true即可。
feign.hystrix.enabled=true
#补充:在springcloud Dalston之前的版本中,Feign默认开启Hystrix支持,无需设置feign.hystrix.enabled=true.
#从springcloud Dalston版本开始,Feign的Hystrix支持默认关闭,需要手动设置开启
#配置Hystrix的超时时间
#default全局有效,service id指定应用有效
hystrix.command.default.execution.timeout.enabled=true #默认为true
#默认值为 1000毫秒(对于每一个标有注解 @FeignClient 的接口的所有抽象方法生效)
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=9000
#显示服务器详细的健康信息
management.endpoint.health.show-details=always
#暴露全部的监控信息(解决hystrix-dashBoard仪表盘不能访问)
management.endpoint.web.exposure.include="*"
分别启动 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user
三个服务,使用 Postman
测试如下
此时再关闭 Hystrix-study-activity
服务
说明执行了 @HystrixCommand(fallbackMethod = "firstLoginError")
服务熔断的回退方法
@HystrixCommand
注解的简单使用依然使用上面的入门项目,只不过不需要引入 Hystrix
的依赖了,直接使用 Feign
客户端进行调用。在使用 Feign
组件作为接口调用远程服务时,是不需要添加 Hystrix
的依赖的。因为 Feign
默认已经集成了 Hystrix
和 Ribbon
。如果单独使用 Hystrix
组件时,可以导入以下依赖
Hystrix-study-user
服务的 Service
实现类添加方法execution.isolation.thread.timeoutInMilliseconds
:该属性用来配置方法执行的超时时间。我们在之前对于降级处理时间的配置,都是在全局配置文件 application.yml
中配置的,commandProperties
可以让我们在一些具有独特要求的方法上,单独进行一些配置操作
// 设置Hystrix的服务降级超时时间,超过2000毫秒时,直接进入服务降级处理
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
@Override
public String firstLoginTimeOut(Integer id) {
String result = userFeign.getCouponTimeOut(id);
log.info("===================result的值为:" + result + "======================");
return result;
}
Hystrix-study-activity
服务的 Controller
类@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {
private static final Logger log = LoggerFactory.getLogger(ActivityController.class);
@RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
@ResponseBody
public String getCouponTimeOut(@RequestBody Integer id) {
try {
Random random = new Random();
TimeUnit.SECONDS.sleep(random.nextInt(10) % (7) + 4);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("=============该用户首次登陆(注册),领取优惠券失败============");
return "error";
}
}
分别启动 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user
三个服务,使用 Postman
测试如下
说明执行了 UserFeignFallback
服务降级处理类的相应方法
Hystrix-study-activity
服务的 Controller
类再测试@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {
private static final Logger log = LoggerFactory.getLogger(ActivityController.class);
@RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
@ResponseBody
public String getCouponTimeOut(@RequestBody Integer id) {
log.info("=============该用户首次登陆(注册),领取优惠券成功============");
return "SUCCESS";
}
}
再测试结果
@HystrixCommand
注解的常见使用@Service
public class UserServiceImpl implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
private UserFeign userFeign;
@HystrixCommand(threadPoolKey = "time", threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "2"),
@HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
@Override
public String timeOut(Integer mills) {
log.info("-----------mills:的值为:" + mills + "--------------");
return userFeign.timeOut(mills);
}
@HystrixCommand(threadPoolKey = "time_1", threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "2"),
@HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
@Override
public String timeOut_1(Integer mills) {
log.info("-----------mills:的值为:" + mills + "--------------");
return userFeign.timeOut(mills);
}
/** * Hystrix的断路器测试 * * 模拟测试:3秒钟内,请求次数达到2次,并且失败率在50%以上,断路器做跳闸动作。跳闸后的活动窗口设置为3秒 * * 服务的健康状态检查:http://ip:port/actuator/health * Hystrix的健康状态为:status: "UP" * Hystrix的断路器跳闸后状态为:status: "CIRCUIT_OPEN" * 此时要删除服务的降级处理类 UserFeignFallback,才能查看健康状态 */
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "3000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000")})
@Override
public String tripTest(Integer mills) {
return userFeign.tripTest(mills);
}
}
鉴于篇幅,文章不再赘述,详情可以查看:https://www.cnblogs.com/zhenbianshu/p/9630167.html
Hystrix
与 Ribbon
的超时时间hystrix.command.default.execution.timeout.enabled = true(默认)
,则会有两个执行方法超时的配置:一个就是 ribbon
的 ReadTimeout
,一个就是熔断器 hystrix
的timeoutInMilliseconds
,此时谁的值小谁生效hystrix.command.default.execution.timeout.enabled = false
,则熔断器不进行超时熔断,而是根据 ribbon
的 ReadTimeout
抛出的异常而熔断,也就是取决于 ribbon
ribbon
的 ConnectTimeout
配置的是请求服务的超时时间,除非服务找不到,或者网络原因,这个时间才会生效ribbon
还有 MaxAutoRetries
对当前实例的重试次数,MaxAutoRetriesNextServer
对切换实例的重试次数,如果 ribbon
的 ReadTimeout
超时,或者 ConnectTimeout
连接超时,会进行重试操作ribbon
的重试机制,通常熔断的超时时间需要配置的比 ReadTimeout
长,ReadTimeout
比 ConnectTimeout
长,否则还未重试就熔断了hystrix
的超时时间为:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) /* ReadTimeout
Hystrix
的断路器工作原理10
秒内 20
次请求,当请求失败率达到默认 50%
的时,此时断路器将会开启,所有的请求都不会执行5
秒(默认)时,这时断路器是半开状态, 会允许其中一个请求执行熔断机制是应对雪崩效应的一种微服务链路保护机制,一般来说,每个服务都需要熔断机制的
使用注解 @HystrixCommand(fallbackMethod = " ")
来指定服务熔断的回退方法
@Service
public class UserServiceImpl implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
private UserFeign userFeign;
// 使用注解 @HystrixCommand 指定服务熔断的回退方法
@HystrixCommand(fallbackMethod = "firstLoginError")
@Override
public String firstLogin(Integer id) {
// 采用 Feign 客户端来调用服务 Hystrix-study-activity
String result = userFeign.getCoupon(id);
log.info("===================result的值为:" + result + "======================");
return result;
}
// 当服务 Hystrix-study-activity 不可用时,这时让其回调回退方法
public String firstLoginError(Integer id) {
return "---------您请求的服务暂时不可用,请稍后再试--------------";
}
}
RPC
调用环节来讲,就是说整体资源快不够了,忍痛将某些服务单元先关掉,关闭后还要返回一些可处理的备选方法,待渡过难关,再开启回来@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {
@RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
String getCouponTimeOut(@RequestBody Integer id);
@RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
String timeOut(@RequestParam Integer mills);
}
@Component
public class UserFeignFallback implements UserFeign {
@Override
public String getCouponTimeOut(Integer id) {
return "------超过2000毫秒时,直接进入服务降级处理------";
}
@Override
public String timeOut(Integer mills) {
return "---------------您的请求【超时】或【失败】,已进入服务降级模式了----------------";
}
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_38192427/article/details/114176876
内容来源于网络,如有侵权,请联系作者删除!