天天看點

SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)使用詳解

前言

本篇主要介紹的是SpringCloud中的服務消費者(Feign)和負載均衡(Ribbon)功能的實作以及使用Feign結合Ribbon實作負載均衡。

SpringCloud Feign

Feign 介紹

Feign是一個聲明式的Web Service用戶端,它使得編寫Web Serivce用戶端變得更加簡單。我們隻需要使用Feign來建立一個接口并用注解來配置它既可完成。它具備可插拔的注解支援,包括Feign注解和JAX-RS注解。Feign也支援可插拔的編碼器和解碼器。Spring Cloud為Feign增加了對Spring MVC注解的支援,還整合了Ribbon和Eureka來提供均衡負載的HTTP用戶端實作。

開發準備

開發環境

  • JDK:1.8
  • SpringBoot:2.1.1.RELEASE
  • SpringCloud:Finchley

注:不一定非要用上述的版本,可以根據情況進行相應的調整。需要注意的是SpringBoot2.x以後,jdk的版本必須是1.8以上!

确認了開發環境之後,我們再來添加相關的pom依賴。

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
</dependencies>
           

注: 基于SpringBoot1.x以上SpringCloud是Dalston版本的eureka 依賴是

<artifactId>spring-cloud-starter-eureka</artifactId>

,feign 依賴是

<artifactId>spring-cloud-starter-feign</artifactId>

,少了個 netflix 。SpringCloud的版本命名方式是通過倫敦的地方來命名的,版本順序是根據首字母的順序來的。

SpringCloud Feign 示例

服務端

首先建立一個

springcloud-feign-eureka

服務的工程,用于做注冊中心。配置和之前的基本一樣。

application.properties

添加如下的配置:

配置資訊:

spring.application.name=springcloud-feign-eureka-server
server.port=8001
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
           

配置說明:

  • spring.application.name: 這個是指定服務名稱。
  • server.port:服務指定的端口。
  • eureka.client.register-with-eureka:表示是否将自己注冊到Eureka Server,預設是true。
  • eureka.client.fetch-registry:表示是否從Eureka Server擷取注冊資訊,預設為true。
  • eureka.client.serviceUrl.defaultZone: 這個是設定與Eureka Server互動的位址,用戶端的查詢服務和注冊服務都需要依賴這個位址。

完成配置資訊的添加後,我們再來看代碼如何實作。

在服務端這邊隻需要在SpringBoot啟動類添加

@EnableEurekaServer

注解就可以了,該注解表示此服務是一個服務注冊中心服務。

代碼示例:

@EnableEurekaServer
	@SpringBootApplication
	public class FeignEurekaApplication {
	  public static void main(String[] args) {
	      SpringApplication.run(FeignEurekaApplication.class, args);
	      System.out.println("feign注冊中心服務啟動...");
	  }
	}

           

用戶端

這裡我們定義兩個消費者,

springcloud-feign-consumer

springcloud-feign-consumer2

,一個使用feign做轉發,另一個為一個普通的項目。 添加如上的依賴之後,在

application.properties

consumer 配置資訊:

spring.application.name=springcloud-feign-consumer
server.port=9002
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
           

consumer2 配置資訊:

spring.application.name=springcloud-feign-consumer2
server.port=9003
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
           
  • spring.application.name: 這個是用戶端的服務名稱。如果有多個服務使用同一個名稱但是通路位址不同,結合ribbon 使用,則可以實作負載均衡功能。
  • eureka.client.serviceUrl.defaultZone: 注冊中心服務端的位址。
springcloud-feign-consumer

springcloud-feign-consumer

服務因為要實作fegin的功能,是以需要在啟動類上添加

@EnableFeignClients

該注解,使用該注解表示啟用feign進行遠端調用。

啟動類代碼示例:

@SpringBootApplication
	@EnableDiscoveryClient
	@EnableFeignClients
	public class FeignConsumerApplication {
		public static void main(String[] args) {
			SpringApplication.run(FeignConsumerApplication.class, args);
			  System.out.println("feign第一個消費者服務啟動...");
		}
	}

           

需要定義轉發的服務,這裡使用

@FeignClient

注解來實作,該注解表示需要轉發服務的名稱,該名稱在

application.properties

中進行配置。

這裡我們把請求轉發到第二個服務

springcloud-feign-consumer2

轉發類代碼示例:

@FeignClient(name= "springcloud-feign-consumer2") 
	public interface HelloRemote {
    	@RequestMapping(value = "/hello")
   		 public String hello(@RequestParam(value = "name") String name);
	}


           

我們還需要提供一個入口供外部調用,然後調用上述的的方法進行轉發。

控制層代碼示例:

@RestController
	public class ConsumerController {
	
	    @Autowired
	    HelloRemote helloRemote;
		
	    @RequestMapping("/hello/{name}")
	    public String index(@PathVariable("name") String name) {
	    	System.out.println("接受到請求參數:"+name+",進行轉發到其他服務");
	        return helloRemote.hello(name);
	    }
	}

           
springcloud-feign-consumer2

這個服務的代碼就比較簡單了,隻是一個普通的服務,提供一個接口然後列印資訊即可。

@SpringBootApplication
	@EnableDiscoveryClient
	public class FeignConsumerApplication2 {
		public static void main(String[] args) {
			SpringApplication.run(FeignConsumerApplication2.class, args);
			  System.out.println("feign第二個消費者服務啟動...");
		}
	}

           
@RestController
	public class ConsumerController {
	
		@RequestMapping("/hello")
	    public String index(@RequestParam String name) {
	        return name+",Hello World";
	    }
	}

           

功能測試

完成如上的工程開發之後,我們依次啟動服務端和用戶端的三個程式,然後在浏覽器界面輸入:

http://localhost:8001/

,即可檢視注冊中心的資訊。

在浏覽器輸入:

http://localhost:9003/hello?name=pancm

傳回:

pancm,Hello World
           

說明可以直接通路第二個消費服務。

然後再輸入:

http://localhost:9002/hello/pancm

通過第一個消費服務調用第二個服務。

控制台列印:

接受到請求參數:pancm,進行轉發到其他服務
           

界面傳回結果:

pancm,Hello World
           

示例圖:

SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)使用詳解
SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)使用詳解

出現以上結果說明用戶端已經成功的通過feign調用了遠端服務hello,并且将結果傳回到了浏覽器。

SpringCloud Ribbon

Ribbon 介紹

Ribbon是Netflix釋出的開源項目,主要功能是提供用戶端的軟體負載均衡算法,将Netflix的中間層服務連接配接在一起。Ribbon用戶端元件提供一系列完善的配置項如連接配接逾時,重試等。簡單的說,就是在配置檔案中列出Load Balancer後面所有的機器,Ribbon會自動的幫助你基于某種規則(如簡單輪詢,随即連接配接等)去連接配接這些機器。我們也很容易使用Ribbon實作自定義的負載均衡算法。簡單地說,Ribbon是一個用戶端負載均衡器。

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>
</dependencies>
           

<artifactId>spring-cloud-starter-eureka</artifactId>

<artifactId>spring-cloud-starter-ribbon</artifactId>

SpringCloud Ribbon 示例

springcloud-ribbon-eureka

服務的工程,用于做注冊中心。配置和代碼之前的基本一樣,除了端口和列印資訊,這裡就不在說明了。

這裡我們定義三個服務,一個服務使用Ribbon做負載均衡,另外兩個做普通的服務,服務名稱依次為

springcloud-ribbon-consumer

springcloud-ribbon-consumer2

springcloud-ribbon-consumer3

。 添加如上的依賴之後,在

application.properties

spring.application.name=springcloud-ribbon-consumer
server.port=9006
eureka.client.serviceUrl.defaultZone=http://localhost:8003/eureka/
           
spring.application.name=springcloud-ribbon-consumer2
server.port=9007
eureka.client.serviceUrl.defaultZone=http://localhost:8003/eureka/
           

consumer3 配置資訊:

這裡的服務名稱和另一個服務的名稱保持一緻才能實作負載均衡功能。

spring.application.name=springcloud-ribbon-consumer2
server.port=9008
eureka.client.serviceUrl.defaultZone=http://localhost:8003/eureka/
           
springcloud-ribbon-consumer

使用Ribbon實作負載均衡,隻需要在啟動類中執行個體化

RestTemplate

,通過

@LoadBalanced

注解開啟均衡負載能力.。

@SpringBootApplication
	@EnableDiscoveryClient
	public class RibbonConsumerApplication {
		public static void main(String[] args) {
			SpringApplication.run(RibbonConsumerApplication.class, args);
			System.out.println("ribbon第一個消費者服務啟動...");
		}
	
		@Bean
		@LoadBalanced
		public RestTemplate restTemplate() {
			return new RestTemplate();
		}
	}

           

RestTemplate

來進行調用,調用另外一個服務的名稱。

@RestController
	public class ConsumerController {
	   
	    @Autowired
	    RestTemplate restTemplate;
	    
	    @RequestMapping("/hello")
	    public String hello() {
	    	//進行遠端調用
	        return restTemplate.getForObject("http://springcloud-ribbon-consumer2/hello/?name=xuwujing", String.class);
	    }
	}
    
           

springcloud-ribbon-consumer2

springcloud-ribbon-consumer3

代碼基本和fegin中的

springcloud-feign-consumer

一樣,是以這裡就不在貼代碼了。

完成如上的工程開發之後,我們依次啟動服務端和用戶端的四個程式,然後在浏覽器界面輸入:

http://localhost:8003/

http://localhost:9006//hello

然後進行重複通路,傳回如下結果:

xuwujing,Hello World!
xuwujing,Hello World! 這是另一個服務!
xuwujing,Hello World!
xuwujing,Hello World! 這是另一個服務!
xuwujing,Hello World!
xuwujing,Hello World! 這是另一個服務!
           

說明已經實作了負載均衡功能了。

我們從上述的結果中發現了一點,這個調用貌似是有規律的,兩個服務進行來回調用。那麼根據這個我們發現了,負載均衡是由政策的。上述的這個示例的政策就是其中的一個RoundRobinRule輪詢政策。

這裡就順便說下Ribbon的政策,Ribbon一共有7中政策,預設使用的政策是輪詢。政策說明如下表格:

政策名 政策聲明 政策描述 實作說明
BestAvailableRule public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 選擇一個最小的并發請求的server 逐個考察Server,如果Server被tripped了,則忽略,在選擇其中ActiveRequestsCount最小的server
AvailabilityFilteringRule public class AvailabilityFilteringRule extends PredicateBasedRule 過濾掉那些因為一直連接配接失敗的被标記為circuit tripped的後端server,并過濾掉那些高并發的的後端server(active connections 超過配置的門檻值) 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status裡記錄的各個server的運作狀态
WeightedResponseTimeRule public class WeightedResponseTimeRule extends RoundRobinRule 根據響應時間配置設定一個weight,響應時間越長,weight越小,被選中的可能性越低。 一個背景線程定期的從status裡面讀取評價響應時間,為每個server計算一個weight。Weight的計算也比較簡單responsetime 減去每個server自己平均的responsetime是server的權重。當剛開始運作,沒有形成status時,使用roubine政策選擇server。
RetryRule public class RetryRule extends AbstractLoadBalancerRule 對標明的負載均衡政策機上重試機制。 在一個配置時間段内當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server
RoundRobinRule public class RoundRobinRule extends AbstractLoadBalancerRule roundRobin方式輪詢選擇server 輪詢index,選擇index對應位置的server
RandomRule public class RandomRule extends AbstractLoadBalancerRule 随機選擇一個server 在index上随機,選擇index對應位置的server
ZoneAvoidanceRule public class ZoneAvoidanceRule extends PredicateBasedRule 複合判斷server所在區域的性能和server的可用性選擇server 使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的運作性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于過濾掉連接配接數過多的Server。

這裡也順便說明如何指定一個政策使用方法。

最簡單的方式

application.properties

添加如下配置:

springcloud-ribbon-consumer2.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
           

該配置的意思是為

springcloud-ribbon-consumer2

服務指定随機政策。

另一種方式

建立一個類,通過

@Bean

注解指定政策。

@Configuration
	public class RibbonConfiguration{
	      @Bean
	      public IRule ribbonRule(){        
	          return new RandomRule();
	     }
	}
           

然後再通過

@RibbonClien

注解指定服務。

@RibbonClient(name="springcloud-ribbon-consumer2", configuration=RibbonConfiguration.class)
	public class HelloRibbon{	 
	}

           

注: 如果有的服務沒有在Eureka進行注冊,可以使用

ribbon.listOfServers

方式在配置檔案中來指定服務。

例如:

springcloud-ribbon-consumer2.ribbon.listOfServers:localhost:9007,localhost:9008
           

添加好了該配置之後,我們重新開機

springcloud-ribbon-consumer

服務,然後依舊重複通路

http://localhost:9006//hello

該位址,

通路的結果如下:

xuwujing,Hello World!
xuwujing,Hello World! 這是另一個服務!
xuwujing,Hello World! 這是另一個服務!
xuwujing,Hello World!
xuwujing,Hello World!
xuwujing,Hello World!
           

可以看到已經成功實作了随機通路的政策!

SpringCloud Fegin結合Ribbon實作負載均衡

Fegin包含了Ribbon,可以直接實作負載均衡功能。這裡我們就在Ribbon的項目稍微進行改造下實作該功能。

首先在pom檔案添加Fegin的依賴包。

<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
           

然後在

springcloud-ribbon-consumer

項目的啟動類上添加

@EnableFeignClients

注解,啟用feign進行遠端調用。

添加完成之後,建立一個類,實作feign遠端調用。

代碼如下:

@FeignClient(name= "springcloud-ribbon-consumer2") 
	public interface HelloRemote {
	    @RequestMapping(value = "/hello")
	    public String hello(@RequestParam(value = "name") String name);
	}

           

最後在提供一個新的接口供外部調用。這裡就直接在之前的代碼上新加一個接口了。

@RestController
	public class ConsumerController {
	   
	    @Autowired
	    RestTemplate restTemplate;
	    
	    @RequestMapping("/hello")
	    public String hello() {
	        return restTemplate.getForObject("http://springcloud-ribbon-consumer2/hello/?name=xuwujing", String.class);
	    }
	    
	   
	    @Autowired
	    HelloRemote helloRemote;
		
	    @RequestMapping("/hello/{name}")
	    public String index(@PathVariable("name") String name) {
	    	System.out.println("接受到請求參數:"+name+",進行轉發到其他服務!");
	        return helloRemote.hello(name);
	    }
	}

           

添加完之後,重新開機

springcloud-ribbon-consumer

http://localhost:9006//hello/pancm

pancm,Hello World!
pancm,Hello World! 這是另一個服務!
pancm,Hello World!
pancm,Hello World! 這是另一個服務!
pancm,Hello World!
pancm,Hello World! 這是另一個服務!
           
SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)使用詳解
SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)使用詳解

其他

項目位址

基于SpringBoot2.x、SpringCloud的Finchley版本開發的位址:https://github.com/xuwujing/springcloud-study

基于SpringBoot1.x、SpringCloud 的Dalston版本開發的位址: https://github.com/xuwujing/springcloud-study-old

如果感覺項目不錯,希望能給個star,謝謝!

音樂推薦

一首非常棒的純音樂 NEXT TO YOU ,強烈推薦!

原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力!

版權聲明:

作者:虛無境

部落格園出處:http://www.cnblogs.com/xuwujing

CSDN出處:http://blog.csdn.net/qazwsxpcm    

個人部落格出處:http://www.panchengming.com

如果你對生活感覺到了絕望,請不要氣餒。因為這樣隻會讓你更加絕望!

所謂的希望往往都是在絕望中萌發的,是以,請不要放棄希望!

繼續閱讀