多項目如何高效協同合作 | springcloud系列之bus消息匯流排

  • 2021 年 10 月 8 日
  • 筆記

前言

  • 在springcloud config章節中我們完成了配種中心的搭建,以及通過配置中心完成配置的抽離通過springcloud config模組我們將配置抽離到git倉庫中我們不必要每次為了改配置而發包了。但是springcloud config並沒有徹底的幫我們解決配置自動更新的問題。我們在config章節中我們遺留最後是每次修改git倉庫後需要人為手動調用actuator/refresh介面才能促使配置的更新。當時也指出了在分散式微服務眾多的情況人為調用介面耗時而且沒有保障!!!當然你也可以寫個腳本批量調用。但是今天我們即將學習的springcloud bus正好可以我們規避掉上述的問題
  • 之前在springcloud config中有一點這裡做一個補充說明。在git倉庫發生變化時如何進行調用refresh介面。主要是通過git倉庫的WebHooks來進行回調的。

image-20210608153000436.png

整合springcloud bus

  • config章節我們使用的是framework-root項目中的order模組來進行的。本次我們選擇payment模組作為config客戶端演示(再次操作熟練下記憶)。
  • 首先我們的pom中需要添加config作為client。 和上次不同的是我們本次需要引入bus模組。因為需要用到端點刷新所以actuator必不可少

pom

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置文件

  • 這裡我們需要回顧上章節內容。首先需要在bootstrap.yml文件中指定config-server地址
spring:
  cloud:
    config:
      label: master
      name: config-server
      profile: dev
      uri: //localhost:8070
  • 因為bus藉助到消息隊列我們這裡通過rabbitmq來進行演示。所以我們還需要配置rabbit資訊在application.yml中
rabbitmq:
  host: 39.102.60.114
  port: 5672
  username: 'zxhtom'
  password: '025025'
  • 為了更加了解每個模組功能涉及的端點情況,我們這裡端點並沒有全部放開所以需要啥端點需要我們自己配置
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream,info,bus-refresh
  • 這裡還是注意下因為springboot版本升級,在actuator監控中會發生變化。低版本中bus涉及的端點介面是/bus/refresh 。但是筆者這裡actuator 是2.2.2.RELEASE版本的。這裡的刷新介面是/actuator/bus-refresh 。

controller

  • 當然這裡為了測試方便能夠直白的看到配置發生了變化。我們寫個介面讀取配置 .。和普通的介面唯一區別就是controller類上多了一個@RefreshScope
@RestController
@RefreshScope
@RequestMapping(value = "/payment/config")
public class ConfigController {
​
    @Value("${zxhtom}")
    String value;
​
    @RequestMapping(value = "/getConfig" , method = RequestMethod.GET)
    public String getConfig() {
        return value;
    }
}

多實例部署

  • 上面我們簡單對payment進行改造完成了config-client的升級。但是在bus自動刷新config-client中需要多台config-client 。 這裡拋個小技巧—idea一份程式碼多實例部署
  • 其實這個功能我們在eureka章節中也提到過。不過筆者這裡還是為什麼大家整理出來就不需要你們去翻啦。畢竟最近高產不好找!!!

image-20210608163044657.png

  • 我們在idea中Edit Configurations 。 然後添加一個springboot啟動類配置。

image-20210608163156348.png

  • 我們直接在VM Options中指定其他埠。這樣就完成了多實例部署。但是有的情況下我們不僅僅需要埠不一樣。那麼我們就可以通過Enviroment varables 配置指定外部配置文件。這裡我們僅僅設置埠不一樣就可以了。

測試

  • 經過上面的多實例部署的方式我們可以在idea中啟動兩個payment服務。

image-20210608163353869.png

  • 這裡我們僅啟動了config-server + euraka + 2* payment 。 實際上此時我們還未使用到eureka。 不過因為項目之前使用了eureka。
  • 全部啟動成功之後我們先訪問兩個payment服務中配置介面查看此時的配置資訊。

image-20210608163930299.png

  • 然後我們在修改倉庫中的對應的值,這裡對應git倉庫中config-server-dev.properties 。 至於為什麼是這個文件就不分析了config章節里詳細分析過了。
  • 修改完倉庫配置文件後,就到了我們bus的重頭菜了,這裡我們payment起了兩個實例。為什麼我要起多個實例了就是為了這裡能夠演示蔓延的效果。我們這個時候通過刷新其中一個實例的數據就可以實現兩個實例數據全部刷新了。但是actuator/refresh這個介面是不能滿足的我們需要使用actuator/bus-refresh來實現。

image-20210608165658183.png

  • 刷新完之後我們在訪問兩個payment數據會發現發生變化。這裡讀者自己操作下就可以看出效果了。

各歸其位

  • 不知道你有沒有發現,上面通過bus我們實現了只需要執行一次刷新介面就可以完成所有的配置刷新了。但是還有有點缺點的,springcloud bus模組在springcloud中的定位是【消息匯流排】 。 匯流排的意思個人理解應該是龍頭的意思。但是上面的實現好像只是一個中轉的作用。就好像一個組織里龍頭老大需要聽命與其中一個手下辦事一樣
  • 所有大多數項目架構中都不採用上述的方式來實現config的動態刷新。而是將config-server進行改造升級。讓config-server擁有bus刷新的能力。這樣在git倉庫中鉤子配置成config-server對應的刷新介面就可以了。這樣從職能上分析也會變得職責分明;匯流排做數據的回調、各個微服務訂閱消息刷新配置就可以了。
  • 還有人說為了讓職責更加的分明,我們可以新建一個模組叫做bus。讓他充當鉤子回到的函數。這樣config-server做為配置的數據源、config-client讀取配置、bus作為配置刷新通知功能。這樣三者互相相輔相成。
  • 總之,至於怎麼劃分就是每個架構中需要考慮的事情了。我們這裡不做探討。

局部刷新

  • 上面通過引入第三方模組我們將模組功能職責分的很明晰了。而且也能夠實現配置的動態刷新,但是有的時候我們服務刷新配置的消耗是巨大這種情況我們就需要精準刷新。換句話說就是如非必要拒絕刷新。有的時候我們git倉庫並不會影響到所有模組的刷新這個時候我們就需要只刷部分服務。
  • 上述中兩個payment埠分別為8001/8003 。 加入這個時候我們想在git更新時只刷新8003埠服務。我們可以調用刷新介面是指定服務名
  • localhost:8092/actuator/bus-refresh/cloud-payment-service:8003 。 這樣8003的payment的配置會發生變化。而8001的配置還是之前舊數據
  • 重點就是在刷新介面上。actuator/bus-refresh/{destination} 。 destination的取值就是對我們下發服務的一種描述。關於他的格式主要是如下
  • ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id}:${server.port} 。正常情況下我們通過${spring.application.name}:${server.port}進行識別。

源碼

點我下載哦