當(dāng)一個(gè)系統(tǒng)中有多個(gè)服務(wù)提供者微服務(wù)的時(shí)候即横,服務(wù)消費(fèi)者應(yīng)該如何去選擇哪個(gè)提供者去訪問(wèn)呢。Spring Cloud提供了Ribbon來(lái)提供客戶端的負(fù)載均衡功能,本文將通過(guò)搭建的方式來(lái)簡(jiǎn)單了解如何使用Ribbon實(shí)現(xiàn)負(fù)載均衡功能。
系列文章
SpringCloud(一)-手把手教你創(chuàng)建springcloud微服務(wù)父子項(xiàng)目
SpringCloud(二)-手把手教你搭建Eureka Server和Eureka Client
SpringCloud(三)-手把手教你通過(guò)Rinbbon實(shí)現(xiàn)客戶端負(fù)載均衡
SpringCloud(四)-手把手教你使用OpenFeign
SpringCloud(五)-手把手教你使用Hystrix配置服務(wù)熔斷和降級(jí)以及Hystrix Dashboard
SpringCloud(六)-手把手教你搭建SpringCloud Config配置中心
SpringCloud(七)-手把手教你使用消息總線Bus實(shí)現(xiàn)動(dòng)態(tài)刷新
SpringCloud(八)-手把手教你使用Stream消息驅(qū)動(dòng)
負(fù)載均衡分為客戶端負(fù)載均衡和服務(wù)端負(fù)載均衡怜俐,客戶端負(fù)載均衡就是客戶端去選擇具體的微服務(wù)進(jìn)行訪問(wèn),而服務(wù)端負(fù)載均衡則是通過(guò)中間件攔截客戶端的請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的微服務(wù)吞滞。而Ribbon提供的則是客戶端的負(fù)載均衡功能佑菩,因此我們要在消費(fèi)端去裝配負(fù)載均衡功能盾沫。
1. Ribbon配置
1.1 消費(fèi)端配置Ribbon
找到我們的服務(wù)提供者springcloud-product-consumer-8200
1.1.1 修改pom.xml
<!--ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
1.1.2 添加注解
我們?cè)谂渲胷estTemplate的時(shí)候加上 @LoadBalanced 注解
package com.elio.springcloud.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
1.1.3 配置負(fù)載均衡規(guī)則
新增MyRule配置類,注意千萬(wàn)不要建在主啟動(dòng)類同一級(jí)目錄下殿漠,不然會(huì)有問(wèn)題赴精。
package rule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRule {
@Bean
public IRule getLoadBalancedRule(){
return new RoundRobinRule();
}
}
1.2 新增訪問(wèn)服務(wù)信息的API
現(xiàn)在服務(wù)消費(fèi)者和服務(wù)提供者的API不能很明確的顯示我們?cè)L問(wèn)的是哪個(gè)微服務(wù),因此需要新增一個(gè)查詢當(dāng)前訪問(wèn)微服務(wù)信息的api
1.2.1 服務(wù)提供者8100
我們找到服務(wù)提供者8100的controller新增geServieInfo方法
package com.elio.springcloud.controller;
import com.elio.springcloud.dto.Result;
import com.elio.springcloud.entity.Product;
import com.elio.springcloud.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@Slf4j
@RequestMapping("/")
public class ProductProviderController {
@Resource
private ProductService productService;
@Value("${spring.application.name}")
private String instantName;
@Value("${server.port}")
private String port;
@GetMapping("product/provider/get/info")
public Result geServieInfo(){
return new Result(200, "查詢成功", "當(dāng)前服務(wù)名:"+instantName + " 當(dāng)前端口:"+port);
}
/**
* 查詢
* @param id
* @return
*/
@GetMapping("product/provider/get/{id}")
public Result selectById(@PathVariable("id") Long id){
return new Result(200, "查詢成功", productService.selectById(id));
}
/**
* 刪除
* @param id
* @return
*/
@GetMapping("product/provider/delete/{id}")
public Result deleteById(@PathVariable("id") Long id){
return new Result(200, "刪除成功", productService.deleteById(id));
}
/**
* 修改
* @param product
* @return
*/
@PostMapping("product/provider/update")
public Result updateById(@RequestBody Product product){
return new Result(200, "修改成功", productService.updateById(product.getId(), product.getName()));
}
/**
* 新增
* @return
*/
@PutMapping( "product/provider/add")
public Result insertById(@RequestBody Product product){
return new Result(200, "修改成功", productService.insertOne(product));
}
}
1.2.2 服務(wù)消費(fèi)者8200
找到服務(wù)消費(fèi)者項(xiàng)目绞幌,修改controller蕾哟,新增geServieInfo方法,然后注意將我們寫死的地址換成服務(wù)提供者微服務(wù)名
package com.elio.springcloud.controller;
import com.elio.springcloud.dto.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
public class ProductConsumerController {
@Resource
RestTemplate restTemplate;
//public static String url = "http://localhost:8100/";
public static String url = "http://springcloud-product-provider/";
/**
* 查詢
* @return
*/
@GetMapping("product/consumer/get/info")
public Result selectById(){
return new Result(200, "查詢成功",
restTemplate.getForObject(url+"product/provider/get/info", Result.class));
}
/**
* 查詢
* @param id
* @return
*/
@GetMapping("product/consumer/get/{id}")
public Result selectById(@PathVariable("id") Long id){
return new Result(200, "查詢成功",
restTemplate.getForObject(url+"product/provider/get/"+id, Result.class));
}
}
1.3 服務(wù)提供者啟動(dòng)多個(gè)實(shí)例
在上面的兩篇文章中我們都是通過(guò)新增子項(xiàng)目來(lái)配置多個(gè)實(shí)例的,這種方法無(wú)腦而且麻煩莲蜘,因此接下來(lái)介紹第二種方法谭确。通過(guò)idea的啟動(dòng)配置來(lái)設(shè)置一個(gè)微服務(wù)在不同端口啟動(dòng)。
選中服務(wù)提供者項(xiàng)目票渠,點(diǎn)擊左上角的復(fù)制按鈕
如圖為復(fù)制后的配置名逐哈, 我們修改名稱為ProductProvider8103
在VM options中,添加參數(shù) -Dserver.port=8103问顷,表示這個(gè)實(shí)例將在8103上運(yùn)行昂秃。
點(diǎn)擊了ok后,我們?cè)傧吕璻un按鈕杜窄,就可以看到配置的 ProductProvider8103了肠骆,然后點(diǎn)擊右邊的debug按鈕,可以在8103端口上啟動(dòng)服務(wù)提供者了塞耕。
最后我們要注意的是服務(wù)提供者的實(shí)例名要不同蚀腿,不然的話只能注冊(cè)成功一個(gè),由于端口是不一樣的所以保證了實(shí)例名不一樣,服務(wù)名是一樣的扫外。
eureka:
instance:
instance-id: ${spring.application.name}:${server.port}
然后依次啟動(dòng)服務(wù)注冊(cè)中8300莉钙,服務(wù)提供者8100,8101畏浆,8103胆胰,服務(wù)消費(fèi)者8200,然后Eureka 服務(wù)中心中服務(wù)提供者會(huì)有三個(gè)實(shí)例刻获。
1.4 測(cè)試
在配置的過(guò)程中注意我提出的兩點(diǎn)注意,不然的話要么注冊(cè)不成功瞎嬉,要么就是實(shí)現(xiàn)不了負(fù)載均衡蝎毡。接下來(lái)就是測(cè)試負(fù)載均衡了,訪問(wèn)消費(fèi)者的api http://localhost:8200/product/consumer/get/info, 然后多刷新幾次氧枣,發(fā)現(xiàn)按照8100沐兵,8101,8103的順序訪問(wèn)服務(wù)提供者
2. 總結(jié)
本文通過(guò)一個(gè)簡(jiǎn)單的配置例子來(lái)實(shí)現(xiàn)了Spring Cloud項(xiàng)目配置Ribbon來(lái)實(shí)現(xiàn)客戶端負(fù)載均衡的便监,其工作原理和工作流程也沒(méi)有涉及扎谎,這將在其它文章中解析碳想。
上篇文章中,我們拋出了兩個(gè)問(wèn)題毁靶,在這篇文章中我們已經(jīng)解決了胧奔,一個(gè)是解決服務(wù)地址寫死的問(wèn)題,另一個(gè)則是負(fù)載均衡的實(shí)現(xiàn)预吆。但是現(xiàn)有的項(xiàng)目還是存在一個(gè)問(wèn)題龙填,就是我們?cè)L問(wèn)服務(wù)提供者的接口時(shí),需要在方法中指出具體的地址拐叉,如果這個(gè)接口被多處訪問(wèn)以后需要修改的話就需要修改多次岩遗,這個(gè)問(wèn)題我們留在下篇文章中解決。