SpringCloud-服務間通訊方式

接下來在整個微服務架構中,咱們比較關心的就是服務間的服務改如何調用,有哪些調用方式?java

總結:在springcloud中服務間調用方式主要是使用 http restful方式進行服務間調用git

1. 基於RestTemplate的服務調用

在上面的基礎上,使用的是consul註冊,pom.xml文件github

<?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 服務調用

  1. 建立兩個服務並註冊到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. 測試服務調用

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模版請求自動轉換成客戶端負載均衡的服務調用。

再建立一個服務類,和上面的服務類同樣,只有端口不一樣web

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,循環訪問spring

2. Ribbon負載均衡策略

ribbon負載均衡算法apache

  • RoundRobinRule 輪訓策略 按順序循環選擇 Server瀏覽器

  • RandomRule 隨機策略 隨機選擇 Serverrestful

  • AvailabilityFilteringRule 可用過濾策略
    `會先過濾因爲屢次訪問故障而處於斷路器跳閘狀態的服務,還有併發的鏈接數量超過閾值的服務,而後對剩餘的服務列表按照輪詢策略進行訪問markdown

  • 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

相關文章
相關標籤/搜索