目录
5.appliction.yml 中添加配置,在客户端配置请求超时的时间
在微服务架构中,一个应用往往由多个服务组成,这些服务之间相互依赖,依赖关系错综复杂。
当服务 E 发生故障或网络延迟时,会出现以下情况:
1.即使其他所有服务都可用,由于服务 E 的不可用,那么用户请求 1、2、3 都会处于阻塞状态,等待服务 E 的响应。在高并发的场景下,会导致整个服务器的线程资源在短时间内迅速消耗殆尽
2.所有依赖于服务 E 的其他服务,例如服务 B、D 以及 F 也都会处于线程阻塞状态,等待服务 E 的响应,导致这些服务的不可用
3.所有依赖服务B、D 和 F 的服务,例如服务 A 和服务 C 也会处于线程阻塞状态,以等待服务 D 和服务 F 的响应,导致服务 A 和服务 C 也不可用
当微服务系统的一个服务出现故障时,故障会沿着服务的调用链路在系统中疯狂蔓延,最终导致整个微服务系统的瘫痪,这就是“雪崩效应”。为了防止此类事件的发生,微服务架构引入了“熔断器”的一系列服务容错和保护机制。
Hystrix
概念
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,可以保证一个服务出现故障时,不会导致整个系统出现雪崩效应,以提高分布式系统的弹性。
作为“断路器”,在一个服务出现故障时,可以通过短路器监控,返回一个可以处理的响应结果,保证服务调用线程不会被长时间占用,避免故障蔓延。
作用
保护线程资源:防止单个服务的故障耗尽系统中的所有线程资源
快速失败机制:当某个服务发生了故障,不让服务调用方一直等待,而是直接返回请求失败
提供降级(FallBack)方案:在请求失败后,提供一个设计好的降级方案,通常是一个兜底方法,当请求失败后即调用该方法
防止故障扩散:使用熔断机制,防止故障扩散到其他服务
监控功能:提供熔断器故障监控组件 Hystrix Dashboard,随时监控熔断器的状态
服务降级
简介
服务出现故障时,给故障服务降级到事先准备好的故障处理结果,将此结果返回给服务消费者;
如:
客户端访问服务1,服务1调用服务2,服务2出现故障,Hystrix服务降级,返回一个可以处理的结果给服务1,服务1再以友好的错误界面返回给客户端
使用场景
1.在服务器压力剧增时,根据实际业务情况及流量,对一些不重要、不紧急的服务进行有策略地不处理或简单处理,从而释放服务器资源以保证核心服务正常运作。
2.当某些服务不可用时,为了避免长时间等待造成服务卡顿或雪崩效应,而主动执行备用的降级逻辑立刻返回一个友好的提示,以保障主体业务不受影响
接口降级
服务端服务降级
1.添加依赖
<!--hystrix 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.定义接口
public interface DeptService {
// hystrix 熔断器示例 ok
public String deptInfo_Ok(Integer id);
//hystrix 熔断器超时案例
public String deptInfo_Timeout(Integer id);
}
3.实现接口
@Service("deptService")
public class DeptServiceImpl implements DeptService {
@Override
public String deptInfo_Ok(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " deptInfo_Ok,id: " + id;
}
//一旦该方法失败并抛出了异常信息后,会自动调用 @HystrixCommand 注解标注的 fallbackMethod 指定的方法
@HystrixCommand(fallbackMethod = "dept_TimeoutHandler",
commandProperties =
//规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
{@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")})
@Override
public String deptInfo_Timeout(Integer id) {
int outTime = 6;
try {
TimeUnit.SECONDS.sleep(outTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " deptInfo_Timeout,id: " + id + " 耗时: " + outTime;
}
// 当服务出现故障后,调用该方法给出友好提示
public String dept_TimeoutHandler(Integer id) {
return "C语言中文网提醒您,系统繁忙请稍后再试!"+"线程池:" + Thread.currentThread().getName() + " deptInfo_Timeout,id: " + id;
}
}
@HystrixCommand 注解:
参数 fallbackMethod 属性用于指定降级方法
参数 execution.isolation.thread.timeoutInMilliseconds 用于设置自身调用超时时间的峰值,峰值内可以正常运行,否则执行降级方法
4.Controller类使用
@RestController
@Slf4j
public class DeptController {
@Autowired
private DeptService deptService;
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/dept/hystrix/ok/{id}")
public String deptInfo_Ok(@PathVariable("id") Integer id) {
String result = deptService.deptInfo_Ok(id);
log.info("端口号:" + serverPort + " result:" + result);
return result + ", 端口号:" + serverPort;
}
// Hystrix 服务超时降级
@RequestMapping(value = "/dept/hystrix/timeout/{id}")
public String deptInfo_Timeout(@PathVariable("id") Integer id) {
String result = deptService.deptInfo_Timeout(id);
log.info("端口号:" + serverPort + " result:" + result);
return result + ", 端口号:" + serverPort;
}
}
5.启动类添加注释
@SpringBootApplication
@EnableEurekaClient //开启 Eureka 客户端功能
@EnableCircuitBreaker //激活熔断器功能
public class MicroServiceCloudProviderDeptHystrix8004Application {
public static void main(String[] args) {
SpringApplication.run(MicroServiceCloudProviderDeptHystrix8004Application.class, args);
}
}
6.浏览器访问
客户端服务降级
通常情况下,我们都会在客户端进行服务降级,当客户端调用的服务端的服务不可用时,客户端直接进行服务降级处理,避免其线程被长时间、不必要地占用
1.添加依赖
<!--hystrix 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.application.yml 中添加配置
application.yml 中添加以下配置,开启客户端的 Hystrix 功能
feign:
hystrix:
enabled: true #开启客户端 hystrix
3.定义接口
@Component
@FeignClient(value = "MICROSERVICECLOUDPROVIDERDEPTHYSTRIX")
public interface DeptHystrixService {
@RequestMapping(value = "/dept/hystrix/ok/{id}")
public String deptInfo_Ok(@PathVariable("id") Integer id);
@RequestMapping(value = "/dept/hystrix/timeout/{id}")
public String deptInfo_Timeout(@PathVariable("id") Integer id);
}
4.Controller类使用
@Slf4j
@RestController
public class HystrixController_Consumer {
@Resource
private DeptHystrixService deptHystrixService;
@RequestMapping(value = "/consumer/dept/hystrix/ok/{id}")
public String deptInfo_Ok(@PathVariable("id") Integer id) {
return deptHystrixService.deptInfo_Ok(id);
}
//在客户端进行降级
@RequestMapping(value = "/consumer/dept/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "dept_TimeoutHandler") //为该请求指定专属的回退方法
public String deptInfo_Timeout(@PathVariable("id") Integer id) {
String s = deptHystrixService.deptInfo_Timeout(id);
log.info(s);
return s;
}
// deptInfo_Timeout方法的 专用 fallback 方法
public String dept_TimeoutHandler(@PathVariable("id") Integer id) {
log.info("deptInfo_Timeout 出错,服务已被降级!");
return "C语言中文网提醒您:服务端系统繁忙,请稍后再试!(客户端 deptInfo_Timeout 专属的回退方法触发)";
}
}
5.appliction.yml 中添加配置,在客户端配置请求超时的时间
######################### Ribbon 客户端超时控制 ###################################
ribbon:
ReadTimeout: 6000 #建立连接所用的时间,适用于网络状况正常的情况下,两端两端连接所用的时间
ConnectionTimeout: 6000 #建立连接后,服务器读取到可用资源的时间
######################配置请求超时时间##########################
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 7000
####################配置具体方法超时时间 为 3 秒########################
DeptHystrixService#deptInfo_Timeout(Integer):
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
注意:
1.Hystrix 可以来为所有请求(方法)设置超时时间(单位为毫秒),若请求超时则触发全局的回退方法进行处理
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=mmm
2.Hystrix 还可以为某个特定的服务请求(方法)设置超时时间
hystrix.command.xxx#yyy(zzz).execution.isolation.thread.timeoutInMilliseconds=mmm
格式说明如下:
- xxx:为包含该服务方法的类的名称(通常为服务绑定接口的名称),例如 DeptHystrixService 接口。
- yyy:服务方法名,例如 deptInfo_Timeout() 方法。
- zzz:方法内的参数类型,例如 Integer、String 等等
- mmm:要设置的超时时间,单位为毫秒(1 秒 =1000 毫秒)
6.启动类添加注释
@SpringBootApplication
@EnableFeignClients //开启 OpenFeign 功能
@EnableHystrix //启用 Hystrix
public class MicroServiceCloudConsumerDeptFeignApplication {
public static void main(String[] args) {
SpringApplication.run(MicroServiceCloudConsumerDeptFeignApplication.class, args);
}
}
7.浏览器访问
全局降级
针对所有业务方法都配置降级方法,这极有可能会造成代码的急剧膨胀。为了解决该问题,我们还可以为所有业务方法指定一个全局的回退方法
1.注解配置
@Slf4j
@RestController
@DefaultProperties(defaultFallback = "dept_Global_FallbackMethod") //全局的服务降级方法
public class HystrixController_Consumer {
……
}
2.创建方法
创建一个名为 dept_Global_FallbackMethod 的全局回退方法
/**
* 全局的 fallback 方法,
* 回退方法必须和 hystrix 的执行方法在相同类中
* @DefaultProperties(defaultFallback = "dept_Global_FallbackMethod") 类上注解,请求方法上使用 @HystrixCommand 注解
*/
public String dept_Global_FallbackMethod() {
return "C语言中文网提醒您,运行出错或服务端系统繁忙,请稍后再试!(客户端全局回退方法触发,)";
}
降级(FallBack)方法必须与其对应的业务方法在同一个类中,否则无法生效
3.业务方法标注注解
在所有的业务方法上都标注 @HystrixCommand 注解,将 deptInfo_Timeout() 方法上的 @HystrixCommand(fallbackMethod = "dept_TimeoutHandler") 修改为 @HystrixCommand 即可
//在客户端进行降级
@RequestMapping(value = "/consumer/dept/hystrix/timeout/{id}")
@HystrixCommand
public String deptInfo_Timeout(@PathVariable("id") Integer id) {
String s = deptHystrixService.deptInfo_Timeout(id);
log.info(s);
return s;
}
全局降级方法的优先级较低,只有业务方法没有指定其降级方法时,服务降级时才会触发全局回退方法。若业务方法指定它自己的回退方法,那么在服务降级时,就只会直接触发它自己的回退方法,而非全局回退方法。
4.浏览器访问
服务熔断
简介
熔断机制是应对服务雪崩的一种链路保护机制,当服务出现故障时,服务会进行降级,熔断该服务节点,迅速返回错误响应信息。当检测到服务访问正常时,恢复其链路节点
熔断参数设置
①circuitBreaker.enabled:是否开启熔断;
②circuitBreaker.requestVolumeThreshold:当前服务失败几次后开启断路,默认20次;
③circuitBreaker.sleepWindowInMilliseconds:设置断路时间,过了该时间后会尝试恢复,在断路时间内,即使请求正确也会走降级方法;
熔断类型
在熔断机制中涉及了三种熔断类型:
熔断打开
熔断打开后,在此时间内不会对该服务进行调用,而是直接访问降级方法。通过设置熔断时间,当达到该时间后,会尝试恢复该服务
熔断关闭
熔断关闭代表服务正常,不会干扰正常服务调用。
熔断半开
熔断半开时,请求可以访问服务,若请求正常访问,则熔断会关闭;若请请求不正常,继续熔断,调用降级方法。
熔断机制
熔断机制是通过 Hystrix 实现的。Hystrix 会监控微服务间调用的状况,当失败调用到一定比例时(例如 5 秒内失败 20 次),就会启动熔断机制
使用步骤
1.当服务的调用出错率达到或超过 Hystix 规定的比率(默认为 50%)后,熔断器进入熔断开启状态。
2.熔断器进入熔断开启状态后,Hystrix 会启动一个休眠时间窗,在这个时间窗内,该服务的降级逻辑会临时充当业务主逻辑,而原来的业务主逻辑不可用。
3.当有请求再次调用该服务时,会直接调用降级逻辑快速地返回失败响应,以避免系统雪崩。
4.当休眠时间窗到期后,Hystrix 会进入半熔断转态,允许部分请求对服务原来的主业务逻辑进行调用,并监控其调用成功率。
5.如果调用成功率达到预期,则说明服务已恢复正常,Hystrix 进入熔断关闭状态,服务原来的主业务逻辑恢复;否则 Hystrix 重新进入熔断开启状态,休眠时间窗口重新计时,继续重复第 2 到第 5 步。
示例
1.定义接口
public interface DeptService {
// hystrix 熔断器示例 ok
public String deptInfo_Ok(Integer id);
//hystrix 熔断器超时案例
public String deptInfo_Timeout(Integer id);
// Hystrix 熔断机制案例
public String deptCircuitBreaker(Integer id);
}
2.实现接口
实现类 DeptServiceImpl 添加 deptCircuitBreaker() 的方法实现及其回退方法
//Hystrix 熔断案例
@Override
@HystrixCommand(fallbackMethod = "deptCircuitBreaker_fallback", commandProperties = {
//以下参数在 HystrixCommandProperties 类中有默认配置
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启熔断器
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "1000"), //统计时间窗
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //统计时间窗内请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //在统计时间窗口期以内,请求失败率达到 60% 时进入熔断状态
})
public String deptCircuitBreaker(Integer id) {
if (id < 0) {
//当传入的 id 为负数时,抛出异常,调用降级方法
throw new RuntimeException("c语言中文网提醒您,id 不能是负数!");
}
String serialNum = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号为:" + serialNum;
}
//deptCircuitBreaker 的降级方法
public String deptCircuitBreaker_fallback(Integer id) {
return "c语言中文网提醒您,id 不能是负数,请稍后重试!\t id:" + id;
}
3.方法对外提供服务
// Hystrix 服务熔断
@RequestMapping(value = "/dept/hystrix/circuit/{id}")
public String deptCircuitBreaker(@PathVariable("id") Integer id){
String result = deptService.deptCircuitBreaker(id);
log.info("result:"+result);
return result;
}
4.浏览器访问
故障监控
Hystrix 还提供了准实时的调用监控功能,Hystrix 会持续地记录所有通过 Hystrix 发起的请求的执行信息,并以统计报表的形式展示给用户,包括每秒执行请求的数量、成功请求的数量和失败请求的数量等
1.添加依赖
<!--hystrix-dashboard 监控的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2.application.yml 中添加配置
#http://eureka7001.com:9002/hystrix 熔断器监控页面
# localhost:8004//actuator/hystrix.stream 监控地址
hystrix:
dashboard:
proxy-stream-allow-list:
- "localhost"
3.主启动类上添加 @EnableHystrixDashboard 注解,开启 Hystrix 监控功能
@SpringBootApplication
@EnableHystrixDashboard
public class MicroServiceCloudConsumerDeptHystrixDashboard9002Application {
public static void main(String[] args) {
SpringApplication.run(MicroServiceCloudConsumerDeptHystrixDashboard9002Application.class, args);
}
}
4.创建配置类
@Configuration
public class HystrixDashboardConfig {
/**
* Hystrix dashboard 监控界面必须配置
* @return
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");//访问路径
registrationBean.setName("hystrix.stream");
return registrationBean;
}
}
5.浏览器访问