本篇主要介紹的是SpringCloud中的服務消費者(Feign)和負載均衡(Ribbon)功能的實現以及使用Feign結合Ribbon實現負載均衡。git
Feign是一個聲明式的Web Service客戶端,它使得編寫Web Serivce客戶端變得更加簡單。咱們只須要使用Feign來建立一個接口並用註解來配置它既可完成。它具有可插拔的註解支持,包括Feign註解和JAX-RS註解。Feign也支持可插拔的編碼器和解碼器。Spring Cloud爲Feign增長了對Spring MVC註解的支持,還整合了Ribbon和Eureka來提供均衡負載的HTTP客戶端實現。github
開發環境算法
注:不必定非要用上述的版本,能夠根據狀況進行相應的調整。須要注意的是SpringBoot2.x之後,jdk的版本必須是1.8以上!spring
確認了開發環境以後,咱們再來添加相關的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-eureka
服務的工程,用於作註冊中心。配置和以前的基本同樣。application.properties
添加以下的配置:bash
配置信息:併發
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/
複製代碼
配置說明:app
完成配置信息的添加後,咱們再來看代碼如何實現。 在服務端這邊只須要在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/
複製代碼
配置說明:
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);
}
}
複製代碼
這個服務的代碼就比較簡單了,只是一個普通的服務,提供一個接口而後打印信息便可。
啓動類代碼示例:
@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/
,便可查看註冊中心的信息。
在瀏覽器輸入:
返回:
pancm,Hello World
複製代碼
說明能夠直接訪問第二個消費服務。
而後再輸入:
經過第一個消費服務調用第二個服務。
控制檯打印:
接受到請求參數:pancm,進行轉發到其餘服務
複製代碼
界面返回結果:
pancm,Hello World
複製代碼
示例圖:
出現以上結果說明客戶端已經成功的經過feign調用了遠程服務hello,而且將結果返回到了瀏覽器。
Ribbon是Netflix發佈的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務鏈接在一塊兒。Ribbon客戶端組件提供一系列完善的配置項如鏈接超時,重試等。簡單的說,就是在配置文件中列出Load Balancer後面全部的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨即鏈接等)去鏈接這些機器。咱們也很容易使用Ribbon實現自定義的負載均衡算法。簡單地說,Ribbon是一個客戶端負載均衡器。
開發環境
注:不必定非要用上述的版本,能夠根據狀況進行相應的調整。須要注意的是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</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>
複製代碼
注: 基於SpringBoot1.x以上SpringCloud是Dalston版本的eureka 依賴是 <artifactId>spring-cloud-starter-eureka</artifactId>
,feign 依賴是 <artifactId>spring-cloud-starter-ribbon</artifactId>
,少了個 netflix 。SpringCloud的版本命名方式是經過倫敦的地方來命名的,版本順序是根據首字母的順序來的。
首先創建一個springcloud-ribbon-eureka
服務的工程,用於作註冊中心。配置和代碼以前的基本同樣,除了端口和打印信息,這裏就不在說明了。
這裏咱們定義三個服務,一個服務使用Ribbon作負載均衡,另外兩個作普通的服務,服務名稱依次爲springcloud-ribbon-consumer
、springcloud-ribbon-consumer2
和springcloud-ribbon-consumer3
。 添加如上的依賴以後,在application.properties
添加以下的配置:
consumer 配置信息:
spring.application.name=springcloud-ribbon-consumer
server.port=9006
eureka.client.serviceUrl.defaultZone=http://localhost:8003/eureka/
複製代碼
consumer2 配置信息:
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/
複製代碼
配置說明:
使用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/
,便可查看註冊中心的信息。
在瀏覽器輸入:
而後進行重複訪問,返回以下結果:
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!
複製代碼
能夠看到已經成功實現了隨機訪問的策略!
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! 這是另外一個服務!
複製代碼
示例圖:
基於SpringBoot1.x、SpringCloud的Dalston版本開發的地址:github.com/xuwujing/sp…
基於SpringBoot1.x、SpringCloud 的Dalston版本開發的地址: github.com/xuwujing/sp…
若是感受項目不錯,但願能給個star,謝謝!
一首很是棒的純音樂 NEXT TO YOU ,強烈推薦!
原創不易,若是感受不錯,但願給個推薦!您的支持是我寫做的最大動力! 版權聲明: 做者:虛無境 博客園出處:www.cnblogs.com/xuwujing CSDN出處:blog.csdn.net/qazwsxpcm 我的博客出處:www.panchengming.com