title: springcloud系列之配置中心
date: 2021-06-03 12:00:30
tags:
- [配置中心]
- [config]
categories:
- [springcloud]
permalink: zxh
prefix: springcloud
背景
有多少次因為配置檔案忘記修改導致重新發布
有多少次因為無法實時修改配置導致重新發布
有多少次同一個配置在不同專案需要重複修改
有多少次因為配置導致專案啟動失敗!!!
配置服務中心
- 面對上面種種的問題
springcloud
為我們提供一種解決方案---Springcloud Config
它為分散式微服務提供了集中化的外部配置支援,配置伺服器為微服務下所有環境提供配置中心 Springcloud Config
分為服務端和客戶端、服務端就是本節介紹的物件。而客戶端就是嵌入在各個微服務中和服務端進行互動的從而實現配置的動態獲取
pom
- 還是一樣的味道我們通過
framework-root
框架來實現我們config中心,首先繼承framework-root
然後在pom中新增如下座標
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-config-server</artifactid>
</dependency>
application.yml
- 除了一些基本的引數設定以外我們需要指定config拉取的倉庫即git相關資訊
server:
port: 8070
spring:
application:
name: config-server
cloud.config.server.git:
uri: https://gitee.com/zxhTom/spring-cloud-demo
searchPaths: helloworldconfig
啟動類
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
測試
- 你沒看錯!就是這簡單或者說還是之前的配方。我們只需要引包、配置、啟動即可!這就是spring的強大之處或者說是
springboot
的開箱即用的強大之處 - 我們訪問
http://localhost:8070/master/config-server-dev.properties
就會將https://gitee.com/zxhTom/spring-cloud-demo
專案下master分支下的helloworldconfig
資料夾下的config-server-dev.properties
檔案讀取出來! - 請注意下,筆者的
config
倉庫後續會有變動。最終讀者的演示情況和筆者這裡略有不同!!!
路徑規則
- 上面我們已經可以通過介面的形式訪問到我們的配置檔案了。但是那只是其中一種方式我們換個介面同樣可以訪問到
http://localhost:8070/config-server-dev.yml
。那麼config的代理訪問肯定是按照一定規律來的。我們訪問官網,官網已經幫我們整理好了
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
- 咋一看,心裡萬馬奔騰這是啥玩意呀。再仔細看看你會發現官網總結的太到位了。首先官網整理出的是三種訪問格式:
resultful
、yml
、properties
。當我們的介面滿足其中一種格式的時候就會被config
解析出來並有對應變數管理。
- 為了充分演示出效果,小哲這裡新建了幾個配置檔案。當我們訪問如下介面時會出現哪幾種情況
http://localhost:8070/config/server-dev
. - 按照我們上面的格式進行匹配,首先是
resultful
結構的,那麼就只有一種匹配方式得出application=config;profile=server-dev,label=null
。label是可填的預設是master。
- 最終我們可以看到我們分析是沒有問題,其中多處一個
version
欄位,這個筆者猜測是git commitId
,因為我發現和提交記錄一樣。 而對應的配置檔案就是propertySources
裡的檔案。細心的朋友一定會發現這裡為什麼是個陣列呢?這裡筆者在官網上沒有找到說明但是經過測試筆者這裡整理出springcloud config
對映規則
//字尾包括兩種 。 回去找{label}分支下如下格式的檔案
{application}/{profile}.[properties|yml]
{application}.[properties|yml]
- 另外兩種方式和
resultful
差不多,只不過他返回的資訊時精簡版的。只返回配置檔案中內容的並集。這裡需要注意相同內容取前者,那麼誰先誰後呢?這就需要我們resultful
格式介面告訴我們了。
- 記住這個時候我們訪問
http://localhost:8070/config-server.properties
。 然後通過resultful
風格來確定是來源哪裡.這裡在強調下上面hello為什麼是yml
。還記得上面我提到在這麼多檔案中如果存在相同的配置會優先去首位的。這是什麼意思呢? - 我們通過
resultful
可以看出來會讀取三個檔案的配置分別是config-server.properties
、config-server.yml
、config.properties
。
- 我們在分別看下這三個檔案中的內容,hello這個key出現在兩個檔案中。然後在
resultful
介面我們可以看出config-server.yml
排在config.properties
前面,所以我們通過檔案字尾方式訪問到的資料配置hello=yml
。
配置讀取客戶端
- 上面我們也提到了關於
config
存在兩個角色,config
中心是用來統一為微服務提供服務的,剩下的就是嵌入在微服務中的。在配置微服務的config
客戶端之前我們先來梳理下springboot
的一個注意點。 springboot
的配置檔案除了在載入順序有不同之外,還有一點是檔名的區別。在springboot
中其實存在兩種配置檔名稱;我們常用的是application開頭的配置檔案(application.yml
和application.properties
)。springcloud
程式會建立一個bootstrap
上下文同時他也是application上下文的父類!它負責從外部源載入配置屬性,並解密本地外部配置檔案中的屬性。這兩個上下文共享一個Environment,它是任何Spring應用程式的外部屬性的來源。在springcloud
中bootstrap型別的配置檔案優先順序最高所以不需要擔心會被本地的配置所覆蓋。- 我們客戶端想要讀取
config-server
中心的配置資料我們就需要在bootstrap
配置檔案中配置。
bootstrap.yml
zxhtom: hello-zxhtom
spring:
cloud:
config:
label: master
name: config-server
profile: dev //這裡和config-server解析不一樣的是,他將訪問master分支下的config-server-dev.yml或者properties檔案
uri: http://localhost:8070
application.yml
zxhtom: hello-zxhtom2
server:
port: 80
tomcat:
max-threads: 10
pom
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-config</artifactid>
</dependency>
測試
- 首先引入
pom
包這裡大家應該都沒有問題,其次我們在application.yml
和bootstrap.yml
兩個配置檔案中配置相同的東西。這個時候在bootstrap中不配置config
東西。此時我們訪問zxhtom
引數得到的結果是application中的。當我們將config
配置加進來之後我們訪問到的是git遠端倉庫的東西。關於演示筆者這裡就不演示了。因為上面配置完成之後我們只需要寫個介面獲取引數就可以了。
小瑕疵
-
但是存在一個小瑕疵,當我們遠端倉庫配置修改後我們的服務也需要跟著修改!這好坑啊,感情玩了半天我還在原地打轉啊。除了解決多模組相同配置重複修改的問題,重啟的問題還是沒能解決。難道我們就只能如此了嗎?
-
上面我們已經實現
config-server
來讀取遠端倉庫配置了。也實現了客戶端通過config-server
讀取遠端配置了。但是當我們修改git遠端倉庫上配置時,我們的config-server
會實時的修改配置值,客戶端確無法實時更新!解決辦法就是重啟。
動態重新整理
- 發現問題才能不斷進步當然前提你得承認問題!這是一個偉大的哲學家說的(我自己) 。
- 首先我們需要引入
actuator
模組,這個我們在講解hystrix
模組的時候在父專案root中引入了。當時筆者一直出了在高版本中actuator中需要加入actuator字首。 - 然後我們在獲取配置的介面類上新增
@RefreshScope
。 記住這裡一定要在這裡加哦!!! - 好了,到這裡我們就解決了,現在啟動我們的config客戶端,在這裡我們是
order
模組。啟動之後通過http://localhost/order/config/getConfig
獲取zxhtom這個值。
仍然不足
- 上面我們基於
actuator
實現了動態重新整理,但是這個動態重新整理並不是自動重新整理還是需要我們認為參與。實際專案生產使用中會有很多個微服務充電config-client角色。那麼我們每次更新git倉庫內容時是不是需要誒個呼叫介面呢?這顯然是不行的。我也說了存在問題才能優化。那麼我們該如何解決
奇技淫巧
脫離git
- 在
config-server
中我們通過spring.cloud.config.server.git.uri
中指定git遠端倉庫。如果我們在內網環境開發而且內網中我們沒有自己搭建git服務呢。我們可以配置本地地址也可以實現讀取指定外部倉庫的。
spring.cloud.config.server.git.uri=file://xxxxxx/repository
多倉庫
spring.cloud.config.server.git:
uri: https://gitee.com/zxhTom/spring-cloud-demo
searchPaths: helloworldconfig
repos:
dev:
pattern: dev/*
uri: file:///D:\test\repository\spring-cloud-demo
searchPaths: helloworldconfig
- 上述配置
spring.cloud.config.server.git.uri
是預設的倉庫配置。然後根據repos
來進行多倉庫的配置。repos
下跟了多少個就說明是多少個環境配置。比如我們上面的配置repos
下只有dev
一個配置,這個dev
就是我們用於dev
的環境。他的匹配模式是任何已dev
開頭的都將使用dev
這個配置的倉庫來進行我們上面匹配規則分析。
新增許可權
-
如果你的公司沒有單獨部署git。如果你使用的就是
github
這種公網性質。那麼將我們專案中的配置放在這種地方是不是有點不安全呢?你的所有的服務的密碼都被公開了。這樣是極度不安全。那麼我們要麼自己單獨部署git。要麼將配置檔案這個專案設定成私有 -
專案配置成私有我們config-server所在的服務可以通過ssh方式進行配置專案uri 。
-
spring: cloud: config: server: git: username: xxxx password: xxxx
-
我們也可以通過如上配置方式將我們專案的使用者名稱和密碼配置,然後在通過http方式進行訪問。這樣也是可以的。
指定本地倉庫位置
- 當我們通過介面訪問獲取遠端倉庫配置資訊的時候,實際上config幫我們將遠端倉庫的檔案拉取到本地路徑上了。這個我們通過觀察日誌就可以看得出來。
- 可以證實我們沒訪問一次介面
config都會重新整理本地檔案庫的。但是本地檔案儲存的位置其實是不固定的,專案每次啟動當前專案所在的目錄都會發生隨機改變。檔案路徑為
config-repo-隨機id。會出現這麼一種情況當我們重啟的時候git掛了這個時候我們將無法獲取但是因為隨機id的原因我們將獲取不到配置資訊了。所以
config` 可以讓我們指定這個路勁。
spring.cloud.config.server.git.basedir: xxxxx
分模組讀取配置
- 實際分散式專案中我們會有很多模組,如果我們都將放在同一層級的話會顯得很多。這用並不是不能使用但是為了方便管理我們還是希望能夠進行分類管理不同的服務請求過來進不同檔案中進行匹配。
spring.cloud.config.server.git.searchPaths: '{application}'
- 而application就是我們上文提到的通過地址分析中得到的那個application 。注意這裡一定要加引號
總結
springcloud config
模組極大的簡化了我們微服務中重複配置的問題,預設使用的git來實現公共服務的獲取的當然他也是支援svn
,關於svn
的整合呢筆者這裡沒有指出因為現在使用svn
的公司應該很少了。如果非要使用svn
的話也很簡單。將uri
地址換成svn
的就可以了。前提引入如下包
<dependency>
<groupid>org.tmatesoft.svnkit</groupid>
<artifactid>svnkit</artifactid>
<version>1.8.10</version>
</dependency>