一:服務的注冊和發現
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在客戶端已經實現了對服務調用的均衡負載。