Spring Cloud Hystrix 容錯保護

JiangYue發表於2018-04-24

在微服務架構中,系統被拆分成很多個服務單元,各個服務單元的應用通過 HTTP 相互呼叫、依賴。

在某個服務由於網路或其他原因自身出現故障、延遲時,呼叫方也會出現延遲。若呼叫方請求不斷增加,可能會形成任務積壓,最終導致呼叫方服務癱瘓,服務不可用現象逐漸放大。

Spring Cloud Hystrix

針對上述問題,Spring Cloud Hystrix 實現了一系列服務保護措施,從而實現服務降級、服務熔斷等功能,對延遲和故障提供強大的容錯能力。

Hystrix 有以下主要特性:

  • 服務熔斷

Hystrix 會記錄各個服務的請求資訊,通過 成功失敗拒絕超時 等統計資訊判斷是否開啟斷路器,將某個服務的請求進行熔斷。一段時間後切換到半開路狀態,如果後面的請求正常則關閉斷路器,否則繼續開啟斷路器。

  • 服務降級

服務降級是請求失敗時的後備方法,故障時執行降級邏輯。

  • 執行緒隔離

Hystrix 通過執行緒池實現資源的隔離,確保對某一服務的呼叫在出現故障時不會對其他服務造成影響。

容錯實踐

首先啟動之前提到的服務註冊中心 eureka-server、服務提供方 hello-service 和服務消費放 ribbon-consumer,然後改造 ribbon-consumer 使其具備容錯能力。

1.新增相關依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
複製程式碼

2.配置 hystrix 超時時間

spring.application.name=ribbon-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

# hystrix command 請求執行超時進入降級邏輯
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
複製程式碼

3.編寫 service 完成服務呼叫

package com.ulyssesss.ribbonconsumer.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.ulyssesss.ribbonconsumer.exception.NotFallbackException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HelloService {

    @Autowired
    RestTemplate restTemplate;

    private static final String HELLO_SERVICE = "http://hello-service/";

    @HystrixCommand(fallbackMethod = "helloFallback", ignoreExceptions = {NotFallbackException.class}
            , groupKey = "hello", commandKey = "str", threadPoolKey = "helloStr")
    public String hello(String p1, String p2) {
        return restTemplate.getForObject(HELLO_SERVICE + "hello", String.class, p1, p2);
    }

    private String helloFallback(String p1, String p2, Throwable e) {
        System.out.println("class: " + e.getClass());
        return "error, " + p1 + ", " + p2;
    }
}
複製程式碼

其中 fallbackMethod 指定處理降級邏輯的方法,ignoreExceptions 指定不執行降級邏輯的異常,groupKey、commandKey 作為命令統計的分組及命令名稱,threadPoolKey 用於指定執行緒池的劃分。

4.Controller 通過 HelloService 完成請求

package com.ulyssesss.ribbonconsumer.web;

import com.ulyssesss.ribbonconsumer.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConsumerController {

    @Autowired
    HelloService helloService;

    @GetMapping("hello")
    public String hello(@RequestParam String p1, @RequestParam String p2) {
        System.out.println("hello");
        return helloService.hello(p1, p2);
    }
}
複製程式碼

5.調整 hello-service 使其便於測試

package com.ulyssesss.helloservice.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

@RestController
public class HelloController {

    @GetMapping("hello")
    public String hello(@RequestParam String p1, @RequestParam String p2) throws Exception {
        int sleepTime = new Random().nextInt(2000);
        System.out.println("hello sleep " + sleepTime);
        Thread.sleep(sleepTime);
        return "hello, " + p1 + ", " + p2;
    }
}
複製程式碼

完成上述步驟後啟動應用,訪問 http://localhost:8080/hello?p1=1&p2=2 ,正常情況下響應為 hello, 1, 2 ,關閉 hello-service 或在 sleepTime 超過 1000ms 時,執行降級邏輯,返回 error, 1, 2

原文地址

示例程式碼 歡迎 Star

相關文章