1. 程式人生 > >Spring Cloud第十一篇 | 分散式配置中心高可用

Spring Cloud第十一篇 | 分散式配置中心高可用

本文是Spring Cloud專欄的第十一篇文章,瞭解前十篇文章內容有助於更好的理解本文:

  1. Spring Cloud第一篇 | Spring Cloud前言及其常用元件介紹概覽

  2. Spring Cloud第二篇 | 使用並認識Eureka註冊中心

  3. Spring Cloud第三篇 | 搭建高可用Eureka註冊中心

  4. Spring Cloud第四篇 | 客戶端負載均衡Ribbon

  5. Spring Cloud第五篇 | 服務熔斷Hystrix

  6. Spring Cloud第六篇 | Hystrix儀表盤監控Hystrix Dashboard

  7. Spring Cloud第七篇 | 宣告式服務呼叫Feign

  8. Spring Cloud第八篇 | Hystrix叢集監控Turbin

  9. Spring Cloud第九篇 | 分散式服務跟蹤Sleuth

  10. Spring Cloud第十篇 | 分散式配置中心Config

一、前言

    ​為了保證配置中心服務的高可用,將配置中心服務端做成一個微服務,將其叢集化,從而達到高可用,當你部署了多個Config Server例項並預期一個或多個例項不時不可用時,為確保高可用性,你可以指定多個URL(作為spring.cloud.config.uri屬性下的逗號分隔列表),也可以讓所有例項在Eureka等Service Registry中註冊(如果使用發現優先Bootstrap模式)。注意:只有在Config Server未執行時(即應用程式已退出時)或發生連線超時時,才能確保高可用性,例如:如果Config Server返回500(內部伺服器錯誤)響應或Config Client從Config Server收到401(由於憑據錯誤或其他原因),則Config Client不會嘗試從其他URL獲取屬性,這種錯誤表示使用者問題而不是可用性問題。

​    ​上一篇文章《Spring Cloud第十篇 | 分散式配置中心Config》講述了一個服務如何從配置中心讀取檔案,上一篇案例只是通過client直接訪問server,地址直接寫死,這種方式顯然不夠靈活,當服務例項很多時,都從配置中心讀取檔案,如果配置中心服務端地址變動的話,那我們所有的服務都啟動不起來了,都需要變更配置中心服務端地址,特別麻煩,由於微服務使用了註冊中心,以及註冊中心的優點等,我們可以結合Eureka註冊中心,將配置中心做成微服務,將其叢集化部署,達到配置中心的高可用,架構圖如下:

二、改造配置中心服務端

1、添加註冊中心客戶端依賴

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、主啟動類上添加註解@EnableEurekaClient

3、在application.yml檔案中新增Eureka相關配置

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8700/eureka
    #客戶端每隔30秒從Eureka服務上更新一次服務資訊
    registry-fetch-interval-seconds: 30
    #需要將我的服務註冊到eureka上
    register-with-eureka: true
    #需要檢索服務
    fetch-registry: true
  #心跳檢測檢測與續約時間
  instance:
    #告訴服務端,如果我10s之內沒有給你發心跳,就代表我故障了,將我剔除掉,預設90s
    #Eureka服務端在收到最後一次心跳之後等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
    lease-expiration-duration-in-seconds: 10
    #每隔2s向服務端傳送一次心跳,證明自已依然活著,預設30s
    #Eureka客戶端向服務端傳送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
    lease-renewal-interval-in-seconds: 2
    # 啟用ip配置 這樣在註冊中心列表中看見的是以ip+埠呈現的
    prefer-ip-address: true
    # 例項名稱  最後呈現地址:ip:2002
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

4、然後啟動config server服務端就行了

三、改造配置中心客戶端

1、改造步驟同1-1,1-2,1-3,然後在application.yml檔案中將spring.cloud.config配置修改為如下樣子

spring:
  cloud:
    config:
      #uri則表示配置中心的地址
      #uri: http://localhost:8888
      #注:config 客戶端在沒有 spring.cloud.config.name屬性的時候,服務端{application} 獲取的是客戶端
      #spring.application.name的值,否則,獲取的是 spring.cloud.config.name的值。
      #1)、當沒有spring.cloud.config.name時,客戶端獲取的是spring.application.name 所對應的git庫中的檔案,並且只能獲取一個檔案
      #2)、當一個專案中有需求要獲取多個檔案時,就需要用到spring.cloud.config.name這個屬性,以逗號分割
      name: configclient
      profile: dev
      #label對應了label部分
      label: master
      discovery:
        #表示開啟通過服務名來訪問config-server
        enabled: true
        #則表示config-server的服務名
        service-id: tmgsp-config-server

2、檢視註冊中心上註冊的服務

3、然後訪問http://localhost:8881/index可以看到相同效果,如果需要配置中心高可用,只需要將配置中心啟動多個例項就行了。

四、失敗快速響應與重試

1、失敗快速響應

    Spring Cloud Config的客戶端會預先載入很多其他資訊,然後再開始連線Config Server進行屬性的注入。不作任何額外配置的情況下,失敗響應有點遲鈍,舉個簡單的例子,關掉config-server,我們直接啟動config-client,此時啟動會報錯,但是報錯時間較晚,當我們構建的應用較為複雜的時候,可能在連線Config Server之前花費較長的啟動時間,而在一些特殊場景下,我們又希望可以快速知道當前應用是否能順利地從Config Server獲取到配置資訊,這對在初期構建除錯環境時,可以減少很多等待啟動的時間。要實現客戶端優先判斷Config Server獲取是否正常,並快速響應失敗內容,只需在Config客戶端的bootstrap.yml中配置引數spring.cloud.config.failFast=true即可。

    此時不啟動config-server直接啟動config-client依然會報錯,但是我們看到報錯時間較早,系統都沒列印幾條啟動日誌。

2、重試

    上面我們提過了當Config Server宕機或是客戶端配置不正確導致連線不到Config Server而啟動失敗的情況,快速響應的配置可以發揮比較好的效果。但是,如果網路波動等其他間歇性原因導致的問題,直接啟動失敗似乎代價有些高。所以Config客戶端還提供了自動重試的功能,在開啟重試功能前,先確保已經配置了(確保開啟失敗快速響應)spring.cloud.config.failFast=true在進行下面操作。

2-1、在客戶端新增依賴

<!--連線config-server重試機制相關依賴-->
<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2-2、不需要再做其他任何配置,啟動客戶端應用,在控制檯中可以看到如下內容。客戶端在連線Config Server失敗之後,會繼續嘗試,直到第6次失敗後,才返回錯誤資訊。通過這樣的重試機制,可以避免一些間歇性問題引起的失敗導致客戶端應用無法啟動的情況。檢視日誌如下,測試的時候切記Config Server需要在註冊中心沒有剔除掉,要是剔除掉那就沒的說了。

INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [tbeatExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_SPRINGCLOUD-CONFIG-CLIENT/172.20.10.2:8881 - Re-registering apps/SPRINGCLOUD-CONFIG-CLIENT
INFO 9996 --- [tbeatExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_SPRINGCLOUD-CONFIG-CLIENT/172.20.10.2:8881: registering service...
INFO 9996 --- [tbeatExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_SPRINGCLOUD-CONFIG-CLIENT/172.20.10.2:8881 - registration status: 204
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://172.20.10.2:8888/
INFO 9996 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://172.20.10.2:8888/. Will be trying the next url if available
ERROR 9996 --- [           main] o.s.boot.SpringApplication               : Application run failed

2-3、從日誌上可以看出Config client一共嘗試了六次去訪問Config server,六次都失敗了才拋異常和重試機制相關的配置有如下四個:

# 配置重試次數,預設為6
spring.cloud.config.retry.max-attempts=6
# 間隔乘數,預設1.1
spring.cloud.config.retry.multiplier=1.1
# 初始重試間隔時間,預設1000ms
spring.cloud.config.retry.initial-interval=1000
# 最大間隔時間,預設2000ms
spring.cloud.config.retry.max-interval=2000

五、動態重新整理配置

1、有的時候,我動態的更新了Git倉庫中的配置檔案,那麼我如何讓我的config-client能夠及時感知到呢?方式很簡單,首先在config-client中新增如下依賴:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

由於我們父模組(springcloud-learn)依賴中已經引入該依賴,所以可以省略不引入。

該依賴中包含了/refresh端點的實現,我們將利用這個端點來重新整理配置資訊。

2、在需要重新整理的Bean上新增@RefreshScope註解,不然客戶端不知道重新整理哪裡

3、然後需要在application.yml中配置暴露/refresh端點

management:
  endpoints:
    web:
      exposure:
        include: ["info","health","refresh"]

4、然後啟動訪問http://localhost:8881/index

5、修改碼雲上的configclient-dev.yml檔案,因為我們客戶端載入的是這個配置檔案

6、然後用postman工具向http://localhost:8881/actuator/refresh地址傳送POST請求(該端點只接受post請求,日誌上可以看出),結果如下:

7、重新訪問http://localhost:8881/index顯示內容如下

​​

 

詳細參考案例原始碼:https://gitee.com/coding-farmer/spirngcloud-learn