天天看点

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix

服务容错保护:Spring Cloud Hystrix

    • 一、服务容错
    • 二、简单使用Hystrix
          • 1. 启动微服务
          • 2. 不使用Hystrix
          • 3. 给活动管理服务引入Hystrix
            • (1) 配置依赖
            • (2) @EnableCircuitBreaker开启断路器功能
            • (3) 新增一个使用断路器的活动申请接口
          • 4. 当服务正常时,调用配置了Hystrix的活动申请接口
          • 5. 当邮件服务故障时,调用配置了Hystrix的活动申请接口
          • 6. 模拟邮件服务延时,调用配置了Hystrix的活动申请接口
            • (1) 修改邮件发送接口,模拟延时
            • (2) 修改活动申请接口,打印时间
            • (3) 多次访问使用了Hystrix的活动申请接口
          • 7. 以上

一、服务容错

  • 在微服务架构中,我们将系统拆分成了很多服务,各个服务间通过服务注册与服务发现的方式互相依赖。各个服务之间通过远程调用的方式执行,这样就可能因为网络原因或服务自身原因导致服务调用的故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因为被调用服务延迟相应而形成任务挤压,最终导致自身服务瘫痪。
  • 例子:在电商网站中,一般有订单服务、库存服务等,当用于从页面下单时,订单服务创建订单后,会向库存服务请求库存减一。此时若库存服务因自身问题响应很慢,会导致刚才创建订单的这个请求被挂起,一直等待库存服务响应,直到请求超时返回请求超时信息。在高并发情况下,订单服务能够处理的线程数一定,如果所有的请求线程都在等到库存服务的响应,就会直接导致订单服务后面来的请求被阻塞,最终导致订单服务也不可用。当前以上只是举个栗子,真实的电商网站库存应该是存储在Redis缓存中能够快速响应的。
  • 断路器服务保护机制:当某个服务发生故障或延迟之后,通过断路器的故障监控,向调用方返回一个错误响应,而不是一直让调用方的请求一直等待。
  • Spring Cloud Hystrix:实现了断路器、线程隔离等一系列服务保护功能。它是基于Netflix的开源框架Hystrix实现的。Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。

二、简单使用Hystrix

1. 启动微服务

先把之前的注册中心集群、活动管理服务、邮件服务都启动。

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix

之前活动管理服务的申请活动功能,调用申请活动接口,活动管理服务会去调用邮件服务。

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
2. 不使用Hystrix

现在不使用Hystrix,停止邮件服务模拟邮件服务故障,再调用申请活动接口,会返回:

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
3. 给活动管理服务引入Hystrix

(1) 配置依赖

<!--Hystrix依赖-->
 <dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
           

(2) @EnableCircuitBreaker开启断路器功能

@EnableEurekaClient // 启用Eureka客户端
@EnableCircuitBreaker // 启用断路器功能
@SpringBootApplication
public class ActivimanageApplication {
    // 创建RestTemplate的Spring Bean实例,添加@LoadBalanced开启客户端负载均衡
    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ActivimanageApplication.class, args);
    }
}
           

(3) 新增一个使用断路器的活动申请接口

  • Controller
@RestController
@RequestMapping("/api/activity")
public class ActivityApplyController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ActivityApplyService service;

    /**
     * applySimpleActivity : 申请活动
     *
     * @author zhaoxudong
     * @date 2019/11/21 18:02
     */
    @GetMapping(value = "/simple/apply")
    public void applySimpleActivity(){
        // 申请活动逻辑...

        // 调用【邮件服务】发送活动申请成功邮件
        String emailServiceRs = restTemplate.getForEntity("http://SCLOUD-EMAIL-SERVICE/api/email/simple/[email protected]&subject=活动申请&content=申请活动成功,此邮件为活动管理服务调用邮件服务发送!",
                                                            String.class).getBody();

        System.out.println("| -------------------------------");
        System.out.println("| 活动管理服务(SCLOUD-ACTIVIMANAGE-SERVICE):");
        System.out.println("|   活动申请成功... ");
        System.out.println("|   邮件服务返回: " + emailServiceRs);
        System.out.println("| -------------------------------");
    }

    /**
     * applySimpleActivityHystrix : 使用了Hystrix的申请活动接口
     *
     * @author zhaoxudong
     * @date 2019/12/2 20:24
     */
    @GetMapping(value = "/simple/apply/hystrix")
    public String applySimpleActivityHystrix(){
        return service.applySimpleActivityHystrix();
    }
}
           
  • Service
@Service
public class ActivityApplyService {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "applySimpleActivityError") //指定回调方法
    public String applySimpleActivityHystrix(){
        // 申请活动逻辑...

        // 调用【邮件服务】发送活动申请成功邮件
        String emailServiceRs = restTemplate.getForEntity("http://SCLOUD-EMAIL-SERVICE/api/email/simple/[email protected]&subject=活动申请&content=申请活动成功,此邮件为活动管理服务调用邮件服务发送!",
                String.class).getBody();

        System.out.println("| -------------------------------");
        System.out.println("| 活动管理服务(SCLOUD-ACTIVIMANAGE-SERVICE):");
        System.out.println("|   活动申请成功... ");
        System.out.println("|   邮件服务返回: " + emailServiceRs);
        System.out.println("| -------------------------------");

        return "活动申请成功,邮件已发送!";
    }

    public String applySimpleActivityError(){
        return "邮件服务故障,活动申请失败!";
    }
}
           
4. 当服务正常时,调用配置了Hystrix的活动申请接口

能够正常调用:

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
5. 当邮件服务故障时,调用配置了Hystrix的活动申请接口

停止邮件服务后,调用活动申请接口:

SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
6. 模拟邮件服务延时,调用配置了Hystrix的活动申请接口

(1) 修改邮件发送接口,模拟延时

在收到请求后,会阻塞0-3000ms中的随机值。

@RestController
@RequestMapping("/api/email")
public class EmailSendController {

    /**
     * sendSimpleEmail : 发送一封简单的邮件
     *
     * @author zhaoxudong
     * @date 2019/11/21 15:34
     */
    @GetMapping(value = "/simple/send")
    public String sendSimpleEmail(@RequestParam("to")String to, @RequestParam("subject") String subject, @RequestParam("content") String content) throws InterruptedException {
        // 邮件发送逻辑....

        // 生成0-3000随机数
        int sleepTime= new Random().nextInt(3000);
        Thread.sleep(sleepTime);

        System.out.println("| ------------------------------------------");
        System.out.println("| 邮件服务(SCLOUD-EMAIL-SERVER):");
        System.out.println("|   简单邮件发送接口(/api/email/simple/send):");
        System.out.println("|       to(收件人)    : " + to);
        System.out.println("|       subject(主题) : " + subject);
        System.out.println("|       content(内容) : " + content);
        System.out.println("|   ..... 邮件发送成功,耗时:"+ sleepTime +"ms .....");
        System.out.println("| ------------------------------------------");

        return "send ok";
    }
}
           

(2) 修改活动申请接口,打印时间

  • Controller
@RestController
@RequestMapping("/api/activity")
public class ActivityApplyController {

    @Autowired
    private ActivityApplyService service;

    public final static SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    @GetMapping(value = "/simple/apply/hystrix")
    public String applySimpleActivityHystrix(){
        System.out.println(dateFormat.format(new Date()) + "----- Hystrix 活动申请接口-收到请求");
        return service.applySimpleActivityHystrix();
    }
}
           
  • Service
@Service
public class ActivityApplyService {

    @Autowired
    private RestTemplate restTemplate;

    public final static SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    @HystrixCommand(fallbackMethod = "applySimpleActivityError")
    public String applySimpleActivityHystrix(){
        ***

        System.out.println(dateFormat.format(new Date()) + "----- Hystrix 活动申请接口-处理结束");
        return "活动申请成功,邮件已发送!";
    }

    public String applySimpleActivityError(){
        System.out.println(dateFormat.format(new Date()) + "----- Hystrix 活动申请接口-邮件服务故障,触发熔断");
        return "邮件服务故障,活动申请失败!";
    }
}
           

(3) 多次访问使用了Hystrix的活动申请接口

  • 邮件服务1s内处理完,正常调用。
    SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
  • 邮件服务1s以上处理完,则会触发熔断,直接返回错误信息。

    注意这里Hystrix只等待了1s,邮件服务还不响应,就直接返回了服务故障,即邮件服务延迟触发熔断。

    SpringCloud架构:6-服务容错保护:Spring Cloud Hystrix
7. 以上

由此可以看出:

  • 当不配置Hystrix时,邮件服务延迟时,申请活动的请求会一直等待邮件服务响应,最终导致过多申请活动的请求都在挂起等待。
  • 当配置了Hystrix是,邮件服务延迟的时间一旦超过了Hystrix默认的1s的阈值,会触发熔断,请求直接返回错误信息,而不会一直等待。

继续阅读