一:简介:
spring cloud 用的是 hystrix,是一个容错组件。
Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下几点功能:
- 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
- 防止雪崩。
- 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
- 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
- 资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
- 快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
- 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
- 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
- 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。前面有介绍。
二:hystrix独立使用脱离spring cloud
<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.18</version> </dependency>
测试代码,当出现错误时解决方案,
hystrix简单理解就是对错误以及不符合业务逻辑的项目的一种修复及补丁处理
public class CommonTest extends HystrixCommand<String> { private String name; public CommonTest(String name) { super(HystrixCommandGroupKey.Factory.asKey("myGroup")); this.name=name; } @Override protected String run() throws Exception { Thread.sleep(1000); return Thread.currentThread().getName(); } /* @Override protected String getFallback() { return "超时了,请等等"; }*/ public static void main(String[] args) throws InterruptedException, ExecutionException { CommonTest t= new CommonTest("zhangsan"); Future<String> future=t.queue(); while (!future.isDone()){ Thread.sleep(700); System.out.println(111); } System.out.println(future.get()); //System.out.println(aa1); } }
三:hystrix结合feign实现服务降级
简单介绍服务降级:就是当访问数据时由于数据量过大或者某些原因,不能提供给前端完整的数据,我们可以提供部分数据给到前端,这样既保证了前端的部分显示,又保证了后端服务继续提供
application.properties中添加如下配置,即feign中开启hystrix
feign.hystrix.enabled=true
在api中添加forback配置
@FeignClient(name = "user-provider",fallback = UserProvider.class) public interface UserApi extends UserHandler { @RequestMapping("/getUser") User getUser(); @RequestMapping("/testMap") Map testMap(); @RequestMapping("/putUser") String putUser(User var1); }
这样如果服务不通或者出现其他故障,将进入UserProvider类当中,所以UserProvider应该实现UserApi,因为这样就可以对每个方法进行处理了
@Component public class UserProvider implements UserApi { /**对服务进行降级*/ @Override public User getUser() { User user = new User(); user.setName("服务不正常,返回默认数据"); return user; } @Override public Map testMap() { return null; } @Override public String putUser(User var1) { return null; } }
测试访问接口:正常访问:
当我在服务方设置睡眠之后:
再次访问:
测试完成,再次测试,如果我在服务端设置两个服务器,其中一个睡眠,一个不睡,然后用ribbon做负载均衡,测试如下:
负载均衡
测试结果:当访问到线程等待的服务器时直接返回降级之后的数据,并没有再次请求别的服务器,如果没有配置hystrix时,会访问其他的机器(感觉好像应该先访问别的机器,等所有的机器都访问不了时才触发降级)
写法二,使用fallbackFactory实现
@FeignClient(name = "user-provider",fallbackFactory = UserProvider.class) public interface UserApi extends UserHandler { @RequestMapping("/getUser") User getUser(); @RequestMapping("/testMap") Map testMap(); @RequestMapping("/putUser") String putUser(User var1); }
编写UserProvider
@Component public class UserProvider implements FallbackFactory<UserApi> { @Override public UserApi create(Throwable throwable) { return new UserApi() { @Override public User getUser() { Throwable cause = throwable.getCause(); String message = cause.getMessage(); User user=new User(); user.setName(message); return user; } @Override public Map testMap() { return null; } @Override public String putUser(User var1) { return null; } }; } }
这样写的好处是对不同的错误可以进行不同的处理
四:hystrix结合RestTmplate使用
引入pom
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR3</spring-cloud.version> </properties> <groupId>paic.consumer</groupId> <artifactId>user_consumer</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>paic.common</groupId> <artifactId>user_api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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-openfeign</artifactId> </dependency> <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-hystrix</artifactId> <version>2.2.2.RELEASE</version> </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-netflix-hystrix</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>
在启动类中增加注解,如果不加,则hystrix不再生效:
@EnableCircuitBreaker
使用方式:为了代码的规范性,hystrix最好写在service模块当中
@LoadBalanced @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } @Autowired RestTemplate restTemplate; @GetMapping("/getUser") @HystrixCommand(fallbackMethod = "getUserBackMethod") public User getUser() { ResponseEntity<User> userResponseEntity= restTemplate.getForEntity("http://USER-PROVIDER/getUser",User.class); User body = userResponseEntity.getBody(); return body; } public User getUserBackMethod(){ User user =new User(); user.setName("fullBack"); return user; }
注意的事情:
在使用feign时,不能在类上加其他的路径,比如
feign不支持这样形式的拼接写法,你可以直接写在下面的方法上面