接下來在整個微服務架構中,我們比較關心的就是服務間的服務改如何調用,有哪些調用方式?
總結:
在springcloud中服務間調用方式主要是使用 http restful方式進行服務間調用
1. 基於RestTemplate的服務調用
在上面的基礎上,使用的是consul注冊,pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.md</groupId>
<artifactId>04-products9998</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>04-products9998</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--引入consul依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 這個包是用做健康度監控的-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<!--全局管理springcloud版本,並不會引入具體依賴-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1. 說明
- spring框架提供的RestTemplate類可用於在應用中調用rest服務,它簡化了與http服務的通信方式,統一了RESTful的標准,封裝了http鏈接, 我們只需要傳入url及返回值類型即可。相較於之前常用的HttpClient,RestTemplate是一種更優雅的調用RESTful服務的方式。
2. RestTemplate 服務調用
- 創建兩個服務並注冊到consul注冊中心中
- users 代表用戶服務 端口為 9999
- products 代表商品服務 端口為 9998
`注意:這里服務僅僅用來測試,沒有實際業務意義
3. 在商品服務中提供服務方法
@RestController
@Slf4j
public class ProductController {
@Value("${server.port}")
private int port;
@GetMapping("/product/findAll")
public Map<String,Object> findAll(){
log.info("商品服務查詢所有調用成功,當前服務端口:[{}]",port);
Map<String, Object> map = new HashMap<String,Object>();
map.put("msg","服務調用成功,服務提供端口為: "+port);
map.put("status",true);
return map;
}
}
4. 在用戶服務中使用restTemplate進行調用
@RestController
@Slf4j
public class UserController {
@GetMapping("/user/findAll")
public String findAll(){
log.info("調用用戶服務...");
//1. 使用restTemplate調用商品服務
RestTemplate restTemplate = new RestTemplate();
// get請求getxxx,post請求postxxx
// 參數1:請求路徑,參數2:返回的類型是String的
String forObject = restTemplate.getForObject("http://localhost:9998/product/findAll",
String.class);
return forObject;
}
}
5. 啟動服務
6. 測試服務調用
- 瀏覽器訪問用戶服務 http://localhost:9999/user/findAll
7. 總結
- rest Template是直接基於服務地址調用沒有在服務注冊中心獲取服務,也沒有辦法完成服務的負載均衡如果需要實現服務的負載均衡需要自己書寫服務負載均衡策略。
restTemplate直接調用存在問題 - 1.直接使用restTemplate方式調用沒有經過服務注冊中心獲取服務地址,代碼寫死不利於維護,當服務宕機時不能高效剔除
- 2.調用服務時沒有負載均衡需要自己實現負載均衡策略
2. 基於Ribbon的服務調用
0. 說明
- 官方網址: https://github.com/Netflix/ribbon
- Spring Cloud Ribbon是一個基於HTTP和TCP的客戶端負載均衡工具,它基於Netflix Ribbon實現。通過Spring Cloud的封裝,可以讓我們輕松地將面向服務的REST模版請求自動轉換成客戶端負載均衡的服務調用。
再創建一個服務類,和上面的服務類一樣,只有端口不同
server.port=9997
spring.application.name=products
spring.cloud.consul.port=8500
spring.cloud.consul.host=localhost
其他一樣
@RestController
@Slf4j
public class ProductController {
@Value("${server.port}")
private int port;
@GetMapping("/product/findAll")
public Map<String,Object> findAll(){
log.info("商品服務查詢所有調用成功,當前服務端口:[{}]",port);
Map<String, Object> map = new HashMap<String,Object>();
map.put("msg","服務調用成功,服務提供端口為: "+port);
map.put("status",true);
return map;
}
}
1. Ribbon 服務調用
# 1.項目中引入依賴
- 說明:
1.如果使用的是eureka client 和 consul client,無須引入依賴,因為在eureka,consul中默認集成了ribbon組件
2.如果使用的client中沒有ribbon依賴需要顯式引入如下依賴
<!--引入ribbon依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
# 2.查看consul client中依賴的ribbon
# 3.使用restTemplate + ribbon進行服務調用
- 使用discovery client 進行客戶端調用
- 使用loadBalanceClient 進行客戶端調用
- 使用@loadBalanced 進行客戶端調用
# 3.1 使用discovery Client形式調用
@Autowired
private DiscoveryClient discoveryClient;
//獲取服務列表,返回全部的,服務id,上面的products
List<ServiceInstance> products = discoveryClient.getInstances("服務ID");
for (ServiceInstance product : products) {
log.info("服務主機:[{}]",product.getHost());
log.info("服務端口:[{}]",product.getPort());
log.info("服務地址:[{}]",product.getUri());
log.info("====================================");
}
# 3.2 使用loadBalance Client形式調用
@Autowired
private LoadBalancerClient loadBalancerClient;
//根據負載均衡策略選取某一個服務調用,服務id=products
ServiceInstance product = loadBalancerClient.choose("服務ID");//地址 默認輪詢策略
log.info("服務主機:[{}]",product.getHost());
log.info("服務端口:[{}]",product.getPort());
log.info("服務地址:[{}]",product.getUri());
# 3.3 使用@loadBalanced(常用)
//1.整合restTemplate + ribbon
@Configuration
public class RestTemplateConfig {
// 在工廠中創建一個restTemplate對象
@Bean
// 加上這個注解代表當前的restTemplate對象帶有ribbon負載均衡
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//2.調用controller服務位置注入RestTemplate
// 此時的restTemplate就具有了負載均衡的功能
@Autowired
private RestTemplate restTemplate;
//3.調用
@RestController
@Slf4j
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/user/findAll")
public String findAll(){
// 服務id就是在配置文件中的當前服務名products
String forObject = restTemplate.getForObject("http://服務ID/product/findAll",
String.class);
return forObject;
}
}
默認的輪訓策略,也就是當前訪問的9998,之后是9997,循環訪問
2. Ribbon負載均衡策略
ribbon負載均衡算法
-
RoundRobinRule 輪訓策略 按順序循環選擇 Server
-
RandomRule 隨機策略 隨機選擇 Server
-
AvailabilityFilteringRule 可用過濾策略
`會先過濾由於多次訪問故障而處於斷路器跳閘狀態的服務,還有並發的連接數量超過閾值的服務,然后對剩余的服務列表按照輪詢策略進行訪問 -
WeightedResponseTimeRule 響應時間加權策略
`根據平均響應的時間計算所有服務的權重,響應時間越快服務權重越大被選中的概率越高,剛啟動時如果統計信息不足,則使用RoundRobinRule策略,等統計信息足夠會切換到 -
RetryRule 重試策略
`先按照RoundRobinRule的策略獲取服務,如果獲取失敗則在制定時間內進行重試,獲取可用的服務。 -
BestAviableRule 最低並發策略
`會先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然后選擇一個並發量最小的服務
3.修改服務的默認負載均衡策略
# 1.修改服務默認隨機策略
- 服務id.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
`下面的products為服務的唯一標識
products.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
4.Ribbon停止維護
# 1.官方停止維護說明
- https://github.com/Netflix/ribbon