什么是服务雪崩?
单个服务发生故障, 占用过多的系统资源, 从而导致级联故障的情况称为服务雪崩.
什么是 Hystrix?
在分布式环境中, 许多服务依赖项中的一些必然会失败.(服务挂了)
Hystrix 是一个库, 通过添加延迟容忍和容错逻辑, 控制这些分布式服务之间的交互.
Hystrix 通过隔离服务之间的访问点, 停止级联失败和提供回退选项来实现这一点, 所有这些都可以提高系统的整体弹性.
容错: 允许犯错, 在微服务开放中主要体现在服务故障.
简言之, Hystrix 是一个实现容错机制的组件.[也是实现高可用的目的]
Hystrix 的主要作用
为网络请求设置超时
使用断路器模式
什么是断路器模式?
家用空开就是一种断路器模式, 前身是保险丝. 假设某个电器负载过大而损坏, 空开会跳闸, 而保险丝会熔断.
假设没有空开或者保险丝呢? 引起更大的电路故障, 甚至导致火灾, 再扩张可能会烧到邻居家的房子.
对于微服务来说同样如此, 当某一个服务出现问题时, 使用断路器关停服务, 不会导致由于持续访问导致的资源占有从而引起其他服务的正常运行.
服务熔断与服务降级
服务熔断指的是当网络请求达到某一个阈值 (可设置) 时, 为了防止服务过载, 占用系统资源, 暂停该服务的调用, 使服务降级.[服务没挂, 但是担心挂了, 就让服务暂时休息一下]
服务降级涉及的范围更大,
超时降级: 主要配置好超时时间和超时重试次数和机制, 并使用异步机制探测回复情况
失败次数降级: 主要是一些不稳定的 API, 当失败调用次数达到一定阀值自动降级, 同样要使用异步机制探测回复情况
故障降级: 比如要调用的远程服务挂掉了(网络故障, DNS 故障, http 服务返回错误的状态码, rpc 服务抛出异常), 则可以直接降级. 降级后的处理方案有: 默认值(比如库存服务挂了, 返回默认现货), 兜底数据(比如广告挂了, 返回提前准备好的一些静态页面), 缓存(之前暂存的一些缓存数据)
限流降级
当我们去秒杀或者抢购一些限购商品时, 此时可能会因为访问量太大而导致系统崩溃, 此时开发者会使用限流来进行限制访问量, 当达到限流阀值, 后续请求会被降级; 降级后的处理方案可以是: 排队页面(将用户导流到排队页面等一会重试), 无货(直接告知用户没货了), 错误页(如活动太火爆了, 稍后重试).
如何理解服务熔断和服务降级的差异?
服务熔断的场景是请求次数过多而设计的一种保护策略. 而服务降级是着眼于整个系统的各种问题(超时, 故障等等). 服务熔断会引起服务降级. 换句话说, 熔断是降级的一部分.
@HystrixCommand 注解
默认开启线程池隔离, 服务熔断, 服务降级
接着上次的工程做些修改:[和 feign 结合使用]
https://github.com/HCJ-shadow/Feign
新建工程 msc-consumer-hystrix-80
pom 依赖
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.7.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <properties>
- <java.version>1.8</java.version>
- <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-config</artifactId>
- </dependency>
- <!-- Eureka 客户端启动需要依赖 web 模块 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-Web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</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-netflix-hystrix-dashboard</artifactId>
- </dependency>
- <!-- <dependency>-->
- <!-- <groupId>org.springframework.cloud</groupId>-->
- <!-- <artifactId>spring-cloud-starter-openfeign</artifactId>-->
- <!-- </dependency>-->
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>${spring-cloud.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- controller
- package zkrun.top.controller;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.Web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.RequestMethod;
- import org.springframework.Web.bind.annotation.RestController;
- import zkrun.top.service.Hystrix_FeignService;
- @RestController
- public class Hystrix_FeignController {
- @Autowired
- Hystrix_FeignService hystrix_feignService;
- @RequestMapping(value = "/feign/info/get",method = RequestMethod.GET)
- @HystrixCommand(fallbackMethod = "hystrix_fallback")
- public String request()
- {
- return this.hystrix_feignService.request();
- }
- public String hystrix_fallback()
- {
- return "当前服务故障, 服务熔断已启动!";
- }
- }
application.YAML
- server:
- port: 80
- eureka:
- client:
- service-url:
- defaultZone: http://eureka6001.com:6001/eureka/,http://eureka6002.com:6002/eureka/,http://eureka6003.com:6003/eureka/
- spring:
- application:
- name: hystrix-consumer
主启动类[@EnableCircuitBreaker]
- package zkrun.top;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
- import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
- import org.springframework.cloud.openfeign.EnableFeignClients;
- @SpringBootApplication
- @EnableFeignClients
- @EnableEurekaClient
- @EnableCircuitBreaker
- public class App_Consumer_Hystrix_Feign_80
- {
- public static void main(String[] args)
- {
- SpringApplication.run(App_Consumer_Hystrix_Feign_80.class, args);
- }
- }
运行测试:
启动三个 Eureka,
启动 5001,5002,5003
启动 hystrix80
测试服务熔断
使用 Jmeter
http://jmeter.apache.org/download_jmeter.cgi
解压后双击 bin 下面的 jmeter.bat 即可
设置线程数为 100
设置相关信息
执行测试, 查看结果树
额嗯, 完全抗的住啊!!!
设置线程数为 500:
出现熔断情况.
测试服务降级
设置故障降级, 把 5001 关停
调用降级方法, 重复几次之后, 将不再访问 5001.[Ribbon 的 RetryRule 策略]
假设重启服务,
即可正常访问.
小结:
为了保持高可用, 应用可以配置多份, 这样即使故障一台, 对外仍旧可以保持可用性. 但是随之而来的是数据库的一致性问题. CAP 理论的 A 与 C 只能选择一个也是这个原理. 根据实际的业务情况, 哪些业务是必须保持高可用的, 而哪些是必须保持一致性的, 需要进一步分析和判断.
Hystrix 实现服务的熔断和降级策略的自由度很高, 理解其原理, 搭配 Feign 中集成的 RIbbon 访问算法, 可以实现更高的扩展和组合.
代码参考: https://github.com/HCJ-shadow/Hystrix
来源: https://www.cnblogs.com/noneplus/p/11395789.html