服务降级
降级,通常指高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。
支付模块
1,POM文件
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</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-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
2,YML文件
server:
port: 8001
spring:
application:
name: cloud-payment-service
eureka:
instance:
instance-id: payment8001
prefer-ip-address: true
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
3,主启动类
@SpringBootApplication @EnableEurekaClient @EnableHystrix public class HystrixPayment8001Main { public static void main(String[] args) { SpringApplication.run(HystrixPayment8001Main.class,args); } }
4,业务类
@Service public class PaymentService { public String paymentOK() { String s = UUID.randomUUID().toString(); return Thread.currentThread().getName() + "payment OK" + "\t" + s; } @HystrixCommand(fallbackMethod = "paymentTimeoutFallback", commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "5000") }) public String paymentTimeout() { String s = UUID.randomUUID().toString(); try { TimeUnit.SECONDS.sleep(6); } catch (InterruptedException e) { e.printStackTrace(); } return Thread.currentThread().getName() + "payment timeout" + "\t" + s; } public String paymentTimeoutFallback() { return "这是payment time out fallback 处理逻辑"; } }
@RestController @Slf4j public class PaymentController { @Value("${server.port}") private String serverPort; @Autowired private PaymentService paymentService; @GetMapping("/payment/ok") public String paymentOK(){ String result = paymentService.paymentOK(); log.info(result); return "payment OK "+result; } @GetMapping("/payment/timeout") public String paymentTimeout(){ String result = paymentService.paymentTimeout(); log.info("payment timeout "+result); return "payment timeout"+"\t"+serverPort+"\t"+result; } }
订单模块
1,POM文件
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</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-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
2,YML文件
server:
port: 85
spring:
application:
name: cloud-hystrix-order-service
eureka:
instance:
instance-id: order85
prefer-ip-address: true
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
feign:
hystrix:
enabled: true
ribbon:
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 10000 #单位为毫秒
#指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用的时间
ConnectTimeOut: 5000 #单位为毫秒
eureka:
enabled: true
3,主启动类
@SpringBootApplication @EnableEurekaClient @EnableHystrix @EnableFeignClients public class HystrixOrder85Main { public static void main(String[] args) { SpringApplication.run(HystrixOrder85Main.class,args); } }
4,业务类
@Component public class OrderServiceImpl implements OrderService { @Override public String paymentOK() { return "consumer ok fallback "; } @Override public String paymentTimeout() { return "consumer timeout fallback"; } }
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE",fallback = OrderServiceImpl.class) public interface OrderService { @GetMapping("/payment/ok") String paymentOK(); @GetMapping("/payment/timeout") String paymentTimeout(); }
@RestController public class OrderController { @Autowired private OrderService orderService; @GetMapping("/consumer/hystrix/payment/ok") public String paymentInfo_OK(){ String s = orderService.paymentOK(); return "consumer hystrix "+s; } @GetMapping("/consumer/hystrix/payment/timeout") /* @HystrixCommand(fallbackMethod = "fallback_handler",commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "1000") })*/ public String paymentInfo_timeout(){ String s = orderService.paymentTimeout(); return "consumer hystrix "+s; } /* public String fallback_handler(){ return "consumer hystrix 85 fallback method"; }*/ }
订单模块遇到异常情况,除了自身的fallback,还有支付模块的fallback。
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
在Spring Cloud框架里,熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况。当失败的调用满足特定条件,如5秒内20次请求,10次失败,就会启动熔断机制,熔断机制的注解是@HystrixCommand。

当Hystrix Command请求后端服务失败数量超过一定比例(默认50%),断路器会切换到开路状态(Open),这时所有请求会直接失败而不会发送到后端服务。断路器保持在开路状态一段时间(默认5秒),自动切换到半开路状态(HALF-OPEN)。这时会判断下一次请求的返回情况,如果请求成功,断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN)。Hystrix的断路器类似保险丝,一旦后端服务不可用,断路器会直接切断请求链,避免发送大量请求影响系统吞吐量,并且断路器有自我检测并恢复的能力。
断路器的状态:
- open:打开状态。请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态。
- closed:关闭状态。服务正常调用。
- half-open:半开状态,部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。
涉及断路器的三个重要参数:
- 快照时间窗口:断路器确定是否打开需要统计一些请求和错误数据。而统计的时间范围就是快照时间窗口,默认为最近的10秒。
- 请求总数的阀值:在快照时间窗口内,必须满足请求总数阀值才有资格熔断。默认为20次,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
- 错误百分比阀值,当请求总数在快照时间窗口内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比。在默认设定的50%阀值情况下,这时候就会将断路器打开。
断路器打开或关闭的条件:
- 当满足一定的阀值的时候(默认10秒内超过20个请求次数)。
- 当失败率达到一定比例的时候(默认10秒内超过50%的请求失败率)。
- 达到以上阀值,断路器将会开启。
- 当开启的时候,所有请求都不会进行转发。
- 一段时间之后(默认为5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5。
支付模块
1,POM文件
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</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-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
2,YML文件
server:
port: 8001
spring:
application:
name: cloud-payment-service
eureka:
instance:
instance-id: payment8001
prefer-ip-address: true
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
3,主启动类
@SpringBootApplication @EnableEurekaClient @EnableHystrix public class HystrixPayment8001Main { public static void main(String[] args) { SpringApplication.run(HystrixPayment8001Main.class,args); } }
4,业务类
@Service public class PaymentService { public String paymentOK() { String s = UUID.randomUUID().toString(); return Thread.currentThread().getName() + "payment OK" + "\t" + s; } @HystrixCommand(fallbackMethod = "paymentTimeoutFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) public String paymentTimeout() { String s = UUID.randomUUID().toString(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return Thread.currentThread().getName() + "payment timeout" + "\t" + s; } public String paymentTimeoutFallback() { return "这是payment time out fallback 处理逻辑"; } //circuit breaker @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", 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") } ) public String paymentCircuitBreaker(@PathVariable("id") Integer id) { if (id < 0) { throw new RuntimeException("参数小于0"); } String randomId = UUID.randomUUID().toString(); return "payment "+"\t"+id + randomId; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) { return "payment circuit breaker "+id; } }
@RestController @Slf4j public class PaymentController { @Value("${server.port}") private String serverPort; @Autowired private PaymentService paymentService; @GetMapping("/payment/ok") public String paymentOK(){ String result = paymentService.paymentOK(); log.info(result); return "payment OK "+result; } @GetMapping("/payment/timeout") public String paymentTimeout(){ String result = paymentService.paymentTimeout(); log.info("payment timeout "+result); return "payment timeout"+"\t"+serverPort+"\t"+result; } @GetMapping("/payment/circuitBreaker/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id){ return paymentService.paymentCircuitBreaker(id); } }
当发送的请求,在一定时间内超过指定的阀值,且失败率超过指定值,这时断路器有closed状态切换到open状态。open状态下直接拒绝任何请求,在一段时间后自动切换到half-open状态,这时再发送请求,如果成功,则由half-open状态切换到closed状态;否则由half-open状态切换到open状态。
Hystrix Dashboard配置
除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续第记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控的内容转化成可视化界面。
1,创建项目模块
2,POM文件
<dependencies> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> </dependencies>
2,YML文件
server:
port: 9001
3,主启动类,添加@EnableHystrixDashboard 表示开启仪表盘监控注解
@SpringBootApplication @EnableHystrixDashboard public class HystrixDashboard9001Main { public static void main(String[] args) { SpringApplication.run(HystrixDashboard9001Main.class,args); } }
4,微服务提供者添加监控jar
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
5,springboot默认路径为“/”,需要修改为“/hystrix.stream”。否则,会报错:Hystrix:Unable to connect to Command Metric Stream
HystrixMetricsStreamServlet源码给出通过xml配置
在springboot中可以采用@Bean方式配置。
解决方法(在微服务提供者配置):
配置bean
@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; }
或者yml文件中加入
management: enabled: false endpoints: web: exposure: include: hystrix.stream base-path: /
6,测试
1)启动注册服务
2)启动监控服务
3)启动被监控的带Hystrix的微服务
4)输入地址访问http://localhost:8001/hystrix.stream

- Delay参数用来控制服务器上轮询监控信息的延迟时间,默认是2000毫秒,可以通过配置该属性来降低客户端的网络和cpu消耗。
- Title参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。
当被监控的服务有被访问时,可以看出监控界面有变化。


实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康程度从绿色>黄色>橙色>红色递减;
该实心圆除了颜色的变化之外,它的大小也会根据实例请求流量发生变化,流量越大实心圆就越大,所以通过该实心圆的展示,就可以在大量实例中快速的发现故障实例和高压力实例。


posted on
浙公网安备 33010602011771号