Spring Cloud-Hystrix 斷路器

在Spring Cloud Netflix棧中,每個微服務都以HTTP接口的形式暴露自身服務,因此在調用遠程服務時就必須使用到HTTP客戶端。我們可以使用JDK原生的URLConnection、Apache的Http Client、Netty的異步HTTP Client,還有之前我們使用到Spring的RestTemplate,這些都可以實現遠程調用。

1.Hystrix是什麼

Hystrix(https://github.com/Netflix/Hystrix)是Netflix(https://www.netflix.com/global)的一個開源項目。

在分佈式系統中,總會有一些必不可免發生的問題,比如超時、異常、服務提供者不可用等,如何保證在依賴出問題的情況下,

不會導致整體服務失敗,對延遲和故障提供更強大的容錯能力,這個就是Hystrix需要做的事情。

Hystrix提供了熔斷、隔離、Fallback、cache、監控等功能,能夠在一個、或多個依賴同時出現問題時保證系統依然可用。

2.FallBack機制

有時候我們的提供者會出現故障,導致消費服務的一方也會級聯故障,Hystrix裡面的FallBack就是為了解決這種情況的發生,

當提供者出現問題的時候,消費方可以指定若提供服務發生故障而默認調用的邏輯。

Spring Cloud-Hystrix 斷路器

Spring cloud官方文檔其實介紹的很詳細,這裡給大家一個簡單的例子感受一下FallBack的魅力。

這裡Eureka Server和之前一樣,只修改服務方的代碼

pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

SpringCloud_Demo

com.ithzk.spring.cloud

1.0-SNAPSHOT

4.0.0

consumer-order-hystrix

consumer-order

http://www.example.com

UTF-8

1.7

1.7

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

1.4.3.RELEASE

org.springframework.boot

spring-boot-starter-actuator

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

1.4.3.RELEASE

maven-clean-plugin

3.0.0

maven-resources-plugin

3.0.2

maven-compiler-plugin

3.7.0

maven-surefire-plugin

2.20.1

maven-jar-plugin

3.0.2

maven-install-plugin

2.5.2

maven-deploy-plugin

2.8.2

主程序加上@EnableCircuitBreaker註解表示啟動斷路器

OrderApp.java

package com.ithzk.spring.cloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.context.annotation.Bean;

import org.springframework.web.client.RestTemplate;

/**

* Hello world!

*

*/

@SpringBootApplication

@EnableEurekaClient

@EnableCircuitBreaker//啟用熔斷

public class OrderApp {

//相當於xml中的bean標籤 用於調用當前方法獲取到指定的對象

@Bean

public RestTemplate getRestTemplate(){

return new RestTemplate();

}

public static void main( String[] args )

{

SpringApplication.run(OrderApp.class);

}

}

這裡加上@HystrixCommand(fallbackMethod = "defaultMethod")註解

fallbackMethod屬性標識服務故障默認調用的備用邏輯的方法名

OrderController.java

package com.ithzk.spring.cloud.controller;

import com.ithzk.spring.cloud.entity.User;

import com.netflix.appinfo.InstanceInfo;

import com.netflix.discovery.EurekaClient;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

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

import org.springframework.web.bind.annotation.PathVariable;

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

import org.springframework.web.client.RestTemplate;

/**

* @author hzk

* @date 2018/5/13

*/

@RestController

public class OrderController {

//spring 提供用於訪問rest接口的模板對象

@Autowired

private RestTemplate restTemplate;

@Autowired

private EurekaClient eurekaClient;

@Value("${user.url}")

private String url;

@GetMapping("/order/{id}")

@HystrixCommand(fallbackMethod = "defaultMethod")

public User getOrder(@PathVariable Integer id){

//訪問提供者 獲取數據 通過rest訪問獲取的json數據轉換為的User對象

//PROVIDER-USER 為eureka中提供者註冊服務名稱

InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);

//獲取接口項目地址

String homePageUrl = instanceInfo.getHomePageUrl();

User user = restTemplate.getForObject(homePageUrl + "/user/" +id, User.class);

return user;

}

/**

* 失敗後執行的回調

* @param id

* @return

*/

public User defaultMethod(Integer id){

return new User(id+1000,"faild",88);

}

}

這樣就配置成功,啟動Eureka Server以及消費者,服務者不啟動模擬服務提供失敗,訪問

http://localhost:8900/order/55依然可以看到我們想要的結果,說明HyStrix應用成功

這就是Hystrix中FallBack的簡單應用

3.上下文傳播

Spring Cloud-Hystrix 斷路器

上圖中若getOrder服務提供出現問題,則會調用fallback指定的方法,實質上getOrder和調用fallback指定方法都在自己獨立的線程中,若我們getOrder中有一個ThreadLocal線程內部變量想在defaultMethod中調用的話,需要在@HystrixCommand中加一個屬性commandProperties

package com.ithzk.spring.cloud.controller;

import com.ithzk.spring.cloud.entity.User;

import com.netflix.appinfo.InstanceInfo;

import com.netflix.discovery.EurekaClient;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

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

import org.springframework.web.bind.annotation.PathVariable;

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

import org.springframework.web.client.RestTemplate;

/**

* @author hzk

* @date 2018/5/13

*/

@RestController

public class OrderController {

//spring 提供用於訪問rest接口的模板對象

@Autowired

private RestTemplate restTemplate;

@Autowired

private EurekaClient eurekaClient;

@Value("${user.url}")

private String url;

@GetMapping("/order/{id}")

@HystrixCommand(fallbackMethod = "defaultMethod",commandProperties = {

@HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")

public User getOrder(@PathVariable Integer id){

//訪問提供者 獲取數據 通過rest訪問獲取的json數據轉換為的User對象

//PROVIDER-USER 為eureka中提供者註冊服務名稱

InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);

//獲取接口項目地址

String homePageUrl = instanceInfo.getHomePageUrl();

User user = restTemplate.getForObject(homePageUrl + "/user/" +id, User.class);

return user;

}

/**

* 失敗後執行的回調

* @param id

* @return

*/

public User defaultMethod(Integer id){

return new User(id+1000,"faild",88);

}

}

execution.isolation.strategy 這個默認不建議修改

4.Health健康指標

Hystrix裡面包含一個健康指標的概念,只需要引用一個依賴,就能實時查看到服務的狀態

pom.xml

org.springframework.boot

spring-boot-starter-actuator

加入依賴之後只需訪問http://localhost:8900/hystrix.stream

Spring Cloud-Hystrix 斷路器

這裡面就會實時刷新出服務的狀態,如果提供服務正常,isCircuitBreakerOpen這個值可以看到是false的,

對於斷路器裡面有一個性質,若我們講服務提供關閉,然後去調用消費服務,由上面可以看出若服務異常他會調

用默認FallBack方法,若同一個接口裡服務異常次數過多,重複調用FallBack指定方法,則健康指標會出現以下狀態

Spring Cloud-Hystrix 斷路器

Spring Cloud-Hystrix 斷路器

當健康指標標識為此,則範圍時間內該接口被調用多少次都默認走FallBack方法,

直到多久時間之後有多次正常調通該接口的服務,則該狀態會重置,則恢復開始狀態,服務異常才調FallBack Method

5.Feign Hystrix-fallback支持

@FeignClient啟用回退,只需設置fallback屬性,配置上對應類就可以實現

pom.xml

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

1.4.3.RELEASE

application.yml

server:

port: 8900

spring:

application:

name: consumer-order-feign-hystrix

user:

url: http://localhost:7900/user/

eureka:

client:

service-url:

defaultZone: http://user:user@localhost:8888/eureka/

feign:

hystrix:

enabled: true # feign啟用fallback機制

OrderApp主程序添加@EnableCircuitBreaker註解啟用熔斷

OrderApp.java

package com.ithzk.spring.cloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.cloud.netflix.feign.EnableFeignClients;

import org.springframework.context.annotation.Bean;

import org.springframework.web.client.RestTemplate;

/**

* Hello world!

*

*/

@SpringBootApplication

@EnableFeignClients

@EnableCircuitBreaker

//啟用熔斷,啟用時若接口調用失敗次數過多則會啟用熔斷,有一定保護時間,默認再次請求該接口則直接調用fallback

//若未啟用則每次都會調用接口,直到接口內部每次出錯才會代用fallback

public class OrderApp {

//相當於xml中的bean標籤 用於調用當前方法獲取到指定的對象

@Bean

public RestTemplate getRestTemplate(){

return new RestTemplate();

}

public static void main( String[] args )

{

SpringApplication.run(OrderApp.class);

}

}

這裡自定義Feign客戶端fallback屬性配置實現該客戶端的實現類

CustomFeignClient.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;

import org.springframework.cloud.netflix.feign.FeignClient;

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

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

/**

* @author hzk

* @date 2018/5/20

*/

@FeignClient(name="PROVIDER-USER",fallback = CustomFeignClientHystrix.class)

//配置fallback之後若調用該接口失敗會默認調用配置fallback類中同名的實現方法

public interface CustomFeignClient {

//C版本的 spring 是不能寫 GETMAPPING 的必須用RequestMapping

@GetMapping("/user/{id}")

User getOrder(@PathVariable("id") Integer id);

/**

* 如果傳遞複雜參數,feign默認都會以方式去請求

* 無法訪問,提供者必須為post方式消費者才可使用,如果非要使用get傳遞多個數據,只能以普通方式傳遞

* @param user

* @return

*/

@PostMapping("/get_user")

User getUser(User user);

}

自定義FeignClient實現類,重寫客戶端中接口方法,用於客戶端調用失敗默認調用

CustomFeignClientHystrix.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;

import org.springframework.stereotype.Component;

/**

* @author hzk

* @date 2018/5/28

*/

@Component

public class CustomFeignClientHystrix implements CustomFeignClient{

@Override

public User getOrder(Integer id) {

User user = new User();

user.setId(-1000);

user.setName("我是fallback");

user.setAge(888);

return user;

}

@Override

public User getUser(User user) {

return user;

}

}

OrderController.java

package com.ithzk.spring.cloud.controller;

import com.ithzk.spring.cloud.entity.User;

import com.ithzk.spring.cloud.feign.CustomFeignClient;

import org.springframework.beans.factory.annotation.Autowired;

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

import org.springframework.web.bind.annotation.PathVariable;

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

/**

* @author hzk

* @date 2018/5/13

*/

@RestController

public class OrderController {

@Autowired

private CustomFeignClient customFeignClient;

@GetMapping("/order/{id}")

public User getOrder(@PathVariable Integer id){

User user = customFeignClient.getOrder(id);

return user;

}

@GetMapping("/get_user")

public User getUser(User user){

User feignUser = customFeignClient.getUser(user);

return feignUser;

}

}

此時啟動Eureka Server,啟動消費者Order,不啟動提供者User,訪問http://localhost:8900/order/xx

可以發現仍然成功,返回數據是fallback配置類中重寫方法的數據,則說明FeignClient配置成功

Spring Cloud-Hystrix 斷路器

6.FallBackFactory實現回退

pom.xml 和 application.yml、OrderApp同上一致

編寫一個自定義FallBack工廠,實現FallbackFactory

CustomFeignClientFactory.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;

import feign.hystrix.FallbackFactory;

import org.springframework.cloud.netflix.feign.FeignClient;

import org.springframework.stereotype.Component;

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

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

/**

* @author hzk

* @date 2018/5/20

*/

@Component

public class CustomFeignClientFactory implements FallbackFactory{

@Override

public CustomFeignClient create(Throwable throwable) {

return new CustomFeignClient() {

@Override

public User getOrder(Integer id) {

User user = new User();

user.setId(-1111);

user.setName("我是fallback");

user.setAge(888);

return user;

}

@Override

public User getUser(User user) {

return user;

}

};

}

}

@FeignClient配置fallbackFactory屬性

CustomFeignClient.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;

import org.springframework.cloud.netflix.feign.FeignClient;

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

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

/**

* @author hzk

* @date 2018/5/20

*/

@FeignClient(name="PROVIDER-USER",fallbackFactory = CustomFeignClientFactory.class)

public interface CustomFeignClient {

//C版本的 spring 是不能寫 GETMAPPING 的必須用RequestMapping

@GetMapping("/user/{id}")

User getOrder(@PathVariable("id") Integer id);

/**

* 如果傳遞複雜參數,feign默認都會以方式去請求

* 無法訪問,提供者必須為post方式消費者才可使用,如果非要使用get傳遞多個數據,只能以普通方式傳遞

* @param user

* @return

*/

@PostMapping("/get_user")

User getUser(User user);

}

同上fallback一樣,啟動服務調用消費,出現默認方法,則配置成功

Spring Cloud-Hystrix 斷路器

7.Hystrix-DashBoard儀表板

Hystrix提供了一個儀表板實現,他可以反映每個斷路器的運行狀況

這裡我們新建一個項目hystrix-dashboard

pom.xml

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-hystrix-dashboard

1.4.3.RELEASE

application.yml這裡暫時只需簡單配置服務端口即可

application.yml

server:

port: 9999

主服務添加@EnableHystrixDashboard註解開啟儀表板

DashBoardApp.java

package com.ithzk.spring.cloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

/**

* Hello world!

*

*/

@SpringBootApplication

@EnableHystrixDashboard

public class DashBoardApp

{

public static void main( String[] args )

{

SpringApplication.run(DashBoardApp.class);

}

}

只需簡單幾步即可,啟動服務,訪問localhost:9999/hystrix即可訪問到儀表板首頁

Spring Cloud-Hystrix 斷路器

這裡可以看到需要填寫對應的服務健康指標地址,啟動Eureka server以及上面帶有健康指標和迴路的任一服務

這裡我只啟動了端口8900的消費服務,未啟動對應的提供服務,訪問消費接口出現調用設置的默認方法數據

此時只需將localhost:8900/hystrix.stream填入dashboard首頁中

Spring Cloud-Hystrix 斷路器

擬定一個自定義標題即可進入到斷路器狀態界面,這裡可以很好的看到斷路器的各種狀態

Spring Cloud-Hystrix 斷路器


分享到:


相關文章: