springCloud(F版)(6)——Hystrix斷路器、HystrixDashboard斷路器監控及Turbine斷路器聚合監控
前面博文我們實現了一個簡單的分散式架構,通過服務叢集實現高可用,通過sleuth實現服務跟蹤。下面通過Hystrix斷路器對服務叢集某介面不可用的情況進行識別和反饋,並進一步優化使用HystrixDashboard對斷路器進行監控、使用Turbine對斷路器監控情況進行聚合分析。
首先,我們將介面服務的消費者進行優化,新增Hystrix斷路器來識別介面不可用情況並給出反饋。前面博文中的系統結構,使用zuul叢集對介面進行消費,使用一個zuul工程實現balance負載均衡,那麼我們首先看看zuul如何實現斷路器功能。然後再依次學習一下Ribbon和Feign如何整合Hystrix斷路器。
一、zuul的FallbackProvider功能
由於springCloud在不斷的更新,因此不同版本的zuul中實現熔斷的interface也在不斷變化,我們前面博文裡搭建的springCloud系統使用的是SpringCloud F版本,Springboot 2.0 版本。經過無數的坑之後,終於找到了zuul在的熔斷方法。。。如果你的工程springCloud版本或springboot版本跟我不一致,下面就當沒看見吧。。。
在之前做好的zuul工程中新增熔斷控制類 client1fallback 實現 FallbackProvider介面,原始碼如下:
package com.testzuul.zuul; import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @Component public class client1fallback implements FallbackProvider { @Override public String getRoute() { return "service-client1"; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { System.out.println("route:"+route); System.out.println("exception:"+cause.getMessage()); return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "ok"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("service-client1 fallback .".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
為了少走彎路,我連import都粘進來了。。。
其他內容全都沒有修改,留意getRoute函式,返回值要跟application name(serviceID)保持一致,用來識別這是哪個微服務的熔斷控制類。當然,這也意味著你有多少微服務,就要建立多少個熔斷控制類了。
編譯執行後,關閉service-client1這個服務叢集中的所有服務,測試一下。
啟動service-client1服務,再試一次。
zuul整合的斷路機制只要是識別微服務是不是還在(剛剛識別的是service-client1這個微服務),而不是具體哪個介面的宕機,下面學習一下在Ribbon中整合Hystrix斷路器來進一步處理介面級別的熔斷機制。
二、Ribbon整合Hystrix斷路器
pom檔案中新增Hystrix起步依賴(spring-cloud-starter-netflix-hystrix)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.testribbon</groupId>
<artifactId>testribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>testribbon</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.springcloud</groupId>
<artifactId>testspringcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
</project>
修改properties配置檔案
eureka.client.serviceUrl.defaultZone=http://10.48.8.231:8761/eureka/
#eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.prefer-ip-address=true
spring.zipkin.base-url=http://10.48.8.231:9411
#spring.zipkin.base-url=http://localhost:9411
#spring.sleuth.sampler.percentage=1.0
spring.sleuth.sampler.probability=1
server.port: 8751
spring.application.name=testRibbon
**application.java入口類添加註解
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix
public class TestribbonApplication {
public static void main(String[] args) {
SpringApplication.run(TestribbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
新增介面呼叫的控制類 clientControler
@RestController
public class clientControler {
@Autowired
clientService client;
@GetMapping(value = "/client1")
public String client1(@RequestParam String name) {
return client.client1Service( name );
}
@GetMapping(value = "/client2")
public String client2(@RequestParam String name) {
return client.client2Service( name );
}
}
建立介面呼叫的service類 clientService
@Service
public class clientService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "client1Error")
public String client1Service(String name) {
return restTemplate.getForObject("http://SERVICE-CLIENT1/hi?name="+name,String.class);
}
public String client1Error(String name) {
return "hi,"+name+",sorry,fallback!";
}
@HystrixCommand(fallbackMethod = "client2Error")
public String client2Service(String name) {
return restTemplate.getForObject("http://SERVICE-CLIENT2/hi?name="+name,String.class);
}
public String client2Error(String name) {
return "hi,"+name+",sorry,fallback!";
}
}
編譯執行後瀏覽器輸入 http://localhost:8751/client1?name=qftest 和 http://localhost:8751/client2?name=qftest
下圖是我開了client2,沒開client1的效果。
三、Feign整合Hystrix斷路器
Feign是自帶hystrix斷路器的,因此pom檔案無需新增新的依賴包。SpringCloud D版本以上斷路器預設是關閉的,因此修改配置檔案,新增feign.hystrix.enabled=true開啟斷路器即可
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ eureka.instance.prefer-ip-address=true spring.zipkin.base-url=http://localhost:9411 #spring.sleuth.sampler.percentage=1.0 spring.sleuth.sampler.probability=1 server.port: 8752 spring.application.name=testFeign #啟動feign自帶的hystrix斷路器 feign.hystrix.enabled=true
**application.java入口類添加註解
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix
控制類testcontroler也沒有變化
@RestController public class testcontroler { @Autowired client1service test1; @Autowired client2service test2; @GetMapping(value = "/client1") public String client1(@RequestParam String name) { return test1.testFunction( name ); } @GetMapping(value = "/client2") public String client2(@RequestParam String name) { return test2.testFunction( name ); } }
client1service介面則不能只宣告個interface函數了,要新增fallback的指定
@FeignClient(value = "service-client1",fallback = Client1serviceimpl.class) public interface client1service { @RequestMapping(value = "/hi",method = RequestMethod.GET) String testFunction(@RequestParam(value = "name") String name); }
其中,FeignClient註解指定了介面對應的微服務service-client1和熔斷處理類client1serviceimpl,介面中的每個函式宣告都對應著一個微服務介面,這一點沒什麼變化。
下面新增client1serviceimpl類實現client1service介面,其實是實現fallback。
@Component public class Client1serviceimpl implements client1service { @Override public String testFunction(String name) { return "hi,"+name+",sorry,fallback!"; } }
當feign程式呼叫介面時,如果介面沒有反饋則會快速執行client1serviceimpl中對應的熔斷處理函式。
編譯執行,效果與Ribbon相同。
四、HystrixDashboard斷路器監控
訪問介面提示報錯資訊,說明我們的Hystrix斷路器已生效,下面我們以zuul工程為例,通過HystrixDashboard對服務的熔斷情況進行檢視監控。
pom檔案新增基礎依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
properties配置檔案中新增必要的配置資訊
#配置 Hystrix Dashboard
management.server.port=9001
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include='*'
入口類添加註解
@EnableHystrix @EnableHystrixDashboard
重新編譯執行zuul程式,瀏覽器呼叫zuul介面(反覆關閉service-client1和service-client2)看到成功呼叫和熔斷資訊後就可以嘗試檢視熔斷情況了。
瀏覽器輸入 http://localhost:8751/hystrix 注意localhost如果不是本地測試的化換成自己的ip、8751是服務的埠號,並不是剛剛配置的management.server.port對應的埠號。如下圖
輸入要要看的檢視的監控資訊 http://localhost:9001/actuator/hystrix.stream 這個時候的埠號才是剛剛配置的9001,讀取的資料地址是management.endpoints.web.base-path配置的actuator,資料流是hystrix.stream。當然這個url也可以直接貼上到瀏覽器上去看具體的資料流內容。如下圖:
至此我們已經可以檢視某個微服務的熔斷資訊了,Ribbon和Feign的改造方式基本相同。但是,這種改造方式只能檢視某個微服務的熔斷情況,當微服務較多時呢?我們希望聚合所有的微服務,將視覺化資訊集中起來檢視,引入下面章節。
五、Turbine斷路器聚合監控
Turbine是一個獨立的server,同樣作為eureka client將自己註冊到註冊中心,通過配置監控的serviceID從註冊中心獲取到各service的ip,然後去拉取hystrix.stream資料流進行統一監控。
我將上面建立的Ribbon和Feign都配置了HystrixDashboard,然後啟動了這兩個負載均衡介面呼叫程式,下面新建立一個springboot工程,配置成TurbineServer實現斷路器的聚合監控。
建立springboot工程命名為turbineserver,修改pom檔案
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.turbine</groupId> <artifactId>turbineserver</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>turbineserver</name> <description>Demo project for Spring Boot</description> <parent> <groupId>com.springcloud</groupId> <artifactId>testspringcloud</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <!-- hystrix起步依賴包 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!-- hystrix dashboard 依賴包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <!-- turbine 依賴包 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-turbine</artifactId> </dependency> </dependencies> </project>
**application.java入口類添加註解
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient @RestController @EnableHystrix @EnableHystrixDashboard @EnableCircuitBreaker @EnableTurbine
修改application.properties配置檔案,新增turbine相關配置
#配置eureka client eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ eureka.instance.prefer-ip-address=true #配置zipkin服務跟蹤 spring.zipkin.base-url=http://localhost:9411 spring.sleuth.sampler.probability=1 #配置自己的埠和serviceID server.port: 9004 spring.application.name=turbine-server #配置 Hystrix Dashboard management.server.port=9003 management.endpoints.web.base-path=/actuator management.endpoints.web.exposure.include="*" management.endpoints.web.cors.allowed-origins="*" management.endpoints.web.cors.allowed-methods="*" #配置 turbine turbine.app-config=testfeign,testribbon turbine.aggregator.cluster-config=default turbine.cluster-name-expression=new String("default") turbine.combine-host-port=true turbine.instanceUrlSuffix.default=actuator/hystrix.stream
OK,編譯執行看下結果
瀏覽器輸入 http://localhost:9004/turbine.stream看一下資料流情況
瀏覽器輸入 http://localhost:9004/hystrix
頁面輸入http://localhost:9004/turbine.stream
收工睡覺。