1. 方法降级
provider
@RestController
@RequestMapping("/hystrix")
public class ProviderHystrixController {
@GetMapping("/error")
public String getInternalError() {
Random random = new Random();
boolean flag = random.nextBoolean();
if (flag) {
return "normal work";
} else {
throw new RuntimeException("wrong parameters");
}
}
@GetMapping("/timeout")
public String getTimeOut() throws InterruptedException {
TimeUnit.SECONDS.sleep(10);
return "after 5s, the result is returned";
}
}
consumer
# 主启动类上加,开启hystrix服务降级及熔断的功能
# @EnableHystrix继承了@EnableCricuitBreaker
@EnableCircuitBreaker 或者 @EnableHystrix
package com.nike.consumer.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consumer")
public class ConsumerHystrixController {
private RestTemplate template = new RestTemplate();
private final String providerErrorUrl = "http://localhost:9001/hystrix/error";
private final String providerTimeOutUrl = "http://localhost:9001/hystrix/timeout";
/**
* 出错的业务, 提供了服务降级的方案
*/
@GetMapping("/error")
@HystrixCommand(fallbackMethod = "internalErrorHystrix")
public String getInternalError() {
return template.getForObject(providerErrorUrl, String.class);
}
private String internalErrorHystrix() {
return "server internal error, check your parameters";
}
/**
* 网络异常业务: 3s 内走正常逻辑, 3s外就走降级逻辑
*/
@GetMapping("/timeout")
@HystrixCommand(fallbackMethod = "netWorkBusinessHystrix", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String getTimeOut() throws InterruptedException {
return template.getForObject(providerTimeOutUrl, String.class);
}
private String netWorkBusinessHystrix() {
return "Server Connection Error, Try Again";
}
}
2. 全局配置
- 不可能为每一个方法都提供一个服务降级处理的方法
- 为类中所有方法配置全局服务降级的方法,某些方法可以单独自定义
@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "globalHandler") // 全局变量处理
public class ConsumerHystrixController {
private RestTemplate template = new RestTemplate();
private final String providerErrorUrl = "http://localhost:9001/hystrix/error";
private final String providerTimeOutUrl = "http://localhost:9001/hystrix/timeout";
/**
* 交给全局服务降级处理的方法,必须加@HystrixCommand,否则全局处理不会生效
*/
@HystrixCommand
@RequestMapping("/info")
public String getInfo() {
int i = 1 / 0;
return "math error";
}
private String globalHandler() {
return "global error processed";
}
@GetMapping("/error")
@HystrixCommand(fallbackMethod = "internalErrorHystrix")
public String getInternalError() {
return template.getForObject(providerErrorUrl, String.class);
}
private String internalErrorHystrix() {
return "server internal error, check your parameters";
}
/**
* 个别方法需要单独特殊处理的,在该方法上再添加具体的配置
*/
@GetMapping("/timeout")
@HystrixCommand(fallbackMethod = "netWorkBusinessHystrix", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String getTimeOut() throws InterruptedException {
return template.getForObject(providerTimeOutUrl, String.class);
}
/**服务降级的方法必须和处理的接口的参数一致*/
private String netWorkBusinessHystrix() {
return "Server Connection Error, Try Again";
}
}
三、服务熔断
1. 在指定时间窗口期内及请求次数,如果失败率达到60%,则开启服务熔断; Closed
2. 再次用正确的参数来进行,断路器依然为Closed,直接进行服务降级
3. 慢慢的将断路器更换为 Half Closed,并尝试来调用当前服务
4. 如果服务恢复了,则变为Open,如果依然是失败的,则继续恢复为Closed
@RequestMapping("/breaker")
@RestController
public class ConsumerCircuitController {
@HystrixCommand(fallbackMethod = "backupPlan", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),// 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 失败率达到多少后开启
})
@GetMapping("/info")
public String getInfo(Integer id) {
if (id < 0) {
throw new RuntimeException("id不能为负数");
}
return new Date() + " ===== " + id + " 正常访问";
}
public String backupPlan(Integer id) {
return new Date() + " ===== " + id + " 服务降级";
}
}
四、服务监控
4.1 DashBoard服务
- 单独搭建一个微服务,用来观察指定服务的降级,熔断情况等
<!--1. web模块的starter和健康检查的starter-->
<!--hystrix的dashboard仪表盘-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
server:
port: 9100
# 不配置如下可能出现如下错误:
# Origin parameter: http://localhost:8080/actuator/hystrix.stream is not in the allowed list of proxy host names.
# If it should be allowed add it to hystrix.dashboard.proxyStreamAllowList.
hystrix:
dashboard:
proxy-stream-allow-list: localhost
# 允许监控的ip,不同版本可能不同
# 主启动类
@EnableHystrixDashboard
# 访问地址
http://localhost:9100/hystrix
4.2 微服务上监控
# 监控: pom中必须带有下面的依赖
spring-boot-starter-actuator
@SpringBootApplication
@EnableCircuitBreaker // hystrix服务降级及熔断的功能开启
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
/**
* 如果不添加下面的bean,监控时候就会链接不到该微服务
* 报错信息: Unable to connect to Command Metric Stream.
* @return
*/
@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;
}
}
4.3. 数据分析
1. 启动DashBoard和业务微服务,页面输入 微服务 ip, 端口
http://localhost:8001/hystrix.stream
2. 随机访问微服务业务断,不断发生服务降级及熔断等多种情况
3. 页面的信息是实时变化的,可以统计当前该服务的访问情况