SpringCloud(二):服務呼叫與負載均衡

petterchx發表於2021-09-09

一、概念部分

在分散式系統中,各個服務透過服務註冊中心來實現服務註冊和服務發現。
服務與服務之前會有相互呼叫的部分,本篇文章將介紹如何使用服務註冊中心,來搭建一個服務註冊與客戶端服務呼叫的例子。
在上篇文章中我們實現了服務註冊中心的叢集實現了高可用的服務註冊中心,本篇文章我們將使用上篇的服務註冊中心來做具體的服務提供和服務呼叫。

本案例提供三個例項:服務註冊中心、服務提供者、服務消費者

圖片描述


呼叫說明:
1.啟動服務註冊中心
2.啟動服務提供者和服務消費者,並且都將自己註冊到服務註冊中心
3.服務消費者從服務註冊中心獲取註冊中心的服務資訊(獲取服務提供者地址給消費者)
4.服務消費者呼叫服務提供者的服務

二、程式碼示例

服務提供者

1.建立專案producer-service,並新增依賴到 build.gradle

dependencies {   compile('org.springframework.cloud:spring-cloud-starter-eureka')
   testCompile('org.springframework.boot:spring-boot-starter-test')
}

2.新建配置檔案 application.yml

#spring配置spring:
  application:    #應用名稱(服務提供者)
    name: producer-service#伺服器配置server:  #埠
  port: 8000#服務中心發現註冊配置eureka:
  client:    #服務註冊中心地址
    service-url:
      defaultZone:  

3.編輯啟動類 新增 @EnableDiscoveryClient 註解

/**
* 服務提供者
*/@SpringBootApplication@EnableDiscoveryClientpublic class ProducerServiceApplication {   public static void main(String[] args) {
      SpringApplication.run(ProducerServiceApplication.class, args);
   }
}

4.新建controller類,提供輸出 hello資訊的服務

/**
* Hello控制器
*/@RestControllerpublic class HelloController {    @Value("${server.display-name}")    private String displayName; // 注入配置檔案中的服務顯示名稱

    /**
     * 提供輸出hello資訊
     *
     * @param name 名字
     * @return "hello @name,this is producer service message!"
     */
    @RequestMapping("hello")    public String hello(@RequestParam String name) {        return "hello " + name + ", this is " + displayName + " service message!";
    }
}

@EnableDiscoveryClient註解具有註冊服務功能。
啟動該專案
開啟瀏覽器輸入:
發現該服務提供者已經註冊到了配置檔案中所配置的服務註冊中心,例項名稱為 PRODUCER-SERVICE

圖片描述


服務消費者

1.建立專案consumer-service,並新增依賴到 build.gradle

dependencies {   compile('org.springframework.cloud:spring-cloud-starter-eureka')   compile('org.springframework.cloud:spring-cloud-starter-feign')
   testCompile('org.springframework.boot:spring-boot-starter-test')
}

2.新建配置檔案application.yml

#spring配置spring:
  application:
    #應用名稱(服務呼叫者)
    name: consumer-service#伺服器配置server:
  #埠
  port: 7000#服務中心發現註冊配置eureka:
  client:
    #服務註冊中心地址
    service-url:
      defaultZone:  []()

3.編輯啟動類,新增@EnableDiscoveryClient和@EnableFeignClients註解

/**
* 服務呼叫者
*/@SpringBootApplication@EnableDiscoveryClient@EnableFeignClientspublic class ConsumerServiceApplication {   public static void main(String[] args) {
      SpringApplication.run(ConsumerServiceApplication.class, args);
   }
}

@EnableDiscoveryClient:啟用服務註冊與發現
@EnableFeignClients: 啟用Feign進行遠端呼叫

4.新建feign呼叫介面類

/**
* feign遠端呼叫介面
* FeignClient註解的name屬性值要寫服務提供者在註冊中心註冊的服務名稱
*/@FeignClient(name = "producer-service")public interface HelloRemote {    /**
     * 遠端呼叫方法
     * @param name 名稱
     * @return 遠端呼叫結果
     */
    @RequestMapping(value = "/hello")    String hello(@RequestParam(value = "name") String name);
}

5.新建controller類,將HelloRemote遠端呼叫介面注入控制器層,然後像呼叫普通方法一樣呼叫

/**
* Hello控制器
*/@RestControllerpublic class HelloController {    private final HelloRemote helloRemote;  // 遠端呼叫介面

    @Autowired
    public HelloController(HelloRemote helloRemote) {        this.helloRemote = helloRemote;
    }    /**
     * 輸出hello方法
     * @param name 名稱
     * @return 遠端呼叫返回值
     */
    @RequestMapping(value = "/hello/{name}")    public String hello(@PathVariable(value = "name") String name){        return helloRemote.hello(name);
    }
}

啟動專案
發現該服務消費者已經註冊到了配置檔案中所配置的服務註冊中心,例項名稱為 CONSUMER-SERVICE


圖片描述

服務呼叫測試

需要先啟動服務註冊中心,然後啟動服務提供者註冊到服務註冊中心,然後啟動服務消費者註冊到服務註冊中心。

瀏覽器訪問:

圖片描述


透過直接訪問服務提供者的控制器方法,返回上圖資訊,說明服務提供者服務正常。

瀏覽器訪問:

圖片描述


透過服務消費者的控制器方法遠端呼叫服務消費者的方法,發現呼叫成功返回上圖資訊。
說明服務消費者成功透過feign客戶端呼叫了服務提供者提供的遠端hello方法。

負載均衡

圖片描述

在一些特殊的場景下,很重要的服務提供者要保證高可用性,需要執行多個相同的服務提供者組成叢集的方式來給服務消費者提供服務。

為了演示方便,我這裡直接為服務提供者專案新建配置檔案,設定不同的顯示名字和埠。

application-pro1.yml

#spring配置spring:
  application:    #應用名稱(服務提供者)
    name: producer-service#伺服器配置server:  #埠
  port: 8001
  #顯示名稱
  display-name: producer-service1#服務中心發現註冊配置eureka:
  client:    #服務註冊中心地址
    service-url:
      defaultZone:  

application-pro2.yml

#spring配置spring:
  application:    #應用名稱(服務提供者)
    name: producer-service#伺服器配置server:  #埠
  port: 8002
  #顯示名稱
  display-name: producer-service2#服務中心發現註冊配置eureka:
  client:    #服務註冊中心地址
    service-url:
      defaultZone:  

application-pro3.yml

#spring配置spring:
  application:    #應用名稱(服務提供者)
    name: producer-service#伺服器配置server:  #埠
  port: 8003
  #顯示名稱
  display-name: producer-service3#服務中心發現註冊配置eureka:
  client:    #服務註冊中心地址
    service-url:
      defaultZone:  

3.打包

gradle build

4.執行

java -jar producer-service-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro1
java -jar producer-service-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro2
java -jar producer-service-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro3

5.驗證

開啟瀏覽器輸入:

圖片描述


可以看到服務註冊中心有4個PRODUCER-SERVICE的服務提供者,佔用埠分別是8000、8001、8002、8003,其中8000埠的提供者是使用預設配置檔案application.yml啟動的。


我們可以透過服務消費者的方法來測試服務提供者的叢集訪問。
開啟瀏覽器輸入:

圖片描述


瀏覽器返回資訊: producer-service
重新整理:


圖片描述

瀏覽器返回資訊: producer-service1

再次重新整理:


圖片描述

瀏覽器返回資訊: producer-service2

再次重新整理:


圖片描述

瀏覽器返回資訊: producer-service3

發現瀏覽器透過每次重新整理,都會返回不同的producer-service呼叫結果,證明負載均衡成功呼叫。

如果手動停止某個服務提供者,其他服務提供者依舊會正常被服務消費者呼叫,從而實現了高可用的服務。

熔斷

如果服務提供者服務部署在不同機器,由於網路等因素的原因導致一個或多個服務提供者無法被呼叫,或者全部的服務提供者節點大面積停止執行,那麼服務消費者這時候就應該友好的進行熔斷,並提示使用者該服務呼叫不成功 返回最佳化處理後的友好資訊。

熔斷是服務消費者(客戶端)主動與服務提供者(服務端)斷開,
一個完整的服務呼叫應該考慮熔斷。
我們直接修改服務消費者 專案consumer-service

1.在application.yml裡新增配置,開啟熔斷

#feign遠端呼叫配置feign:
  hystrix:    #開啟熔斷
    enabled: true

2.建立回撥類

建立 HelloRemoteFallback 繼承 HelloRemote遠端呼叫介面,並實現介面方法。

/**
* 熔斷回撥類
* 繼承feign遠端呼叫介面,並在實現方法中輸出回撥的資訊
*/@Componentpublic class HelloRemoteFallback implements HelloRemote {    /**
     * 遠端呼叫失敗,將會回撥該方法
     * @param name 名稱
     * @return 自定義返回資訊
     */
    @Override
    public String hello(@RequestParam(value = "name") String name) {        return "hello " + name + ", this message is failed";
    }
}

3.新增fallback屬性, 在服務熔斷的時候返回fallback指定的類 並回撥對應方法。

/**
* feign遠端呼叫介面
* FeignClient註解的name屬性值要寫服務提供者在註冊中心註冊的服務名稱
* FeignClient註解的fallback屬性值表示遠端呼叫失敗時的回撥類
*/@FeignClient(name = "producer-service",fallback = HelloRemoteFallback.class)public interface HelloRemote {    /**
     * 遠端呼叫方法
     * @param name 名稱
     * @return 遠端呼叫結果
     */
    @RequestMapping(value = "/hello")    String hello(@RequestParam(value = "name") String name);
}

執行消費者服務,在提供者叢集都正常的時候,發現並沒有觸發熔斷回撥。
我們將提供者叢集的服務全部關閉,然後再次訪問服務消費者,發現觸發了熔斷回撥。


圖片描述

瀏覽器返回上圖資訊,表示服務熔斷成功。

當提供者服務或提供者叢集重新啟動並註冊到服務註冊中心後,消費者服務會結束熔斷,並且再次成功呼叫提服務供者的服務。

專案地址:

歡迎點贊

注意:
在使用feign遠端呼叫的時候一定要新增依賴:

compile('org.springframework.cloud:spring-cloud-starter-feign’)

否則會出現異常資訊:java.lang.NoClassDefFoundError: feign/Logger



作者:藍士欽
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4606/viewspace-2820400/,如需轉載,請註明出處,否則將追究法律責任。

相關文章