基於SpringCloud的服務註冊和呼叫
一:服務的註冊和發現
Eureka是Netflix開源的一款提供服務註冊和發現的產品,它提供了完整的Service Registry(註冊登記)和Service Discovery(發現)實現。也是springcloud體系中最重要最核心的元件之一。
服務中心:
服務中心又稱註冊中心,管理各種服務功能包括服務的註冊、發現、熔斷、負載、降級等。
有了服務中心呼叫關係會有什麼變化,畫幾個簡圖來幫忙理解
例如:專案A呼叫專案B
正常呼叫專案A請求專案B
有了服務中心之後,任何一個服務都不能直接去掉用,都需要通過服務中心來呼叫
專案A呼叫專案B,專案B在呼叫專案C
這時候呼叫的步驟就會為兩步:第一步,專案A首先從服務中心請求專案B伺服器,然後專案B在從服務中心請求專案C服務。
上面的例子只是兩三個專案之間相互簡單的呼叫,但是如果專案超過20個30個呢,畫一張圖來描述幾十個專案之間的相互呼叫關係全是線條,任何其中的一個專案改動,就會牽連好幾個專案跟著重啟,巨麻煩而且容易出錯。通過服務中心來獲取服務你不需要關注你呼叫的專案IP地址,由幾臺伺服器組成,每次直接去服務中心獲取可以使用的服務去呼叫既可。
由於各種服務都註冊到了服務中心,就有了去做很多高階功能條件。比如幾臺服務提供相同服務來做均衡負載;監控伺服器呼叫成功率來做熔斷,移除服務列表中的故障點;監控服務呼叫時間來對不同的伺服器設定不同的權重等等。
Eureka由兩個元件組成:Eureka伺服器和Eureka客戶端。Eureka伺服器用作服務註冊伺服器。Eureka客戶端是一個java客戶端,用來簡化與伺服器的互動、作為輪詢負載均衡器,並提供服務的故障切換支援。Netflix在其生產環境中使用的是另外的客戶端,它提供基於流量、資源利用率以及出錯狀態的加權負載均衡。
上圖簡要描述了Eureka的基本架構,由3個角色組成:
1、Eureka Server
- 提供服務註冊和發現
2、Service Provider
- 服務提供方
- 將自身服務註冊到Eureka,從而使服務消費方能夠找到
3、Service Consumer
- 服務消費方
- 從Eureka獲取註冊服務列表,從而能夠消費服務
二:建立註冊中心 Eureka Server
建立一個簡單的maven springboot專案
pom裡面新增如下依賴:
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 8 <dependencies> 9 <dependency> 10 <groupId>org.springframework.boot</groupId> 11 <artifactId>spring-boot-starter-test</artifactId> 12 <scope>test</scope> 13 </dependency> 14 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-eureka-server</artifactId> 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.RELEASE</version> 27 <type>pom</type> 28 <scope>import</scope> 29 </dependency> 30 </dependencies> 31 </dependencyManagement>
通過@EnableEurekaServer
註解啟動一個服務註冊中心提供給其他應用進行呼叫。這一步非常的簡單,只需要在一個普通的Spring Boot應用中新增這個註解就能開啟此功能,比如下面的例子:
1 package com; 2 3 import org.springframework.boot.autoconfigure.SpringBootApplication; 4 import org.springframework.boot.builder.SpringApplicationBuilder; 5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 7 @EnableEurekaServer//服務註冊中心開啟註解 8 @SpringBootApplication 9 public class Application { 10 11 public static void main(String[] args) { 12 new SpringApplicationBuilder(Application.class).web(true).run(args); 13 } 14 15 }
在預設設定下,該服務註冊中心也會將自己作為客戶端來嘗試註冊它自己,所以我們需要禁用它的客戶端註冊行為,只需要在application.properties
中問增加如下配置:
1 #啟動埠 2 server.port=1111 3 4 #關閉掉自己往服務中心註冊的機制 5 eureka.client.register-with-eureka=false 6 #是否檢索服務 7 eureka.client.fetch-registry=false 8 #服務中心地址 9 eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
專案結構:
啟動專案訪問 http://localhost:1111/
介面如下
三:建立服務提供者
下面我們建立提供服務的客戶端,並向服務註冊中心註冊自己。
假設我們有一個提供計算功能的微服務模組,我們實現一個RESTful API,通過傳入兩個引數a和b,最後返回a + b的結果。
首先,建立一個基本的Spring Boot應用,在pom.xml
中,加入如下配置:
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 8 <dependencies> 9 <dependency> 10 <groupId>org.springframework.boot</groupId> 11 <artifactId>spring-boot-starter-test</artifactId> 12 <scope>test</scope> 13 </dependency> 14 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-eureka</artifactId> 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.RELEASE</version> 27 <type>pom</type> 28 <scope>import</scope> 29 </dependency> 30 </dependencies> 31 </dependencyManagement>
建立我們的業務訪問控制器
1 package com; 2 3 import org.apache.log4j.Logger; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.cloud.client.ServiceInstance; 6 import org.springframework.cloud.client.discovery.DiscoveryClient; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.RequestMethod; 9 import org.springframework.web.bind.annotation.RequestParam; 10 import org.springframework.web.bind.annotation.RestController; 11 12 @RestController 13 public class ComputeController { 14 15 private final Logger logger = Logger.getLogger(getClass()); 16 17 @Autowired 18 private DiscoveryClient client; 19 20 @RequestMapping(value = "/add" ,method = RequestMethod.GET) 21 public Integer add(@RequestParam Integer a, @RequestParam Integer b) { 22 ServiceInstance instance = client.getLocalServiceInstance(); 23 Integer r = a + b; 24 logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r); 25 return r; 26 } 27 28 }
建立啟動器
EnableDiscoveryClient
註解,該註解能啟用Eureka中的DiscoveryClient
實現,才能實現Controller中對服務資訊的輸出。
package com; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient//標識客戶端,並掃描控制器裡面的DiscoveryClient @SpringBootApplication public class ComputeServiceApplication { public static void main(String[] args) { new SpringApplicationBuilder(ComputeServiceApplication.class).web(true).run(args); } }
application.properties
1 #指定微服務的名稱後續在呼叫的時候只需要使用該名稱就可以進行服務的訪問。 2 spring.application.name=compute-service 3 server.port=2222 4 #屬性對應服務註冊中心的配置內容,指定服務註冊中心的位置。 5 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
啟動本專案,然後再訪問http://localhost:1111/ 就可以看到服務已經註冊到服務中心
四:建立服務的消費者
使用ribbon實現負載均衡的消費者,構建一個基本Spring Boot專案,並在pom.xml中加入如下內容:
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 8 <dependencies> 9 <dependency> 10 <groupId>org.springframework.cloud</groupId> 11 <artifactId>spring-cloud-starter-ribbon</artifactId> 12 </dependency> 13 <dependency> 14 <groupId>org.springframework.cloud</groupId> 15 <artifactId>spring-cloud-starter-eureka</artifactId> 16 </dependency> 17 <dependency> 18 <groupId>org.springframework.boot</groupId> 19 <artifactId>spring-boot-starter-web</artifactId> 20 </dependency> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-test</artifactId> 24 <scope>test</scope> 25 </dependency> 26 </dependencies> 27 28 <dependencyManagement> 29 <dependencies> 30 <dependency> 31 <groupId>org.springframework.cloud</groupId> 32 <artifactId>spring-cloud-dependencies</artifactId> 33 <version>Brixton.RELEASE</version> 34 <type>pom</type> 35 <scope>import</scope> 36 </dependency> 37 </dependencies> 38 </dependencyManagement>
通過@LoadBalanced註解實現負載均衡的開啟
1 package com; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 import org.springframework.cloud.client.loadbalancer.LoadBalanced; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.web.client.RestTemplate; 9 10 @SpringBootApplication 11 @EnableDiscoveryClient 12 public class RibbonApplication { 13 14 @Bean 15 @LoadBalanced//負載均衡的開啟 16 RestTemplate restTemplate() { 17 return new RestTemplate(); 18 } 19 20 public static void main(String[] args) { 21 SpringApplication.run(RibbonApplication.class, args); 22 } 23 24 }
建立ConsumerController
來消費COMPUTE-SERVICE
的add服務。通過直接RestTemplate來呼叫服務,計算10 + 20的值。
1 package com; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.RequestMethod; 6 import org.springframework.web.bind.annotation.RestController; 7 import org.springframework.web.client.RestTemplate; 8 9 @RestController 10 public class ConsumerController { 11 12 @Autowired 13 RestTemplate restTemplate; 14 15 @RequestMapping(value = "/add", method = RequestMethod.GET) 16 public String add() { 17 return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody(); 18 } 19 // 20 }
application.properties
中配置eureka服務註冊中心
1 spring.application.name=ribbon-consumer 2 server.port=3333 3 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
這個時候修改服務提供方把埠改為2223,再啟動一個服務提供
可一看到服務中心已經被註冊了兩個服務。
啟動服務消費方,並訪問五次:http://localhost:3333/add
然後,開啟compute-service的兩個服務提供方,分別輸出了類似下面的日誌內容:
埠2222的
埠2223的
可以看到,之前啟動的兩個compute-service服務端分別被呼叫了三次,兩次。到這裡,我們已經通過Ribbon在客戶端已經實現了對服務呼叫的均衡負載。