假如說我們的配置從遠程倉庫獲取失敗了,那麼該如何去處理呢?這裏就要使用到 Spring Cloud Config 爲我們提的動態刷新重試功能了,Spring Cloud Config 是服務化的。那麼什麼是服務化呢?
服務化
我們在前面的配置中,當 Config Client 需要從 Config Server 上獲取配置數據時,我們都是直接在 Config Client 的配置文件中寫上 Config Server 的地址,類似下面這種架構:
這種寫法相當於將 Config Client 和 Config Server 綁定死了,以後 Config Server 的地址不能變,Config Server 也不能掛,否則 Config Client 就獲取不到信息了,而且這種方式也破壞了我們微服務的整體架構,即服務之間互相調用,獲取對方的信息都是去服務註冊中心上獲取,所以我們要對這種結構進行改造,改造成下面這種結構:
當 Config Server 啓動時,將自己註冊到服務註冊中心 Eureka 上,所有 Config Client 都從 Eureka 上去獲取 Config Server 的信息,這樣我們就成功將 Config Server 和 Config Client 解耦了,Eureka 在這裏依然扮演了數據中心的角色。
那麼下面我們來演示如何服務化,大家可以根據上一篇的例子進行改造。當然也可以再創建一個項目來實現。這裏我選擇重新創建來帶着大家來搭建。
首先我們依然是創建一個cloudConfig-fwh普通maven工程來作爲父工程。然後再從cloudConfig-fwh中創建一個普通的文件夾configRepo來存放github配置文件,然後再分別創建eureka、config_server、config_client。
創建好後,項目結構如下:
然後我們分別將config_client 和 config_server 註冊到eureka實例上。
我們訪問localhost:7000
發現已經註冊上去了。
那麼我們還需要對Config Client配置,這裏我們在bootstrap.yml中配置,bootstrap.yml優先級比application.yml高,spring cloud config 優先配置都會放在這裏:
bootstrap.yml 配置如下:
spring:
application:
name: config-server
# 本地配置
# profiles:
# active: native
cloud:
config:
profile: dev
label: master
discovery:
service-id: config-server3
enabled: true
server:
port: 8002
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
這裏新增的兩個配置我說一下,其中discovery.service-id
代替了原來的cloud.config.uri
原來的uri需要寫很長。而且如果ip地址端口號發生了變化,那麼還需要去Config Server去修改,這裏使用了service-id完美瞭解決了這個問題。通過service-id去eureka中心尋找Config Server的實例。discovery.enabled=true
是開啓通過eureka來獲取Config Server。
注意這裏有一個小坑。就是這個spring.application.name的名稱是你在github倉庫的配置文件的前綴如下圖:
這裏取config-server就可以了。
配置好了後,我們訪問http://localhost:8002/love
訪問結果如下:
這樣就訪問成功了,說明我們的配置沒有問題。下面我們來說一下動態刷新。
動態刷新
接下來我們再來看一下配置文件動態刷新的問題,當 Git 倉庫中配置文件發生改變後,如果我們刷新 Config Server 中的請求地址,會發現數據也跟着變化了,即 Config Server 是能夠及時感知到配置文件的變化的,但是這種感知卻不能夠傳遞到 Config Client 中去,即 Config Client 是無法及時感知到配置文件的變化的,默認情況下,只有 Config Client 重啓,才能夠加載到最新的配置文件數據,如何讓 Config Client 也能動態刷新配置數據呢?
我們只需要在Config Client 中加入如下依賴就能動態刷新配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
添加完成後我們還需要對refresh接口暴露,這裏注意,除了G版本的Cloud需要額外手動的暴露refresh接口外,其它版本的Cloud不用配置下面這段配置來進行手動暴露
management:
endpoints:
web:
exposure:
include: 'refresh'
這裏配置好了後,我們對HelloController增加一個註解@RefreshScope
當調用refresh
接口當時候動態刷新:
@RefreshScope
@RestController
public class HelloController {
@Value("${love}")
String love;
@GetMapping("/love")
public String name() {
return love;
}
}
配置好了後,我們重啓Config Client項目,然後可以看到idea的控制檯/actuator/refresh
接口已經暴露出來了。
這個接口用來動態刷新配置文件。
當然配置好了這個動態刷新接口,我們肯定要訪問來測試下。接口是否正常。
我們訪問http://localhost:8002/actuator/refresh
注意這裏使用post請求訪問,如果如下圖一樣就說明接口正常:
但細心的人可能這裏會發現一個問題,不重啓Config Client的情況下,也能實現動態刷新配置,但是所有的微服務都要一個個的去發送/actuator/refresh
接口請求,很麻煩,那麼有什麼簡便的方式呢?肯定是有的下面我會介紹。
請求失敗重試
請求失敗了肯定要重試啊,不可能失敗了,就讓它一直失敗。這肯定是不行的。細心的朋友看過我之前的文章的話,我是講了如何失敗重試的,比如網絡的波動,當網絡質量很差的情況下,就會導致服務調用的失敗。那麼我們就要做到請求失敗了,就要重試。
要實現失敗重試也是非常簡單的,之前看過我文章的朋友,肯定知道這裏需要加兩個依賴:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
加上這個依賴後,我們需要在Config Client 的bootstrap.yml中加入如下配置:
fail-fast: true
這個配置的意思是失敗快速響應,在默認情況下 我們的Config Client 去訪問Config Server 失敗時候,並不會馬上報錯
而是要等到使用到Config Server 的某個數據
的時候纔會報錯
,通俗的意思就是我們之前不是有個love變量嗎?如果這個love變量並不存在,而我們的Config Client又在調用使用的話,那麼就會報錯並拋出異常。所以當我們的Config Client 訪問 Config Server 失敗的時候,就要開啓快速響應,這裏可以是失敗重試,也可以拋出自定義異常信息。
添加完這個配置之後,爲了演示執行效果,接下來我們再做一點點修改,由於目前我們的 Config Server 是有安全認證的,Config Client 必須要有用戶名密碼才能訪問到 Config Server 中的數據。我們暫時先註釋掉 Config Client 中訪問 Config Server 的用戶名密碼,即如下兩行:
#spring:
# cloud:
# config:
# username: jishu
# password: 123456
這裏的username 和 password 是在Config Server 中配置的Security的賬戶密碼信息,這裏我們註釋掉後,重啓Config Client 項目,我們來看下失敗重試的效果:
可以看到,一共發了6次請求,第一失敗後,還繼續重試了5次,這就是默認的請求策略,我們可以配置請求策略:
spring:
cloud:
config:
retry:
initial-interval: 1000
multiplier: 1.1
max-interval: 2000
這四個配置解釋如下:
- max-attempts 表示最大請求次數,默認值爲 6 ,就是大家在上圖看到的情況
- initial-interval 表示請求重試的初始時間間隔
- multiplier 表示時間的間隔乘數,由於網絡抖動一般都是有規律的,爲了防止請求重試時連續的衝突,我們需要一個時間間隔乘數,這裏我設置了間隔乘數爲 1.2 ,表示第一次重試間隔時間爲 1 s,第二次間隔時間爲 1.2 秒,第三次間隔時間爲 1.44 秒…
- max-interval 表示重試的最大間隔時間
開啓了請求重試機制之後,即使在弱網環境下,我們也能有效保證服務的可用性。
總結
本文主要向大家介紹了分佈式配置中心 Spring Cloud Config 中三個常見的問題,服務化、配置數據動態刷新以及請求失敗重試。服務化降低了 Config Server 和 Config Client 之間的耦合度,使我們的項目架構更加規範;動態刷新則讓我們在不重啓 Config Client 的情況下,能夠刷新配置數據;最後的請求重試則保證了弱網環境下服務的可用性,在實際生產項目中,這三個基本上也都是必配的,大家需要認真掌握。