在使用springcloud搭建为服务架构项目中,我们会根据业务或功能将系统拆分为多个服务单元,各个单元之间通过服务注册和订阅的方式相互依赖和调用功能,随着项目和业务的不断拓展,服务单元数量增多,相互之间的依赖关系更为复杂,可能会出现当某个服务出现问题或网络原因出现依赖调用出错或延迟,此时如果调用该依赖的请求不断增加,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。为了解决这种单点或多点问题造成的连锁问题,就有了熔断器的出现。
为了展示熔断器功能,在之前使用pringcloud搭建的项目的基础上进行修改
之前搭建的注册中心:http://blog.csdn.net/chenhaotao/article/details/78677328
服务提供者client:http://blog.csdn.net/chenhaotao/article/details/78677858
服务消费者ribbon:http://blog.csdn.net/chenhaotao/article/details/78678445
服务消费者feign:http://blog.csdn.net/chenhaotao/article/details/78688117
主要实在ribbon或feign项目上实现熔断功能。
改造serice-ribbon 工程的代码
1.pox.xml文件中加入hystrix的起步依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
2.在程序启动类application上添加注解@EnableHystrix开启hystrix功能
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
3.在service方法上添加注解@HystrixCommand(fallbackMethod = “method”)指定熔断点并指定熔断方法
@Service
public class TestService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "testError")
public String testService(String name){
return restTemplate.getForObject("http://SERVICE-HELLO/index?name="+name,String.class);
}
public String testError(String name){
return "sorry, "+name+"访问 SERVICE-HELLO服务 出错";
}
}
启动eureka-server注册中心,再启动eureka-client服务提供者,最后启动service-ribbon服务消费者
打开浏览器访问url:http://localhost:9001/test?name=hao 查看服务正常时返回
服务提供者client:hao服务端口:8081
关闭eureka-client,再访问url地址,发现熔断器已生效,返回熔断方法字段
sorry, hao访问 SERVICE-HELLO服务 出错
这就说明当 SERVICE-HELLO 服务不可用的时候,server-ribbon调用 SERVICE-HELLO的API接口时,会执行快速失败,直接返回一组字符串,而不是等待响应超时,这很好的控制了容器的线程阻塞。
feign已经自带断容器不需要再单独引用hystrix依赖,只不过在feign中熔断器功能默认是未打开的,需要在配置文件中开启。
1.在application.yml中开启熔断器
feign:
hystrix:
enabled: true
2.直接在service-feign的TestFeignService接口的@FeignClient注解加上fallback属性并指定其熔断类就行了
@FeignClient(value = "SERVICE-HELLO",fallback = TestFeignServiceFallback.class)
public interface TestFeignService {
/** * @RequestMapping指定调用到服务的那个接口,@RequestParam("name")指定传入的参数名 */
@RequestMapping(value = "index",method = RequestMethod.GET)
String testEurekaClient(@RequestParam("name")String name);
}
3.自定义类TestFeignServiceFallback 实现 TestFeignService 接口并在相应的重写方法中执行熔断业务
@Component
public class TestFeignServiceFallback implements TestFeignService {
@Override
public String testEurekaClient(String name){
return "sorry, "+name+"访问 SERVICE-HELLO服务 出错";
}
}
注:自定义的熔断类还需要加上@Component注解方式注入容器,否则当熔断执行时会出现找不到类的异常。
启动eureka-server注册中心,再启动eureka-client服务提供者,最后启动service-ribbon服务消费者
打开浏览器访问url:http://localhost:9002/testFeign?name=aaa 查看服务正常时返回
服务提供者client:aaa服务端口:8081
关闭eureka-client,再访问url地址,发现熔断器已生效,执行熔断类返回熔断方法字段
sorry, aaa访问 SERVICE-HELLO服务 出错
附上修改后的项目源码:
ribbon实现熔断器:https://pan.baidu.com/s/1bo5UytD
feign实现熔断器: https://pan.baidu.com/s/1hsu5k7y