- 推荐序一
- 推荐序二
- 推荐序三
- 推荐语
- 前言
- 第1章 基础知识
- 第2章 微服务构建:Spring Boot
- 第3章 服务治理:Spring Cloud Eureka
- 第4章 客户端负载均衡:Spring Cloud Ribbon
- 第5章 服务容错保护:Spring Cloud Hystrix
- 第6章 声明式服务调用:Spring Cloud Feign
- 第7章 API网关服务:Spring Cloud Zuul
- 第8章 分布式配置中心:Spring Cloud Config
- 第9章 消息总线:Spring Cloud Bus
- 第10章 消息驱动的微服务:Spring Cloud Stream
- 附录 A Starter POMs
- 后记
快速入门
在开始使用Spring Cloud Hystrix实现断路器之前,我们先用之前实现的一些内容作为基础,构建一个如下图架构所示的服务调用关系。
我们在这里需要启动的工程有如下一些。
- eureka-server工程:服务注册中心,端口为1111。
- hello-service工程:HELLO-SERVICE的服务单元,两个实例启动端口分别为8081和8082。
- ribbon-consume工程:使用Ribbon实现的服务消费者,端口为9000。
在未加入断路器之前,关闭8081的实例,发送 GET 请求到http://localhost:9000/ribbon-consumer,可以获得下面的输出:
{
"timestamp": 1473992080343,
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.web.client.ResourceAccessException",
"message": "I/O error on GET request for \"http://HELLO-SERVICE/hello\":Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect",
"path": "/ribbon-consumer"
}
下面我们开始引入Spring Cloud Hystrix。
- 在 ribbon-consumer 工程的 pom.xml 的 dependency 节点中引入 springcloud-starter-hystrix依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
- 在 ribbon-consumer 工程的主类 ConsumerApplication 中使用@EnableCircuitBreaker注解开启断路器功能:
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[]args){
SpringApplication.run(ConsumerApplication.class,args);
}
}
注意:这里还可以使用Spring Cloud应用中的@SpringCloudApplication注解来修饰应用主类,该注解的具体定义如下所示。可以看到,该注解中包含了上述我们所引用的三个注解,这也意味着一个Spring Cloud标准应用应包含服务发现以及断路器。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
- 改造服务消费方式,新增HelloService类,注入RestTemplate实例。然后,将在ConsumerController中对RestTemplate的使用迁移到helloService函数中,最后,在helloService函数上增加@HystrixCommand注解来指定回调方法:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod="helloFallback")
public String helloService(){
return restTemplate.getForEntity("http://HELLO-SERVICE/hello",
String.class).getBody();
}
public String helloFallback(){
return "error";
}
}
- 修改 ConsumerController 类,注入上面实现的 HelloService 实例,并在helloConsumer中进行调用:
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@RequestMapping(value="/ribbon-consumer",method=RequestMethod.GET)
public String helloConsumer(){
return helloService.helloService();
}
}
下面,我们来验证一下通过断路器实现的服务回调逻辑,重新启动之前关闭的8081端口的Hello-Service,确保此时服务注册中心、两个Hello-Service以及RIBBONCONSUMER均已启动,访问http://localhost:9000/ribbon-consumer可以轮询两个HELLO-SERVICE并返回一些文字信息。此时我们继续断开8081的HELLO-SERVICE,然后访问http://localhost:9000/ribbon-consumer,当轮询到8081服务端时,输出内容为error,不再是之前的错误内容,Hystrix的服务回调生效。除了通过断开具体的服务实例来模拟某个节点无法访问的情况之外,我们还可以模拟一下服务阻塞(长时间未响应)的情况。我们对HELLO-SERVICE的/hello接口做一些修改,具体如下:
@RequestMapping(value="/hello",method=RequestMethod.GET)
public String hello()throws Exception {
ServiceInstance instance=client.getLocalServiceInstance();
//让处理线程等待几秒钟
int sleepTime=new Random().nextInt(3000);
logger.info("sleepTime:"+sleepTime);
Thread.sleep(sleepTime);
logger.info("/hello,host:"+instance.getHost()+",service_id:"+instance.getServiceId());
return "Hello World";
}
通过Thread.sleep()函数可让/hello接口的处理线程不是马上返回内容,而是在阻塞几秒之后才返回内容。由于Hystrix默认超时时间为2000毫秒,所以这里采用了0至3000的随机数以让处理过程有一定概率发生超时来触发断路器。为了更精准地观察断路器的触发,在消费者调用函数中做一些时间记录,具体如下:
@HystrixCommand(fallbackMethod="helloFallback",commandKey="helloKey")
public String hello(){
long start=System.currentTimeMillis();
//消费服务的逻辑
...
long end=System.currentTimeMillis();
logger.info("Spend time : "+(end-start));
return result.toString();
}
重新启动 HELLO-SERVICE 和 RIBBON-CONSUMER 的实例,连续访问http://localhost:9000/ribbon-consumer几次,我们可以观察到,当RIBBON-CONSUMER的控制台中输出的Spend time大于2000的时候,就会返回error,即服务消费者因调用的服务超时从而触发熔断请求,并调用回调逻辑返回结果。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论