天天看點

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

一.熔斷器Hystrix

為什麼要用熔斷器

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

在高并發領域,在分布式系統中,可能因為一個小小的功能扛不住壓力,當機了,導緻其他服務也跟随當機,最終導緻整個系統當機,是以在SpringCloud中采用Hystrix進行處理。

1.1.簡介

Hystrix,即熔斷器。

首頁:https://github.com/Netflix/Hystrix/

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

Hystrix是Netflix開源的一個延遲和容錯庫,用于隔離通路遠端服務、第三方庫,防止出現級聯失敗。

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

1.2.熔斷器的工作機制:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

正常工作的情況下,用戶端請求調用服務API接口:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

當有服務出現異常時,直接進行失敗復原,服務降級處理:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

當服務繁忙時,如果服務出現異常,不是粗暴的直接報錯,而是傳回一個友好的提示,雖然拒絕了使用者的通路,但是會傳回一個結果。

這就好比去買魚,平常超市買魚會額外贈送殺魚的服務。等到逢年過節,超市繁忙時,可能就不提供殺魚服務了,這就是服務的降級。

系統特别繁忙時,一些次要服務暫時中斷,優先保證主要服務的暢通,一切資源優先讓給主要服務來使用,在雙十一、618時,京東天貓都會采用這樣的政策。

1.3.動手實踐

1.3.1.引入依賴

首先在user-consumer(服務消費者)中引入Hystix依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
           

1.3.2.開啟熔斷

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

1.3.2.改造消費者

我們改造user-consumer,添加一個用來通路的user服務的DAO,并且聲明一個失敗時的復原處理函數:

@Component
public class UserDao {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "queryUserByIdFallback")
    public User queryUserById(Long id){
        long begin = System.currentTimeMillis();
        String url = "http://user-service/user/" + id;
        User user = this.restTemplate.getForObject(url, User.class);
        long end = System.currentTimeMillis();
        // 記錄通路用時:
        System.out.println("通路用時:{}", end - begin);
        return user;
    }

    public User queryUserByIdFallback(Long id){
        User user = new User();
        user.setId(id);
        user.setName("使用者資訊查詢出現異常!");
        return user;
    }
}
           
  • @HystrixCommand(fallbackMethod="queryUserByIdFallback")

    :聲明一個失敗復原處理函數queryUserByIdFallback,當queryUserById執行逾時(預設是1000毫秒),就會執行fallback函數,傳回錯誤提示。
  • 為了友善檢視熔斷的觸發時機,我們記錄請求通路時間。

在原來的業務邏輯中調用這個DAO:

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        ids.forEach(id -> {
            // 我們測試多次查詢,
            users.add(this.userDao.queryUserById(id));
        });
        return users;
    }
}
           

1.3.3.改造服務提供者

改造服務提供者,随機休眠一段時間,以觸發熔斷:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) throws InterruptedException {
        // 為了示範逾時現象,我們在這裡然線程休眠,時間随機 0~2000毫秒
        Thread.sleep(new Random().nextInt(2000));
        return this.userMapper.selectByPrimaryKey(id);
    }
}

           

1.3.4.啟動測試

然後運作并檢視日志:

id為9、10、11的通路時間分别是:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

id為12的通路時間:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

是以,隻有12是正常通路,其它都會觸發熔斷,我們來檢視結果:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

1.3.5.優化

雖然熔斷實作了,但是我們的重試機制似乎沒有生效,是這樣嗎

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

其實這裡是因為我們的Ribbon逾時時間設定的是1000ms:

[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

而Hystix的逾時時間預設也是1000ms,是以重試機制沒有被觸發,而是先觸發了熔斷。

是以,Ribbon的逾時時間一定要小于Hystix的逾時時間。

我們可以通過

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds

來設定Hystrix逾時時間。

hystrix:
  command:
  	default:
        execution:
          isolation:
            thread:
              timeoutInMilliseconds: 6000 # 設定hystrix的逾時時間為6000ms
           
[親測]SpringCloud之熔斷器Hystrix+實踐一.熔斷器Hystrix

再給大家推薦本人的另外一篇文章

SpringCloud之遠端調用Feign

繼續閱讀