技術(shù)背景
在一個(gè)分布式環(huán)境中撵颊,同類型的服務(wù)往往會(huì)部署很多實(shí)例倚舀。這些實(shí)例使用了一些配置姊舵,為了更好地維護(hù)這些配置就產(chǎn)生了配置管理服務(wù)齿税。通過(guò)這個(gè)服務(wù)可以輕松地管理成千上百個(gè)服務(wù)實(shí)例的配置問(wèn)題段直。
王阿晶提出了基于zooKeeper的配置信息存儲(chǔ)方案的設(shè)計(jì)與實(shí)現(xiàn)[1], 它將所有配置存儲(chǔ)在zookeeper上吃溅,這會(huì)導(dǎo)致配置的管理不那么方便,而且他們沒(méi)有相關(guān)的源碼實(shí)現(xiàn)坷牛。淘寶的diamond[2]是淘寶內(nèi)部使用的一個(gè)管理持久配置的系統(tǒng)罕偎,它具有完整的開(kāi)源源碼實(shí)現(xiàn),它的特點(diǎn)是簡(jiǎn)單京闰、可靠颜及、易用,淘寶內(nèi)部絕大多數(shù)系統(tǒng)的配置都采用diamond來(lái)進(jìn)行統(tǒng)一管理蹂楣。他將所有配置文件里的配置打散化進(jìn)行存儲(chǔ)俏站,只支持KV結(jié)構(gòu),并且配置更新的推送是非實(shí)時(shí)的痊土。百度內(nèi)部的BJF配置中心服務(wù)[3]采用了類似淘寶diamond的實(shí)現(xiàn)肄扎,也是配置打散化、只支持KV和非實(shí)時(shí)推送赁酝。
同構(gòu)系統(tǒng)是市場(chǎng)的主流犯祠,特別地,在業(yè)界大量使用部署虛擬化(如JPAAS系統(tǒng)酌呆,SAE衡载,BAE)的情況下,同一個(gè)系統(tǒng)使用同一個(gè)部署包的情景會(huì)越來(lái)越多隙袁。但是痰娱,異構(gòu)系統(tǒng)也有一定的存在意義弃榨,譬如,對(duì)于“拉模式”的多個(gè)下游實(shí)例梨睁,同一時(shí)間點(diǎn)只能只有一個(gè)下游實(shí)例在運(yùn)行鲸睛。在這種情景下,就存在多臺(tái)實(shí)例機(jī)器有“主備機(jī)”模式的問(wèn)題坡贺。目前國(guó)內(nèi)并沒(méi)有很明顯的解決方案來(lái)統(tǒng)一解決此問(wèn)題官辈。
功能特點(diǎn)與設(shè)計(jì)理念
disconf是一套完整的基于zookeeper的分布式配置統(tǒng)一解決方案。
它的功能特點(diǎn)是
- 支持配置(配置項(xiàng)+配置文件)的分布式化管理
- 配置發(fā)布統(tǒng)一化
- 配置發(fā)布拴念、更新統(tǒng)一化(云端存儲(chǔ)钧萍、發(fā)布):配置存儲(chǔ)在云端系統(tǒng),用戶統(tǒng)一在平臺(tái)上進(jìn)行發(fā)布政鼠、更新配置风瘦。
- 配置更新自動(dòng)化:用戶在平臺(tái)更新配置,使用該配置的系統(tǒng)會(huì)自動(dòng)發(fā)現(xiàn)該情況公般,并應(yīng)用新配置万搔。特殊地,如果用戶為此配置定義了回調(diào)函數(shù)類官帘,則此函數(shù)類會(huì)被自動(dòng)調(diào)用瞬雹。
- 配置異構(gòu)系統(tǒng)管理
- 異構(gòu)包部署統(tǒng)一化:這里的異構(gòu)系統(tǒng)是指一個(gè)系統(tǒng)部署多個(gè)實(shí)例時(shí),由于配置不同刽虹,從而需要多個(gè)部署包(jar或war)的情況(下同)酗捌。使用Disconf后,異構(gòu)系統(tǒng)的部署只需要一個(gè)部署包涌哲,不同實(shí)例的配置會(huì)自動(dòng)分配胖缤。特別地,在業(yè)界大量使用部署虛擬化(如JPAAS系統(tǒng)阀圾,SAE哪廓,BAE)的情況下,同一個(gè)系統(tǒng)使用同一個(gè)部署包的情景會(huì)越來(lái)越多初烘,Disconf可以很自然地與他天然契合涡真。 異構(gòu)主備自動(dòng)切換:如果一個(gè)異構(gòu)系統(tǒng)存在主備機(jī),主機(jī)發(fā)生掛機(jī)時(shí)肾筐,備機(jī)可以自動(dòng)獲取主機(jī)配置從而變成主機(jī)哆料。
- 異構(gòu)主備機(jī)Context共享工具:異構(gòu)系統(tǒng)下,主備機(jī)切換時(shí)可能需要共享Context吗铐【缛埃可以使用Context共享工具來(lái)共享主備的Context。
- 注解式編程抓歼,極簡(jiǎn)的使用方式:我們追求的是極簡(jiǎn)的讥此、用戶編程體驗(yàn)良好的編程方式。通過(guò)簡(jiǎn)單的標(biāo)注+極簡(jiǎn)單的代碼撰寫(xiě)谣妻,即可完成復(fù)雜的配置分布式化萄喳。
- 需要Spring編程環(huán)境
它的設(shè)計(jì)理念是:
- 簡(jiǎn)單,用戶體驗(yàn)良好:
- 摒棄了打散化配置的管理方式[2,3]蹋半,仍舊采用基于配置文件的編程方式他巨,這和程序員以前的編程習(xí)慣(配置都是放在配置文件里)一致。特別的减江,為了支持較為小眾的打散化配置功能染突,還特別支持了配置項(xiàng)。
- 采用了基于XML無(wú)代碼侵入編程方式:只需要幾行XML配置辈灼,即可實(shí)現(xiàn)配置文件發(fā)布更新統(tǒng)一化份企、自動(dòng)化。
- 采用了基于注解式的弱代碼侵入編程方式:通過(guò)編程規(guī)范巡莹,一個(gè)配置文件一個(gè)配置類司志,代碼結(jié)構(gòu)簡(jiǎn)單易懂。XML幾乎沒(méi)有任何更改降宅,與原springXML配置一樣骂远。真正編程時(shí),幾乎感覺(jué)不到配置已經(jīng)分布式化
- 可以托管任何類型的配置文件腰根,這與[2,3]只能支持KV結(jié)構(gòu)的功能有較大的改進(jìn)激才。
- 配置更新實(shí)時(shí)推送
- 提供界面良好Web管理功能,可以非常方便的查看配置被哪些實(shí)例使用了额嘿。
詳細(xì)設(shè)計(jì)
架構(gòu)設(shè)計(jì)
disconf服務(wù)集群模式:
disconf的模塊架構(gòu)圖:
每個(gè)模塊的簡(jiǎn)單介紹如下:
- Disconf-core
- 分布式通知模塊:支持配置更新的實(shí)時(shí)化通知
- 路徑管理模塊:統(tǒng)一管理內(nèi)部配置路徑URL
- Disconf-client
- 配置倉(cāng)庫(kù)容器模塊:統(tǒng)一管理用戶實(shí)例中本地配置文件和配置項(xiàng)的內(nèi)存數(shù)據(jù)存儲(chǔ)
- 配置reload模塊:監(jiān)控本地配置文件的變動(dòng)瘸恼,并自動(dòng)reload到指定bean
- 掃描模塊:支持掃描所有disconf注解的類和域
- 下載模塊:restful風(fēng)格的下載配置文件和配置項(xiàng)
- watch模塊:監(jiān)控遠(yuǎn)程配置文件和配置項(xiàng)的變化
- 主備分配模塊:主備競(jìng)爭(zhēng)結(jié)束后,統(tǒng)一管理主備分配與主備監(jiān)控控制
- 主備競(jìng)爭(zhēng)模塊:支持分布式環(huán)境下的主備競(jìng)爭(zhēng)
- Disconf-web
- 配置存儲(chǔ)模塊:管理所有配置的存儲(chǔ)和讀取
- 配置管理模塊:支持配置的上傳岩睁、下載钞脂、更新
- 通知模塊:當(dāng)配置更新后,實(shí)時(shí)通知使用這些配置的所有實(shí)例
- 配置自檢監(jiān)控模塊:自動(dòng)定時(shí)校驗(yàn)實(shí)例本地配置與中心配置是否一致
- 權(quán)限控制:web的簡(jiǎn)單權(quán)限控制
- Disconf-tools
- context共享模塊:提供多實(shí)例間context的共享捕儒。
流程設(shè)計(jì)
運(yùn)行流程詳細(xì)介紹:
與2.0版本的主要區(qū)別是支持了:主備分配功能/主備切換事件冰啃。
-
啟動(dòng)事件A:以下按順序發(fā)生。
- A3:掃描靜態(tài)注解類數(shù)據(jù)刘莹,并注入到配置倉(cāng)庫(kù)里阎毅。
- A4+A2:根據(jù)倉(cāng)庫(kù)里的配置文件、配置項(xiàng)点弯,去 disconf-web 平臺(tái)里下載配置數(shù)據(jù)扇调。這里會(huì)有主備競(jìng)爭(zhēng)
- A5:將下載得到的配置數(shù)據(jù)值注入到倉(cāng)庫(kù)里。
- A6:根據(jù)倉(cāng)庫(kù)里的配置文件抢肛、配置項(xiàng)狼钮,去ZK上監(jiān)控結(jié)點(diǎn)碳柱。
- A7+A2:根據(jù)XML配置定義,到 disconf-web 平臺(tái)里下載配置文件熬芜,放在倉(cāng)庫(kù)里莲镣,并監(jiān)控ZK結(jié)點(diǎn)。這里會(huì)有主備競(jìng)爭(zhēng)涎拉。
- A8:A1-A6均是處理靜態(tài)類數(shù)據(jù)瑞侮。A7是處理動(dòng)態(tài)類數(shù)據(jù),包括:實(shí)例化配置的回調(diào)函數(shù)類鼓拧;將配置的值注入到配置實(shí)體里半火。
-
更新配置事件B:以下按順序發(fā)生。
- B1:管理員在 Disconf-web 平臺(tái)上更新配置季俩。
- B2:Disconf-web 平臺(tái)發(fā)送配置更新消息給ZK指定的結(jié)點(diǎn)钮糖。
- B3:ZK通知 Disconf-cient 模塊。
- B4:與A4一樣种玛。
- B5:與A5一樣藐鹤。
- B6:基本與A4一樣,唯一的區(qū)別是赂韵,這里還會(huì)將配置的新值注入到配置實(shí)體里娱节。
-
主備機(jī)切換事件C:以下按順序發(fā)生。
- C1:發(fā)生主機(jī)掛機(jī)事件祭示。
- C2:ZK通知所有被影響到的備機(jī)肄满。
- C4:與A2一樣。
- C5:與A4一樣质涛。
- C6:與A5一樣稠歉。
- C7:與A6一樣。
模塊實(shí)現(xiàn)
disconf-web提供了前后端分離的web架構(gòu)汇陆,具體可見(jiàn):https://github.com/knightliao/disconf/tree/master/disconf-web
本部分會(huì)重點(diǎn)介紹disconf-client的實(shí)現(xiàn)方式怒炸。
注解式disconf實(shí)現(xiàn)
本實(shí)現(xiàn)會(huì)涉及到 配置倉(cāng)庫(kù)容器模塊、掃描模塊毡代、下載模塊阅羹、watch模塊,
使用AOP攔截的一個(gè)好處是可以比較輕松的實(shí)現(xiàn)配置控制教寂,比如并發(fā)環(huán)境下的配置統(tǒng)一生效捏鱼。關(guān)于這方面的討論可以見(jiàn)這里。
特別地酪耕,本方式提供的編程模式非常簡(jiǎn)單导梆,例如使用以下配置類的程序在使用它時(shí),可以直接@Autowired進(jìn)來(lái)進(jìn)行調(diào)用,使用它時(shí)就和平常使用普通的JavaBean一樣看尼,但其實(shí)它已經(jīng)分布式化了递鹉。配置更新時(shí),配置類亦會(huì)自動(dòng)更新狡忙。
@Service
@DisconfFile(filename = "redis.properties")
public class JedisConfig {
// 代表連接地址
private String host;
// 代表連接port
private int port;
/**
* 地址, 分布式文件配置
*
* @return
*/
@DisconfFileItem(name = "redis.host", associateField = "host")
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
/**
* 端口, 分布式文件配置
*
* @return
*/
@DisconfFileItem(name = "redis.port", associateField = "port")
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
基于XML配置disconf實(shí)現(xiàn)
本實(shí)現(xiàn)提供了無(wú)任何代碼侵入方式的分布式配置梳虽。
ReloadablePropertiesFactoryBean繼承了Spring Properties文件的PropertiesFactoryBean類,管理所有當(dāng)配置更新時(shí)要進(jìn)行reload的配置文件灾茁。對(duì)于被管理的每一個(gè)配置文件,都會(huì)通過(guò) 配置倉(cāng)庫(kù)容器模塊谷炸、掃描模塊北专、下載模塊、watch模塊 進(jìn)行配置獲取至配置倉(cāng)庫(kù)里旬陡。
ReloadingPropertyPlaceholderConfigurer繼承了Spring Bean配置值控制類PropertyPlaceholderConfigurer拓颓。在第一次掃描spring bean 時(shí),disconf會(huì)記錄配置文件的配置與哪些bean有關(guān)聯(lián)描孟。
ReloadConfigurationMonitor是一個(gè)定時(shí)任務(wù)驶睦,定時(shí)check本地配置文件是否有更新。
當(dāng)配置中心的配置被更新時(shí)匿醒,配置文件會(huì)被下載至實(shí)例本地场航,ReloadConfigurationMonitor即會(huì)監(jiān)控到此行為,并且通知 ReloadingPropertyPlaceholderConfigurer 對(duì)相關(guān)的bean類進(jìn)行值更新廉羔。
特別的溉痢,此種方式無(wú)法解決并發(fā)情況下配置統(tǒng)一生效的問(wèn)題。
主備分配實(shí)現(xiàn)
在實(shí)現(xiàn)中憋他,為每個(gè)配置提供主備選擇的概念孩饼。用戶實(shí)例在獲取配置前需要先進(jìn)行全局唯一性競(jìng)爭(zhēng)才能得到配置值。在這里竹挡,我們采用基于zookeeper的全局唯一性鎖來(lái)實(shí)現(xiàn)镀娶。
COMPARISONS
淘寶Diamond[2] | Disconf | 比較 | |
---|---|---|---|
數(shù)據(jù)持久性 | 存儲(chǔ)在mysql上 | 存儲(chǔ)在mysql上 | 都持久化到數(shù)據(jù)庫(kù)里,都易于管理 |
推拉模型 | 拉模型揪罕,每隔15s拉一次全量數(shù)據(jù) | 基于Zookeeper的推模型梯码,實(shí)時(shí)推送 | disconf基于分布式的Zookeeper來(lái)實(shí)時(shí)推送,不斷是在穩(wěn)定性耸序、實(shí)效性忍些、易用性上均優(yōu)于diamond |
配置讀寫(xiě) | 支持實(shí)例對(duì)配置讀寫(xiě)。支持某臺(tái)實(shí)例寫(xiě)配置數(shù)據(jù)坎怪,并廣播到其它實(shí)例上 | 只支持實(shí)例對(duì)配置讀罢坝。通過(guò)在disconf-web上更新配置到達(dá)到廣播寫(xiě)到所有應(yīng)用實(shí)例 | 從目前的應(yīng)用場(chǎng)景來(lái)看,實(shí)例對(duì)配置的寫(xiě)需求不是那么明顯。disconf支持的中心化廣播方案可能會(huì)與人性思考更加相似嘁酿。 |
容災(zāi) | 多級(jí)容災(zāi)模式隙券,配置數(shù)據(jù)會(huì)dump在本地,避免中心服務(wù)掛機(jī)時(shí)無(wú)法使用 | 多級(jí)容災(zāi)模式闹司,優(yōu)先讀取本地配置文件娱仔。 | 雙方均支持在中心服務(wù)掛機(jī)時(shí)配置實(shí)例仍然可以使用 |
配置數(shù)據(jù)模型 | 只支持KV結(jié)構(gòu)的數(shù)據(jù),非配置文件模式 | 支持傳統(tǒng)的配置文件模式(配置文件)游桩,亦支持KV結(jié)構(gòu)數(shù)據(jù)(配置項(xiàng)) | 使用配置文件的編程方式可能與程序員的編程習(xí)慣更為相似牲迫,更易于接受和使用。 |
編程模型 | 需要將配置文件拆成多個(gè)配置項(xiàng)借卧,沒(méi)有明顯的編程模型 | 在使用配置文件的基礎(chǔ)上盹憎,提供了注解式和基于XML的兩種編程模型 | 無(wú) |
并發(fā)性 | 多條配置要同時(shí)生效時(shí),無(wú)法解決并發(fā)同時(shí)生效的問(wèn)題 | 基于注解式的配置铐刘,可以解決并發(fā)性問(wèn)題 | 無(wú) |