Spring Cloud Netflix的3大元件應用 Eureka&Ribbon&Hystrix

小飛鶴發表於2017-05-27

參考:http://blog.csdn.net/a60782885/article/details/69267934


服務發現:(Eureka)

前面提到,Eureka分為服務端和客戶端,服務端是服務註冊中心,而客戶端是提供服務的。


建立服務註冊中心(服務端)

首先在pom檔案中加入以下依賴:

[html] view plain copy
  1. <parent>  
  2. <span style="white-space:pre">  </span><groupId>org.springframework.boot</groupId>  
  3. <span style="white-space:pre">  </span><artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.8.RELEASE</version>  
  5.     <relativePath /> <!-- lookup parent from repository -->  
  6. </parent>  
  7.   
  8. <dependencies>  
  9.     <dependency>  
  10.         <groupId>org.springframework.boot</groupId>  
  11.         <artifactId>spring-boot-starter-test</artifactId>  
  12.         <scope>test</scope>  
  13.     </dependency>  
  14. <span style="white-space:pre">  </span><dependency>  
  15.         <groupId>org.springframework.cloud</groupId>  
  16.         <artifactId>spring-cloud-starter-eureka-server</artifactId>  
  17.     </dependency>  
  18. </dependencies>  
  19.   
  20. <dependencyManagement>  
  21.     <dependencies>  
  22.         <dependency>  
  23.             <groupId>org.springframework.cloud</groupId>  
  24.             <artifactId>spring-cloud-dependencies</artifactId>  
  25.             <version>Brixton.SR7</version>  
  26.             <type>pom</type>  
  27.             <scope>import</scope>  
  28.         </dependency>  
  29.     </dependencies>  
  30. </dependencyManagement>  
在Application檔案中增加@EnableEurekaServer註解,表明這是服務端

[java] view plain copy
  1. @EnableEurekaServer  
  2. @SpringBootApplication  
  3. public class SpringcloudEurekaServerApplication {  
  4.   
  5.     public static void main(String[] args) {  
  6.         SpringApplication.run(SpringcloudEurekaServerApplication.class, args);  
  7.     }  
  8. }  
在預設設定下,該服務註冊中心也會將自己作為客戶端來嘗試註冊它自己,所以我們需要禁用它的客戶端註冊行為。在application.properties或yml中禁止客戶端註冊行為,否則會報錯。

[html] view plain copy
  1. server.port=1111  
  2.   
  3. eureka.client.register-with-eureka=false  
  4. eureka.client.fetch-registry=false  
  5. eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/  

服務端就寫好了,可以訪問localhost:1111進行訪問。可以看到,這時候是沒有服務的。



接下來建立客戶端

建立客戶端,並在註冊中心中註冊自己。

還是首先新增依賴:這裡和上面不同的地方只有對Eureka的依賴。

[html] view plain copy
  1. <parent>  
  2.     <groupId>org.springframework.boot</groupId>  
  3.     <artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.8.RELEASE</version>  
  5.     <relativePath /> <!-- lookup parent from repository -->  
  6. </parent>  
  7.   
  8.   
  9. <dependencies>  
  10.     <dependency>  
  11.         <groupId>org.springframework.cloud</groupId>  
  12.         <artifactId>spring-cloud-starter-eureka</artifactId>  
  13.     </dependency>  
  14. <span style="white-space:pre">  </span><dependency>  
  15.         <groupId>org.springframework.boot</groupId>  
  16.         <artifactId>spring-boot-starter-test</artifactId>  
  17.         <scope>test</scope>  
  18.     </dependency>  
  19. </dependencies>  
  20.   
  21. <dependencyManagement>  
  22.     <dependencies>  
  23.         <dependency>  
  24.             <groupId>org.springframework.cloud</groupId>  
  25.             <artifactId>spring-cloud-dependencies</artifactId>  
  26.             <version>Brixton.SR7</version>  
  27.             <type>pom</type>  
  28.             <scope>import</scope>  
  29.         </dependency>  
  30.     </dependencies>  
  31. </dependencyManagement>  
在Application檔案中加入@EnableDiscoveryClient註解,表明這是一個客戶端。

[java] view plain copy
  1. @EnableDiscoveryClient  
  2. @SpringBootApplication  
  3. public class SpringcloudEurekaServiceApplication {  
  4.   
  5.     public static void main(String[] args) {  
  6.         SpringApplication.run(SpringcloudEurekaServiceApplication.class, args);  
  7.     }  
  8. }  
然後我們需要向註冊中心中註冊自己,只需要在application.properties或yml檔案中增加配置即可:

[html] view plain copy
  1. spring.application.name=compute-service  
  2. server.port=2222  
  3. eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/  
defaultZone指定了服務註冊中心的位置。

註冊了之後我們就可以在客戶端編寫客戶端提供的服務了。比如這裡提供了add加法服務。

[java] view plain copy
  1. @RestController  
  2. public class ComputeController {  
  3.       
  4.     private final Logger logger = Logger.getLogger(getClass());  
  5.       
  6.     @Autowired  
  7.     private DiscoveryClient client;  
  8.       
  9.     @RequestMapping(value = "/add" ,method = RequestMethod.GET)  
  10.     public Integer add(@RequestParam Integer a, @RequestParam Integer b) {  
  11.         ServiceInstance instance = client.getLocalServiceInstance();  
  12.         Integer r = a + b;  
  13.         logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);  
  14.         return r;  
  15.     }  
  16. }  
在提供的服務中,只需要使用DiscoveryClient就可以得到關於呼叫者的資訊。

客戶端也完成了,這個時候可以再次訪問localhost:1111。


可以發現,客戶端已經在服務端上註冊了。


我們看一下架構圖:


很顯然,工作流程是這樣的:Service Consumer -> Proxy Server -> Client(Load Balancer) -> Servie Discovery -> Target Service

我們編寫好了上圖的紅色的部分,接下來應該對服務進行負載均衡了,也就是對客戶端的負載均衡,我們使用Ribbon來完成這件事。

首先我們啟動服務端和兩個客戶端,客戶端分別開在2222和2223埠。即:


開啟了兩個服務,接下來我們使用Ribbon進行負載均衡。


新建一個專案。

在pom檔案中新增如下依賴:

[html] view plain copy
  1. <parent>  
  2.     <groupId>org.springframework.boot</groupId>  
  3.     <artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.5.RELEASE</version>  
  5.     <relativePath/> <!-- lookup parent from repository -->  
  6. </parent>  
  7. <dependencies>  
  8.     <dependency>  
  9.         <groupId>org.springframework.cloud</groupId>  
  10.         <artifactId>spring-cloud-starter-ribbon</artifactId>  
  11.     </dependency>  
  12.     <dependency>  
  13.         <groupId>org.springframework.cloud</groupId>  
  14.         <artifactId>spring-cloud-starter-eureka</artifactId>  
  15.     </dependency>  
  16.     <dependency>  
  17.         <groupId>org.springframework.boot</groupId>  
  18.         <artifactId>spring-boot-starter-web</artifactId>  
  19.     </dependency>  
  20.     <dependency>  
  21.         <groupId>org.springframework.boot</groupId>  
  22.         <artifactId>spring-boot-starter-test</artifactId>  
  23.         <scope>test</scope>  
  24.     </dependency>  
  25. </dependencies>  
  26. <dependencyManagement>  
  27.     <dependencies>  
  28.         <dependency>  
  29.         <groupId>org.springframework.cloud</groupId>  
  30.         <artifactId>spring-cloud-dependencies</artifactId>  
  31.         <version>Brixton.RELEASE</version>  
  32.         <type>pom</type>  
  33.         <scope>import</scope>  
  34.     </dependency>  
  35.     </dependencies>  
  36. </dependencyManagement>  
使用@EnableDiscoveryClient註解在將其註冊在註冊中心。並且提供一個返回RestTemplate的bean例項,使用@LoadBalanced註解對這個例項進行負載均衡這樣,使用這個例項去獲取服務的時候,就會幫我們進行負載均衡了。
[java] view plain copy
  1. @SpringBootApplication  
  2. @EnableDiscoveryClient  
  3. public class RibbonApplication {  
  4.       
  5.     @Bean  
  6.     @LoadBalanced  
  7.     RestTemplate restTemplate() {  
  8.         return new RestTemplate();  
  9.     }  
  10.       
  11.     public static void main(String[] args) {  
  12.         SpringApplication.run(RibbonApplication.class, args);  
  13.     }  
  14. }  

在application.properties中註冊:

[html] view plain copy
  1. spring.application.name=ribbon-consumer  
  2. server.port=3333  
  3. eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/  

建立了bean例項,我們就可以通過@Autowired來獲取這個RestTemplate了,並且使用這個例項去呼叫服務。
[java] view plain copy
  1. @RestController  
  2. public class ConsumerController {  
  3.       
  4.     @Autowired  
  5.     RestTemplate restTemplate;  
  6.       
  7.     @RequestMapping(value = "/add", method = RequestMethod.GET)  
  8.     public String add() {  
  9.         return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();  
  10.     }  
  11. }  
啟動這個專案,並且訪問多次localhost:3333/add可以發現確實進行了負載均衡。


微服務架構中,服務被拆分成一個一個的單元,各個單元之間相互依賴呼叫。如果某個單元由於網路原因或者別的單元故障奔潰,那麼會直接導致呼叫方對外的服務也發生延遲。若此時呼叫方的請求不斷增加,最後就會出現因等待出現故障的依賴方響應而形成任務積壓,最終導致自身服務的癱瘓,這樣的結構相對於傳統的web開發模式來說更加可怕,為了解決這個問題,我們可以採用斷路器。

在分散式架構中,當某個服務單元發生故障,使用斷路器返回一個錯誤的相應,而不是進行長時間的等待,這樣就不會使得執行緒被長時間佔用,導致伺服器的癱瘓。

Spring Cloud提供了Hystrix這麼一個元件來實現斷路器的功能。


首先啟動Eureka服務端和客戶端。

對Ribbon的專案進行以下修改:

首先在pom檔案中增加以下依賴:

[html] view plain copy
  1. <dependency>  
  2.     <groupId>org.springframework.cloud</groupId>  
  3.     <artifactId>spring-cloud-starter-hystrix</artifactId>  
  4. </dependency>  
在application中增加@EnableCircuitBreaker註解,表明使用斷路器。

[java] view plain copy
  1. @SpringBootApplication  
  2. @EnableDiscoveryClient  
  3. @EnableCircuitBreaker  
  4. public class RibbonApplication {  
  5.       
  6.     @Bean  
  7.     @LoadBalanced  
  8.     RestTemplate restTemplate() {  
  9.         return new RestTemplate();  
  10.     }  
  11.       
  12.     public static void main(String[] args) {  
  13.         SpringApplication.run(RibbonApplication.class, args);  
  14.     }  
  15. }  
Hystrix使用訊息佇列的方式,如果連線的服務崩潰,則非同步回撥某個方法進行處理。

新增一個Service類,在這個類中定義好如何訪問,以及失敗之後的返回等。

[java] view plain copy
  1. @Service  
  2. public class ComputeService {  
  3.       
  4.     @Autowired  
  5.     RestTemplate restTemplate;  
  6.       
  7.     @HystrixCommand(fallbackMethod = "addServiceFallback")  
  8.     public String addService() {  
  9.         return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();  
  10.     }  
  11.       
  12.     public String addServiceFallback() {  
  13.         return "error";  
  14.     }  
  15. }  
這裡重點是@HystrixCommand註解:表明該方法為hystrix包裹,可以對依賴服務進行隔離、降級、快速失敗、快速重試等等hystrix相關功能

列舉幾個屬性:
1. fallbackMethod 降級方法
2. commandProperties 普通配置屬性,可以配置HystrixCommand對應屬性,例如採用執行緒池還是訊號量隔離、熔斷器熔斷規則等等
3. ignoreExceptions 忽略的異常,預設HystrixBadRequestException不計入失敗
4. groupKey() 組名稱,預設使用類名稱
5. commandKey 命令名稱,預設使用方法名

最後修改一下Controller即可:

[java] view plain copy
  1. @RestController  
  2. public class ConsumerController {  
  3.       
  4.     @Autowired  
  5.     private ComputeService computeService;  
  6.       
  7.     @RequestMapping(value = "/add", method = RequestMethod.GET)  
  8.     public String add() {  
  9.         return computeService.addService();  
  10.     }  
  11. }  
對於斷路器,針對生產環境,,Netflix還給我們準備了一個非常好用的運維工具, 那就是Hystrix Dashboard和Turbine.可以幫助我們更好的觀察。


當客戶端關閉時訪問:


客戶端啟動時訪問:


成功!


相關文章