SpringCloud實戰7-Config分散式配置管理(轉)
SpringCloud實戰7-Config分散式配置管理
分散式環境下的統一配置框架,已經有不少了,比如百度的disconf,阿里的diamand
官方文件對spring Cloud Config的描述如下:
Spring Cloud Config為分散式系統中的外部配置提供伺服器和客戶端支援,使用Config Server,您可以在所有環境中管理應用程式的外部屬性。客戶端和伺服器上的概念對映與Spring Environment和PropertySource抽象相同,
因此它們與Spring應用程式非常契合,但可以與任何以任何語言執行的應用程式一起使用。隨著應用程式通過從開發人員到測試和生產的部署流程,您可以管理這些環境之間的配置,並確定應用程式具有遷移時需要執行的一切。
伺服器儲存後端的預設實現使用git,因此它輕鬆支援標籤版本的配置環境,以及可以訪問用於管理內容的各種工具。很容易新增替代實現,並使用Spring配置將其插入。
1.為什麼要配置中心?
一個應用中不只是程式碼,還需要連線資源和其它應用,經常有很多需要外部設定的項去調整應用行為,如切換不同的資料庫,設定功能開關等。
隨著系統微服務的不斷增加,首要考慮的是系統的可伸縮、可擴充套件性好,隨之就是一個配置管理的問題。各自管各自的開發時沒什麼問題,到了線上之後管理就會很頭疼,到了要大規模更新就更煩了。
而且你不可能停止你的服務叢集去更新的你配置,這是不現實的做法,因此springcloud配置中心就是一個比較好的解決方案,下圖就是一個springcloud配置中心的解決方案:
常見的配置中心的實現方法有:
1.硬編碼(缺點:需要修改程式碼,風險大)
2.放在xml等配置檔案中,和應用一起打包(缺點:需要重新打包和重啟)
3.檔案系統中(缺點:依賴作業系統等)
4.環境變數(缺點:有大量的配置需要人工設定到環境變數中,不便於管理,且依賴平臺) 5.雲端儲存(缺點:與其他應用耦合)
Spring Cloud Config就是雲端儲存配置資訊的,它具有中心化,版本控制,支援動態更新,平臺獨立,語言獨立等特性。其特點是:
1.提供服務端和客戶端支援(spring cloud config server和spring cloud config client) 2.集中式管理分散式環境下的應用配置 3.基於Spring環境,無縫與Spring應用整合 4.可用於任何語言開發的程式 5.預設實現基於git倉庫,可以進行版本管理 6.可替換自定義實現
spring cloud config包括兩部分:
1.spring cloud config server 作為配置中心的服務端:
1.拉取配置時更新git倉庫副本,保證是最新結果
2.支援資料結構豐富,yml, json, properties 等
3.配合 eureke 可實現服務發現,配合 cloud bus 可實現配置推送更新
4.配置儲存基於 git 倉庫,可進行版本管理
5.簡單可靠,有豐富的配套方案
2.Spring Cloud Config Client 客戶端:
1.Spring Boot專案不需要改動任何程式碼,加入一個啟動配置檔案指明使用ConfigServer上哪個配置檔案即可
SpringCloud Config與百度的disconf之類的有很大不同,主要區別在於下面三點:
1.配置的儲存方式不同:disconf是把配置資訊儲存在mysql、zookeeper中,而spring cloud config是將配置儲存在git/svn上 (即:配置當成原始碼一樣管理)
2.配置的管理方式不同:spring cloud config沒有類似disconf的統一管理介面,既然把配置都當成git之類的原始碼來看待了,git的管理介面,就是配置的管理介面
3.配置變化的通知機制不同:disconf中配置變化後,依賴zk的事件watcher來通知應用,而spring cloud config則是依賴git每次push後,觸發webhook回撥,最終觸發spring cloud bus(訊息匯流排),然後由訊息匯流排通知相關的應用。
從配置變化的通知機制上看,如果有100個應用節點,都依賴於統一配置,如果修改了配置,只想讓某幾個節點"灰度"更新配置,spring cloud config server更容易做到,這一點相對disconf更靈活
首先SpringCloud Config 是分為Server端和Client端的,Server端負責管理配置,Client端用來載入配置。我們每一個為服務都要整合一個Client端的。上面也提到過。因此,我們現在看一下Config的Server端的Demo實現。
首先在原來的專案中新建一個springcloud-config-server模組,並且引入相關依賴,如下:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>1.4.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.3.5.RELEASE</version> </dependency>
我們可以看到引入了Eureka,為什麼呢?很明顯是為了高可用。
接著在啟動類上面加入@EnableConfigServer註解,表示這裡是配置中心服務。還有Eureka的客戶端的註解程式碼如下:
@SpringBootApplication @EnableConfigServer @EnableDiscoveryClient public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } }
application.yml配置如下:
server: port: 7000 #服務名字 spring: application: name: config-server cloud: config: server: git: #git 倉庫的地址 uri: https://gitee.com/xxxx/springcloud-config.git #git 倉庫的賬號密碼 username: xxx password: xxx #加入註冊中心,實現高可用 eureka: client: service-url: defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
注意了,前提是你必須要在git倉庫中先建立一個倉庫,然後配置兩個配置,一個開發dev,一個測試test 如下圖:
dev的內容如下:
test的內容如下:
好了,讓我們把springcloud-config模組啟動起來,啟動啟動類,執行,訪問git倉庫中的cloud-config-dev.properties,如下:
接下來,我們進行springcloud Config的Client端的Demo,如下:
首先引入Client端的相關依賴,如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>1.4.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.3.5.RELEASE</version> </dependency>
這裡提一下,為什麼需要引入前面的actuctor依賴,因為,我們Client端需要在不重啟的情況下,及時更新拉取載入配置中心的改變,然後修改記憶體中的配置的值。
接著在Client啟動類的打上@EnableDiscoveryClient的註解,來註冊到註冊中心去,如下:
@SpringBootApplication @EnableDiscoveryClient public class ConfigClientApplication { public static void main(String[] args) { SpringApplication.run(ConfigClientApplication.class, args); } }
接下來這步驟很關鍵,就是要將Client模組下的application.yml檔案改為bootstrap.yml,這是很關鍵的,因為bootstrap.yml是比application.yml先載入的。bootstrap.yml優先順序高於application.yml。就好比如,你應用程式都跑起來了,你配置還沒載入,這不是扯淡嗎?
如下:
server: port: 7005 spring: application: name: cloud-config cloud: config: #啟動什麼環境下的配置,dev 表示開發環境,這跟你倉庫的檔案的字尾有關,比如,倉庫配置檔案命名格式是cloud-config-dev.properties,所以profile 就要寫dev profile: dev #面向服務,允許被發現 discovery: enabled: true #這個名字是Config Server端的服務名字,不能瞎寫。 service-id: config-server #註冊中心 eureka: client: service-url: defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/ #是否需要許可權拉去,預設是true,如果不false就不允許你去拉取配置中心Server更新的內容 management: security: enabled: false
接著寫一段測試程式碼,如下,建立一個測試Controller,程式碼如下:
@RestController //這裡面的屬性有可能會更新的,git中的配置中心變化的話就要重新整理,沒有這個註解內,配置就不能及時更新 @RefreshScope public class TestController { @Value("${name}") private String name; @Value("${age}") private Integer age; @RequestMapping("/test") public String test(){ return this.name+this.age; } }
接著啟動啟動該工程,執行結果如下:
首先我們我們先看沒更新配置之前的值,如下:
接著我們去git倉庫中修改age的值為24,再用postman來發送post請求localhost:7005/refresh,如下:
可以看到postman返回config.client.version資訊,表示告知Client,遠端的倉庫中的配置中心已經更新了的配置版本資訊,改變的值為age。
接著我們繼續重新整理瀏覽器,localhost:7005/test,看一下年齡是否更新了,如下:
可以看到年齡跟新到24了。
但是這樣就好了嗎?雖然服務沒有重啟,但是我們要一個服務一個服務的傳送post請求,我們能受的了嗎?這比之前的沒配置中心好多了,那麼我們如何繼續避免挨個挨個的向服務傳送Post請求來告知服務,你的配置資訊改變了,需要及時修改記憶體中的配置資訊。
這時候我們就不要忘記訊息佇列的釋出訂閱模型。讓所有為服務來訂閱這個事件,當這個事件發生改變了,就可以通知所有微服務去更新它們的記憶體中的配置資訊。這時Bus訊息匯流排就能解決,這留到下一篇隨筆講解。