[TOC]
1、初识Hystrix
Hystrix
是一个延迟和容错库,目的在隔离远程系统、服务、第三方库,组织级联故障,在负载的分布式系统中实现恢复能力。
在多系统和微服务的情况下,需要一种机制来处理延迟和故障,并保护整合系统处于可用的稳定状态。Hystrix
就是实现这个功能的一个组件。
- 通过客户端库对延迟和故障进行保护和控制。
- 在一个复杂的分布式系统中停止级联故障
- 快速失败、迅速恢复
- 在合理的情况下回退、优雅降级
- 开启近实时监控、警告、操作控制
1.2、熔断器的工作机制:
- 在分布式系统中应用者一模式之后,服务调用方可以自己判断某些服务反应慢或者存在大量超时的情况时,能够主动熔断,防止整个系统被拖垮
- 而且Hystrix可以实现弹性容错,当情况好转之后,可以自动重连。
1、正常工作的情况下,客户端请求调用服务API接口
2、当有服务出现异常时,直接进行失败回滚,服务降级处理
3、当服务繁忙时,如果服务出现异常,不直接报错,而是返回一个友好的提示,虽然拒绝了用户的访问,但是会返回一个结果
系统特别繁忙时,一些次要服务暂时中断,优先保证主要服务的畅通,一切资源优先让给主要服务来使用,如:双十一、618时,京东天猫都会采用这样的策略
作用:在服务出现错误的时候,熔断该服务,保护调用者,防止初出现雪崩。
在使用feign熔断器时,feign默认是不开启Hystrix熔断器的,需要手动配置。
1.3、实例
pom
<!--熔断器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
一、@EnableHystrix
:开启Hystrix熔断器
package com.czxy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
/**
* Created by 庭前云落.
*/
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix //开启熔断器
public class Client4Application {
public static void main(String[] args) {
SpringApplication.run(Client4Application.class,args);
}
}
二、dao,远程调用添加熔断器的备选方案,添加注解+备用方法
@HystrixComman
:fallbackMethod指定当该注解标记的方法出现失败、错误时,调用哪一个方法进行优雅的降级返回,对用户屏蔽错误,做优雅提示。
package com.czxy.dao;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* Created by 庭前云落.
*/
[@Component](https://my.oschina.net/u/3907912)
public class DataDao {
[@Resource](https://my.oschina.net/u/929718)
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "dataFallback")
public ResponseEntity<String> data(){
String url = "http://service4/test";
return restTemplate.getForEntity(url,String.class);
}
/**
* 熔断器超时处理方法
* @return
*/
public ResponseEntity<String> dataFallback(){
return ResponseEntity.ok("临时数据");
}
}
三、改变provide(服务提供方)方法,添加线程sleep,0~~2000随机(测试方便)
package com.czxy.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Random;
/**
* Created by 庭前云落.
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public ResponseEntity<String> test(HttpServletRequest request) throws Exception {
//模拟延迟
Thread.sleep(new Random().nextInt(2000));
return ResponseEntity.ok("测试数据" + request.getServerPort());
}
}
四、优化dao,打印耗时时间
package com.czxy.dao;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* Created by 庭前云落.
*/
@Component
public class DataDao {
@Resource
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "dataFallback")
public ResponseEntity<String> data(){
//1 记录开始时间
long start = System.currentTimeMillis();
//2 调用
String url = "http://service4/test";
ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class);
//3 记录结束时间
long end = System.currentTimeMillis();
//4 统计耗时
System.out.println("耗时时间:" + (end - start));
return entity;
}
/**
* 熔断器超时处理方法
* @return
*/
public ResponseEntity<String> dataFallback(){
return ResponseEntity.ok("临时数据");
}
}
1.4、面试题:熔断器+重试机制
- 面试题:如果项目中同时使用熔断器和Ribbon重试机制,谁先执行?
- 如果时间不相同,超时时间小的,先执行
- 如果时间相同,只执行熔断器
- 结论:如果两个都需要配置,
重试机制
的超时时间小于熔断器
2、远程调用
2.1、回顾
- HttpClient:Apache提供技术,更偏向底层,步骤完善,比较繁琐。
- RestTemplate:由Spring提供,操作比较简单
2.2、初识Feign
- Feign用于远程调用
- 特点:声明式、模块化HTTP客户端。使用远程调用,在使用时,感觉向"本地方法"
2.3、Feign入门
- 步骤一:修改pom文件,添加Feign依赖
<!--远程调用Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 步骤二:修改启动类,添加开启Feign注解
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix //开启熔断器
@EnableFeignClients //Feign开启客户端
public class ClientA9Application {
public static void main(String[] args) {
SpringApplication.run(ClientA9Application.class,args);
}
}
- 步骤三:编写Feign接口,完成远程调用,取代dao层
/**
* @author 庭前云落
* @Date 2019/12/11 11:40
* @description
*/
//FeignClient解析
@FeignClient(value = "服务名",path = "controller前缀")
public interface 接口名 {
//与controller方法一致
}
- 步骤四:修改controller,将调用dao修改成feign
/**
* @author 庭前云落
* @Date 2019/12/11 10:01
* @description
*/
@RestController
@RequestMapping("/data")
public class DataController {
@Resource
private DataFeign dataFeign;
@GetMapping
public ResponseEntity<String> data(){
return dataFeign.test();
}
}
2.4 Feign 整合 负载均衡Ribbon
-
Spring Cloud 完成远程调用,并进行负载均衡
- 方式1:使用RestTemplate,并添加额外注解 @LoadBalanced
- 方式2:使用Feign,集成Ribbon,自动负载均衡
-
如果需要单独给服务配置ribbon,可以参考(可选)
#负载均衡器策略配置 service4: ribbon: #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机 #NFLoadBalancerRuleClassName : com.netflix.loadbalancer.BestAvailableRule #并发最少 NFLoadBalancerRuleClassName : com.netflix.loadbalancer.WeightedResponseTimeRule #请求时间权重 ConnectTimeout: 250 # Ribbon的连接超时时间 ReadTimeout: 1000 # Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true # 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数 MaxAutoRetries: 1 # 对当前实例的重试次数
2.5 Feign 整合 熔断器 Hystrix
-
步骤一:修改yml文件,开启feign熔断机制
-
步骤二:创建feign接口实现类,提供备选方案
-
步骤三:feign调用,指定fallback确定备选方案
-
步骤一:修改yml文件,开启feign熔断机制
feign: hystrix: enabled: true #开启feign熔断
-
步骤二:创建feign接口实现类,提供备选方案
package com.czxy.feign; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; /** * Created by liangtong. */ @Component public class DataFeignFallback implements DataFeign { @Override public ResponseEntity<String> test() { return ResponseEntity.ok("feign备选方案"); } }
-
步骤三:feign调用,指定fallback确定备选方案
@FeignClient(value="服务名",path="前缀路径",fallback=备选方案类.class) public interface 接口名 {
package com.czxy.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import javax.servlet.http.HttpServletRequest; /** * Created by liangtong. */ @FeignClient(value="service4",path="/test",fallback=DataFeignFallback.class) public interface DataFeign { @GetMapping public ResponseEntity<String> test() ; }