1.理解Hystrix
1.1.雪崩效应
- 在电影里面经常出现的场景,在冰山雪地不要大声呼喊,应该声音的震动会导致小雪球的滑落,随着雪球的滑落可能有连锁反应导致整个雪山的崩塌,这就是生活中的雪崩,在微服务里面也是一样,微服务的调用非常复杂的,一个请求往往需要很多的微服务通过完成,在整个微服务调用链中,如果某个服务发生故障,会导致整个调用链调用异常,甚至可能导致整个微服务瘫痪 , — 这就是雪崩效应。
1.2.Hystrix介绍
- Hystrix是国外知名的视频网站Netflix所开源的非常流行的高可用架构框架。Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题。
- Hystrix的英文是豪猪,中文翻译为 熔断器,其思想来源于我们家里的保险开关,当家里出现短路,保险开关及时切掉电路,保证家里人员的安全,其目的就是起保护作用。
- 简单理解Hystrix可以通过熔断和降级等手段解决雪崩问题,它就是一个微服务保护组件。
1.3.Hystrix的作用
- 资源隔离(限流) :包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
- 熔断 :当请求次数达到规定的阀值都出现服务故障(超时),Hystrix就把服务标记为短路状态.
正常情况下,断路器处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(FailFast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态;
- 降级 :高并发情况下 ,为了保证一些主要的服务有足够的资源不出问题,会认为的关掉一些无关紧要的服务,然后返回一些托底的数据,给用户一个友好的提示。
如在淘宝双十一,淘宝为了让主要的业务有充分的资源,会选择关闭一些不重要的业务,如双十一期间不能退款,不能评价等,当你去退款是会返回暂时不能退款的提示信息给你,这个就是服务的降级机制。
- 缓存 :Hystrix内部会把请求做缓存和请求做合并
2.订单服务集成Hystrix
- 修改 springcloud-order-server-1030 集成Hystrix ,该工程已经集成了Ribbon
2.1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.2.配置类开启Hystrix
- 通过 @EnableCircuitBreaker 标签开启熔断功能
/**
* @EnableEurekaServer:开启eurekaServer服务端
* @EnableCircuitBreaker:开启Hystrix断路器注解
*/
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker //开启Hystrix熔断
public class OrderServerApplicationConfig {
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
//@LoadBalanced :让RestTemplate有负载均衡的功能
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(OrderServerApplicationConfig.class,args);
}
}
2.3.方法熔断
- 通过 @HystrixCommand 标签标记方法熔断,标签的fallbackMethod属性指定拖地方法。
//订单服务
@RestController
public class OrderController {
//需要配置成Bean
@Autowired
private RestTemplate restTemplate;
//负载均衡策略
@Bean
public RandomRule randomRule(){
return new RandomRule();
}
//浏览器调用该方法
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
//方法熔断
@HystrixCommand(fallbackMethod = "fallbackMethod")
public User getUserId(@PathVariable("id")Long id){
//发送http请求调用 user的服务,获取user对象 : RestTemplate
//user的ip,user的端口,user的Controller路径
//String url = "http://localhost:1020/user/"+id; 单个用户服务的时候
String url = "http://user-server/user/" + id;
return restTemplate.getForObject(url,User.class);
}
//断路器熔断后调用的方法
public User fallbackMethod(@PathVariable("id")Long id) {
return new User(-1L,"无用户","没有此用户");
}
}
2.4.托底方法
//断路器熔断后调用的方法
public User fallbackMethod(@PathVariable("id")Long id) {
return new User(-1L,"无用户","没有此用户");
}
2.4.测试熔断
- 浏览器访问 http://localhost:1030/order/1 ,当用户服务 springcloud-user-server-1020 正常启动的时候,订单服务是可以访问,浏览器也可以收到结果 , 当关闭掉用户服务,订单服务会触发熔断,返回拖地数据.
3.支付服务集成Hystrix
- 支付服务 springcloud-pay-server-1040之前集成了Feign,其实Feign已经集成了Hystrix,只是默认是关闭的,我们需要开启Feign的Hystrix支持,并制定拖地。
3.1.开启Hystrix
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 10300
readTimeout: 10300
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10300
3.2.Fiegn接口熔断
@FeignClient(value = "user-server",fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
//订单服务来调用这个方法 http://localhost:1020/user/10
// @GetMapping(value = "/user/{id}" )
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
User getById(@PathVariable("id")Long id);
}
提示: fallback = UserFeignClientFallback.class : 该类是当前接口的实现类 ,也是托底数据所在的处理类
3.3.托底实现
//让Spring扫描到该托底类
@Component
public class FeignClientFallBack implements UserFeignClient {
//日志打印器
Logger logger = LoggerFactory.getLogger(FeignClientFallBack.class);
@Override
public User getUser(Long id) {
logger.info("用户服务错误!!!");
//托底数据
return new User(-1L,"无用户","没有此用户");
}
}
- 提示:注意,这里托底类需要交给Spirng管理,类上需要打 @Component 注解 , 拖地类需要实现 Feign接口,复写其中方法,返回拖地数据。当Fiegn调用失败就会以拖地方法返回的结果返回给用户。
3.4.启动测试
启动支付服务,访问:http://localhost:1040/pay/1 ,测试效果同订单一样。
3.5.Fiegn接口熔断-方式二
1.开启Hystrix
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 10300
readTimeout: 10300
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10300
2.修改Feign接口
使用fallbackFactory属性,使用工厂方式指定托底
@FeignClient(value = "user-server",fallbackFactory = FeignClientFallBackFactory.class)
public interface UserFeignClient {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
User getUser(@PathVariable("id")Long id);
}
3.编写拖底类
//工厂方式的 , 托底类
@Component
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient>{
//拖地方法 : throwable,异常
@Override
public UserFeignClient create(Throwable throwable) {
return new UserFeignClient() {
@Override
public User getById(Long id) {
//把异常信息打印到控制台
throwable.printStackTrace();
//真正拖地方法
return new User(-1L,"无此用户","用户服务不可用");
}
};