微服务架构中,微服务之间相互调用,springcloud可以用feign方式和RestTemplate+ribbon方式来实现服务间的相互调用。但如果某一个服务出现问题,所有调用该出问题的服务都将出现阻塞,如果有大量的请求,则Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
为了解决这个问题,业界提出了断路器模型。
1.ribbon中使用断路器hystrix
build.gradle文件
buildscript { ext { springBootVersion = '2.0.4.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'group = 'com.example'version = '0.0.1-SNAPSHOT'sourceCompatibility = 1.8repositories { mavenCentral()}ext { springCloudVersion = 'Finchley.SR1'}dependencies { compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client') compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix') compile('org.springframework.cloud:spring-cloud-starter-netflix-ribbon') testCompile('org.springframework.boot:spring-boot-starter-test')}dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" }}
application.yml文件
server: port: 8797spring: application: name: service-ribbon-hystrixeureka: client: service-url: defaultZone: http://localhost:8791/eureka/
主方法
package com.example.serviceribbonhystrix;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;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@EnableHystrix@EnableEurekaClient@SpringBootApplicationpublic class ServiceRibbonHystrixApplication { public static void main(String[] args) { SpringApplication.run(ServiceRibbonHystrixApplication.class, args); } @Bean RestTemplate restTemplate() { return new RestTemplate(); }}
HelloService.java文件
package com.example.serviceribbonhystrix;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;@Servicepublic class HelloService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "errorMsg") public String hiService() { return restTemplate.getForObject("http://EUREKA-CLIENT-SAY-HI/hi", String.class); } public String errorMsg(){ return "I am ribbon with hystrix,Wrong!"; }}
HelloController.java文件
package com.example.serviceribbonhystrix;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController { @Autowired HelloService helloService; @RequestMapping("/hi") public String sayHi() { return helloService.hiService(); }}
只是单独启动该服务,不启动eureka-client-say-hi服务,访问http://localhost:8797/hi
返回要返回的信息,此时断路器已经生效了:
2.feign中使用断路器hystrix
因为feign是自带断路器的,所以依赖中就不需要加hystrix
build.gradle
buildscript { ext { springBootVersion = '2.0.4.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'group = 'com.example'version = '0.0.1-SNAPSHOT'sourceCompatibility = 1.8repositories { mavenCentral()}ext { springCloudVersion = 'Finchley.SR1'}dependencies { compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client') compile('org.springframework.cloud:spring-cloud-starter-openfeign') testCompile('org.springframework.boot:spring-boot-starter-test')}dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" }}
application.yml文件
server: port: 8796spring: application: name: service-feign-hystrixeureka: client: service-url: defaultZone: http://localhost:8791/eureka/feign: hystrix: enabled: true #feign自带断路器,但需要打开
主方法:
package com.example.servicefeignhystrix;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.cloud.openfeign.EnableFeignClients;@EnableEurekaClient@EnableFeignClients@SpringBootApplicationpublic class ServiceFeignHystrixApplication { public static void main(String[] args) { SpringApplication.run(ServiceFeignHystrixApplication.class, args); }}
接口SayHiService.java文件
package com.example.servicefeignhystrix;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;@FeignClient(value = "eureka-client-say-hi",fallback = SayHiServiceWithHystrix.class)public interface SayHiService { @RequestMapping(value = "/hi", method = RequestMethod.GET) String sayHiFromClient();}
SayHiServiceWithHystrix.java文件
package com.example.servicefeignhystrix;import org.springframework.stereotype.Component;@Componentpublic class SayHiServiceWithHystrix implements SayHiService { @Override public String sayHiFromClient() { return "sorry,I am wrong"; }}
HelloController.java文件
package com.example.servicefeignhystrix;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController { @Autowired SayHiService sayHiService; @RequestMapping("/hi") public String sayHi(){ return sayHiService.sayHiFromClient(); }}
此时启动eureka-server,以及eureka-client-say-hi项目的两个实例,以及刚才新建的项目service-feign-hystrix.
访问http://localhost:8796/hi
出现以下两种场景:
和
如果关掉8792端口的服务,则会返回hi,I am port 8793
如果关掉eureka-client-say-hi服务的8792和8793两个端口实例,则会返回
此时标明,feign的断路器已经生效了。