天天看點

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的門檻值,會觸發熔斷,請求直接傳回錯誤資訊,而不會一直等待。

繼續閱讀