1. 程式人生 > >Spring Cloud(八):使用Spring Cloud Bus來實現配置動態更新

Spring Cloud(八):使用Spring Cloud Bus來實現配置動態更新

使用Spring Cloud Config我們能實現服務配置的集中化管理,在服務啟動時從Config Server獲取需要的配置屬性。但如果在服務執行過程中,我們需要將某個配置屬性進行修改,比如將驗證碼的失效時間從五分鐘調整為十分鐘,如何將這個更新在服務端不重啟服務就能動態生效,是本文討論的內容。

Spring Cloud Bus

Spring Cloud Bus可以理解為Spring Cloud體系架構中的訊息匯流排,通過一個輕量級的Message Broker來將分散式系統中的節點連線起來。可用來實現廣播狀態更新(如配置更新),或其它管理指令。
Spring Cloud Bus 就像是一個分散式的Spring Boot Actuator, 目前提供了兩種型別的訊息佇列中介軟體支援:RabbitMQ與Kafka(對應的pom依賴分別為spring-cloud-starter-bus-amqp, spring-cloud-starter-bus-kafka)。

Spring Cloud 在spring-cloud-context中添加了兩個actuator管理介面(POST請求): /actuator/env/actuator/refresh, 前者可用於更新當前服務例項Environment物件中的配置屬性,後者可用於重新整理當前服務例項的配置資訊。

Spring Cloud Bus也提供了兩個對應的介面

  1. /actuator/bus-env,相對於/actuator/env , 使用鍵值對更新每個例項的Environment,預設不暴露,需配置management.endpoints.web.exposure.include=bus-env 來開放介面訪問
  2. /actuator/bus-refresh,相對於/actuator/refresh,對每個例項,清空RefreshScope快取,重新繫結@ConfigurationProperties, 預設不暴露,可通過配置
    management.endpoints.web.exposure.include=bus-refresh 來開放介面訪問

綜上,/actuator/env/actuator/refresh 是針對單個服務例項修改或重新整理其配置資訊,而 /actuator/bus-env/actuator/bus-refresh 則是藉助於Spring Cloud Bus的訊息機制作用於分散式系統中的所有服務例項,因此前面有Spring Cloud Bus 就像是一個分散式的Spring Boot Actuator的說法。

使用Spring Cloud Bus來實現服務配置動態更新的結構圖如下

  1. 更新配置倉庫中的配置檔案,push到遠端Git倉庫
  2. 遠端Git倉庫通過Webhook呼叫配置伺服器的通知更新介面
  3. 配置伺服器傳送配置更新訊息到訊息匯流排
  4. 其它服務節點監聽到配置伺服器傳送的配置更新訊息
  5. 其它服務節點向配置伺服器傳送拉取最新配置的請求
  6. 配置伺服器向配置倉庫拉取最新的配置返回給其它服務節點

案例演示

我們還是以前面的springcloud-config, springcloud-eureka, springcloud-eureka-client三個專案來完成本文的案例演示。原始碼地址

使用Actuator

在不引入Spring Cloud Bus的情況下,我們可以通過Spring Cloud提供的actuator介面來實現單個例項的配置動態更新。

依次啟動springcloud-eureka, springcloud-config, springcloud-eureka-client專案,然後修改springcloud-eureka-client的啟動埠,將8080改為8081,再啟動一個springcloud-eureka-client的服務例項。

springcloud-eureka-client 的測試介面程式碼如下

@RestController
@RefreshScope
public class HelloController {

    @Autowired
    private Environment env;

    @Value("${app}")
    private String app;

    @RequestMapping("/hello")
    public String hello(){
        return "Hello, welcome to spring cloud 2. env: " + env.getProperty("app") + ", value: " + app;
    }
}

此時依次請求兩個例項的hello介面,得到結果如下

我們通過/actuator/env介面來修改埠8080例項的屬性app的值,使用postman操作如圖

此時再請求介面返回結果如下

可以看到Environment物件中app屬性的值已更新,但是 @Value註解的屬性值未變,可見 /actuator/env 介面只是更新了Environment物件,並不負責重新整理其它方式引用的屬性值。此時請求另一個埠為8081的例項介面,其屬性值都未更新,也可見 /actuator/env 只作用於當前例項本身。

如果要讓8080例項的@Value屬性也動態更新,則可再呼叫/actuator/refresh介面,如圖

此時再請求測試介面,得到結果如下(@Value註解的屬性也已經更新了)

使用Spring Cloud Bus

前面我們使用 /actuator/env/actuator/refresh 兩個介面可以實現單個服務例項配置的動態更新,但在微服務架構中,服務例項可能達幾十甚至幾百個,一個個呼叫來做動態更新就有點太不方便了。這時就該Spring Cloud Bus登場了。

1.新增依賴與配置

在springcloud-config, 與springcloud-eureka-client兩個專案中,新增spring cloud bus的依賴與配置。
在pom.xml檔案中新增依賴

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

在application.yml配置檔案中新增RabbitMQ的相關配置

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: rabbitmq
    password: passw0rd

2.依次啟動springcloud-eureka, springcloud-config, springcloud-eureka-client專案,並以8081埠再啟動一個springcloud-eureka-client的服務例項。

3.我們使用postman對配置伺服器呼叫/actuator/bus-env介面,

請求兩個服務例項的測試介面,得到結果

兩個例項的Environment物件都已經更新,如果要將@Value註解的屬性也更新,則可再呼叫配置伺服器的/actuator/bus-refresh介面。

/actuator/bus-env介面是直接更新的記憶體Environment例項屬性,如果服務重啟,則又還原到之前的配置了, 所以還是需要藉助配置倉庫來永久更新。配置更新後還需要手動呼叫介面使其生效?DevOps時代了,能自動化的就自動化吧,我們可以藉助Git的webhook機制來實現自動化。

自動化

本文開頭的“使用Spring Cloud Bus來實現服務配置動態更新的結構圖”已經示例了使用Git倉庫的webhook來觸發自動更新配置的流程。但是在Git(如Github)中,我們不能直接使用/actuator/bus-refresh介面來作為webhook(因為介面協議不一致,會出現解析異常),也有人通過提供自己的介面來作為webhook,在自己介面中再轉發請求到/actuator/bus-refresh來實現。但實際上,spring-cloud-config-monitor已經提供了對Git webhook的支援。

如下圖,spring-cloud-config-monitor提供了對Github,Gitlab,Gitee,BitBucket等的支援

1.在配置伺服器springcloud-config的pom.xml檔案中新增依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-monitor</artifactId>
</dependency>

2.在配置倉庫的設定頁面配置webhook,比如Github的配置如圖

Payload URL 配置為配置伺服器的monitor介面地址,path引數必須。如果你的配置伺服器在內網,比如做本地測試時,還需要實現一下內網穿透(如frp)。
在配置倉庫專案中修改配置屬性,提交程式碼,Github webhook就會觸發自動更新,上圖下方紅色框為觸發自動更新的記錄。

自動更新配置未生效排查

如果出現Github觸發了自動更新,但服務的配置更新未生效的情況,則需要檢視webhook的匹配規則與服務例項的ServiceID是否匹配,webhook的匹配規則為 spring.application.name:spring.cloud.config.profile:**,服務例項的ServiceID可通過spring.cloud.bus.id配置,如果沒有配置,則預設為

${vcap.application.name:${spring.application.name:application}}:${vcap.application.instance_index:${spring.application.index:${local.server.port:${server.port:0}}}}:${vcap.application.instance_id:${random.value}}

遵循app:index:id的格式,

  • app:如果vcap.application.name存在,使用vcap.application.name,否則使用spring.application.name,預設值為application
  • index:優先使用vcap.application.instance_index,如果不存在則依次使用spring.application.index、local.server.port、server.port, 預設值為0
  • id:如果vcap.application.instance_id存在,使用vcap.application.instance_id,否則給一個隨機值

我們可以在服務專案中開啟spring cloud bus的debug日誌

logging:
  level:
    org.springframework.cloud.bus: debug

通過DefaultBusPathMatcher的debug日誌來檢視是否匹配,如

DEBUG 286196 --- [7O8XC9KNWbyDA-1] o.s.cloud.bus.DefaultBusPathMatcher      : In match: hello-service:8081:c96f04c81dfce6dffaa9d116811d127c, hello-service:8081:c96f04c81dfce6dffaa9d116811d127c

如果沒有匹配則可以按照webhook的匹配規則設定spring.cloud.bus.id值或vcap.application.instance_index值,如

spring:
  application:
    name: hello-service
  cloud:
    config:
      discovery:
        service-id: config-server
        enabled: true
      profile: ${spring.profiles.active:default}
    bus:
      id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}
#或
vcap:
  application:
    instance_index: ${spring.cloud.config.profile}

配置更新未生效的另一個情況是檢視是否用了@RefreshScope註解。

@RefreshScope

細心的人會發現本文開頭的測試介面類上加了@RefreshScope註解。 @RefreshScope是Spring Cloud提供的用來實現配置、例項熱載入的註解。被@RefreshScope修飾的@Bean都是延遲載入的,即在第一次訪問(呼叫方法)時才會被初始化,並且這些bean存於快取中。當收到配置更新的訊息時,快取中的@RefreshScope bean會被清除,這樣下次訪問時將會重新建立bean,此時使用的就是最新的配置資訊,從而實現配置的熱載入。

總結

本文分別示例了使用spring boot actuator與spring cloud bus來實現服務配置的更新及兩者之間的區別, spring cloud bus一定程度上像是一個分散式的spring boot actuator。同時演示了使用webhook與spring cloud bus,monitor結合來實現配置自動更新的具體流程及可能遇到的問題。


認真生活,快樂分享!如果你覺得文章對你有幫助,歡迎分享轉發!
歡迎關注微信公眾號:空山新雨的技術空間
獲取Spring Boot,Spring Cloud,Docker等系列技術文章

相關推薦

Spring Cloud使用Spring Cloud Bus實現配置動態更新

使用Spring Cloud Config我們能實現服務配置的集中化管理,在服務啟動時從Config Server獲取需要的配置屬性。但如果在服務執行過程中,我們需要將某個配置屬性進行修改,比如將驗證碼的失效時間從五分鐘調整為十分鐘,如何將這個更新在服務端不重啟服務就能動態生效,是本文討論的內容。 Sprin

Spring Cloud配置中心服務化與高可用【Finchley 版】

outer get btn discovery ofo DC master 配置 兩個 Spring Cloud(八):配置中心(服務化與高可用)【Finchley 版】 發表於 2018-04-19 | 更新於 2018-04-26 | 本文接之前的《Spring

Spring基礎快速入門spring cloud1Spring Cloud介紹

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Java框架spring Boot學習筆記Spring相關概念

擴展 靜態 輕量級 想要 spring配置 核心 使用 oot 調用方法 Spring是開源、輕量級、一站式框架。 Spring核心主要兩部分 aop:面向切面編程,擴展功能不是修改源代碼實現 ioc:控制反轉,比如一個類,在類裏面有方法(不是靜態的方法),想要調用類

SpringSpring配置Bean

兩種 exceptio 名稱 CA exception 通過 文件系統 publish 基礎 在Spring的IOC容器裏配置Bean 配置Bean形式:基於xml文件方式、基於註解的方式 在xml文件中通過bean節點配置bean: <?xml versi

Spring Security2.4.3 Project Modules

In Spring Security 3.0, the codebase has been sub-divided into separate jars which more clearly separate different functionality areas and third-party depe

白話Spring原始碼Aware介面

我們知道spring框架中所有bean都是在工廠裡建立的,bean對自己是“無知覺”的,不知道自己叫什麼名字(bean的id或者name),從哪裡來(哪個工廠建立)。 一、為什麼需要Aware 大家看過黑客帝國電影吧,黑客帝國中機械工廠裡面“養殖”的人類,他們雖然能完成一定的功能,但是根本不

Spring Boot Mybatis 增強工具 MyBatis-Plus

1. 簡介 在上一篇文章《Spring Boot (七): Mybatis極簡配置》 中我們介紹了在 Spring Boot 中 Mybatis 的基礎使用方式,其中有一部分美中不足的是 Mybatis 本身並未提供分頁功能,還需要我們自己手動新增 PageHelper 外掛或者自己實現分頁的工具類,並且

Spring學習3Spring概述轉載

效率 調度 jpa 源代碼 一個 維護 html www hiberna 1. Spring是什麽?   Spring是一個開源的輕量級Java SE(Java 標準版本)/Java EE(Java 企業版本)開發應用框架,其目的是用於簡化企業級應用程序開發。   在面向對

Spring基礎快速入門spring boot7spring boot 2.0簡單介紹

從這篇文章開始以spring boot2為主要版本進行使用介紹。 Spring boot 2特性 spring boot2在如下的部分有所變化和增強,相關特性在後續逐步展開。 特性增強 基礎元件升級: JDK1.8+ tomcat 8+ Thymeleaf 3

Spring基礎快速入門spring boot2SPRING INITIALIZR

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Spring基礎快速入門spring boot10spring boot + sonarqube +jacoco

上篇文章我們瞭解到瞭如何使用SonarQube對建立的SpringBoot的應用進行分析,這篇文章來接著確認一些如何視覺化地確認測試覆蓋率。 SpringBootTest 需要測試覆蓋率,自然,在此之前需要有測試用例,在前面的例子中已經簡單講述了在SpringBoot應用中進行

白話Spring原始碼spring原始碼分享的思路

做事先列個大綱,這樣思路清晰了才不會亂。 這次spring原始碼系列的部落格每個字我都堅持自己手敲,然後文采不好,但是真實。希望大家喜歡。 大綱: 1.spring框架的理解 2.beanfactory:怎麼建立bean的,怎麼載入xml中bean的定義的 3.AOP 4.a

Spring boot3Spring boot中Redis 的使用

Spring boot除了常用的資料庫支援外,對nosql資料庫也進行了封裝自動化。 1 Redis介紹 Redis 是目前業界使用最廣泛的記憶體資料儲存。相比memcached, (1)Redis支援更豐富的資料結構,例如hashes,lists,sets等

Spring bootSpring boot+ mybatis 多資料來源最簡解決方案

多資料來源一般解決哪些問題?主從模式或者業務比較複雜需要連線不同的分庫來支援業務。 直接上程式碼。 配置檔案 pom包依賴,該依賴的依賴。主要是資料庫這邊的配置: mybatis.config-locations=classpath:mybatis/mybati

白話Spring原始碼spring框架的理解

一、為什麼需要Spring 我們想一下如果沒有spring框架我們是怎麼去開發web應用呢? 我估計大部分程式碼是跟業務無關而跟底層或者網路介面互動;物件,模組關係錯綜複雜;開發週期特別的長很容易流產;後期維護時程式碼會越來越爛,最後可能無法維護。。。 那spring框架給我們解決什麼問

探析Spring AOPSpring AOP的底層實現原理

一、前言   前面第一篇我們講到了AOP的概念和使用,第二篇也講到了 AOP的實現機制,在第一篇,講到了joinpoint,pointcut,aspect,weave等AOP的核心概念,接下來我們詳解分析他們的實現原理!   在動態代理 和 CGLIB 的支

Spring BootSpring Boot 整合 Spring Security (I)

1. 新增Maven依賴 在pom.xml引用spring security. <dependency> <groupId>org.springframework.boot</groupId> <artifac

探析Spring AOPSpring AOP的實現機制

  Spring AOP 屬於第二代 AOP, 採用動態代理機制和位元組碼生成技術實現 。   與最初的 AspectJ 採用編譯器將橫切邏輯織入目標物件不同,動態代理機制和位元組碼生成都是在執行期間為目標物件生成一個代理物件,而將橫切邏輯織入到這個代理物件中

Spring BootSpring Boot 整合 hibernate & JPA

轉眼間,2018年的十二分之一都快過完了,忙於各類事情,部落格也都快一個月沒更新了。今天我們繼續來學習Springboot物件持久化。 首先JPA是Java持久化API,定義了一系列物件持久化的標準,而hibernate是當前非常流行的物件持久化開源框架,Sp