配置(configuration) 這個概念每個技術人都不陌生,可以說一個不提供幾個配置參數的系統都不好意思上線跟别的系統打招呼。那麼為什麼會是這個樣子呢,究其本質是我們人類無法掌控和預知一切,映射到軟體領域上,我們總是需要對系統的某些功能特性預留出一些控制的線頭,以便我們在未來需要的時候,可以人為的撥弄這些線頭進而控制系統的行為特征,我把它叫做 “系統運作時(runtime)飛行姿态的動态調整“。
舉個簡單的例子,
loglevel = info
系統正常飛行的時候,我們希望其隻輸出info級别的日志資訊,在生産環境中我們甚至希望隻輸出warning/error級别的日志,系統出毛病了,再将日志輸出動态的調整成包含診斷資訊的debug級别或者trace級别。
<a></a>
在那個單機即系統的時代,我們基本都是在用配置檔案來存儲配置項,一個配置項,就是如上面的loglevel那樣的一個含有 = 表達式,如下:
一般來說<code>config_value</code>應該是一個有限空間的值集合,應該是有選擇餘地的,如果<code>config_value</code>沒得選擇,那麼我隻能認為這個配置項一定特麼在逗我。而一個配置檔案一般是一組配置項的集合或者叫配置集,一個系統根據邏輯子產品劃分,可以有1到多個配置檔案。如下圖 :
在集中式開發時代,配置檔案基本足夠用了,因為那時配置的管理通常不會成為一個很大的問題,簡單一點來說,系統上了生産之後,如果需要修改一個配置,登入到這台生産機器上,vi修改這個配置檔案,然後reload一下并不是什麼很大的負擔。
如下圖:
是以曾經的企業級應用架構标準j2ee裡并沒有制定關于配置管理這一塊的任何标準。
當然一些follow j2ee标準的廠商,如以前oracle的中間件weblogic在實際實踐時,因為很多大企業客戶的環境也挺複雜的,是以weblogic在這一塊還是做了一些工作,其支援一個叫做deployment plan的特性,如下圖:
其背後的本質就是開發人員(dev)打出來的應用war包裡面的配置檔案都是一些placeholder, 在部署人員(ops)部署war包的時候,為目标環境提供與之比對的的depoloy plan xml檔案,weblogic server本身在deploy這個stage将war包配置項的placeholder值替換成plan裡面的值。
關于什麼是分布式系統,本文不再贅述,毫無疑問今天阿裡的系統就是一個大型的、服務化的、複雜的、分布式系統實作之一。在這個領域有3本書值得反複閱讀<<分布式系統概念與設計>> <<分布式系統原理與泛型>> 以及 distributed systems for system architects,有意思的是這三本書隻有最後一本在21.3小節簡單的提了一下 configuration of distributed systems,裡面簡單的說了一下靜态配置和動态配置的概念和差別 “…system configuration may be static or dynamic…”. 這說明什麼? 這說明我們阿裡技術人包括我們中間件今天面臨的很多問題和領域已經進入深水區,已經沒有人會直接給你提供這個領域清晰的解決方案,我們自己正站在前沿,而我們的成功的或者失敗的探索,其經驗和成果都應該總結并分享給整個業界。
在過去的大約15年左右,軟體工程學在如何持續演進軟體以适應一直要變的需求的方法論上有了很多的突破和大量的實踐,在這個領域,從面向對象設計方法論,到極限程式設計,到靈活開發、持續內建、單元測試等等,理論和實踐都已經比較成熟了,關鍵是配合這一套方法論的配套的工具和軟體集都變得非常的成熟。
這裡面的一個非常有意思的東西是關于系統的演進或者進化論(software evolution),一個系統或者說軟體從被創造出來之後會經曆研發、測試、到最後的go live,上了生産系統。那麼這個之後,如何持續并且無痛的為其添加新行為或者調整已有行為的表現特征? 這确實非常複雜,尤其是要達到無痛的這個目标,畢竟線上系統,調整即意味着可能出故障。系統的動态配置管理毫無疑問是其中的一個小部分,如果每一個系統行為的任何一個微調都需要将整個系統停機,重新開機或者甚至重新建構、釋出部署來實作,那要達到無痛這個目标恐怕難度更高。
在分布式系統中,一次建構、釋出、上線是非常非常重的一個過程,它不像單機時代那樣重新開機一台機器、一個程序就可以了,在分布式系統中,它涉及到将軟體包(例如war)分發到可能超過幾千台機器,然後将幾千台機器上的應用程序一一重新開機這麼一個過程,超過2000台機器的一個應用一次完整的釋出過程需要多長時間,相信很多核心系統的小二都深有體會。
那麼如何在不停應用叢集的情況下,調整整個叢集的運作時的行為特征(即系統運作時的飛行姿态),是一個分布式系統必須回答的一個問題。從這個角度講, 我們認為:
現在我們很容易了解,其實我們平時常見的分布式系統的配置變更,諸如:
線程池、連接配接池大小
開關、預案、限流配置
togglefeature
資料源主備容災切換
路由規則
我是等等等等
背後的本質都是在做分布式系統運作時行為特征(飛行姿态)的調整。
是的,你一定注意到了,這裡的說法跟圖檔上的有點不一樣,這裡想強調的是,未必都需要配置中心,在一個分布式系統規模還較小時,比如一個公司就二個應用叢集,那無論你是用配置檔案+auto-reload還是用redis,zookeeper什麼都可以,這個動态配置管理系統不一定要是一個獨立存在的,可以跟其它的系統,例如注冊中心,甚至作為消息中間件的一個子系統都沒有關系。但是重要的是知道一定要有這麼一個東西,它給自己的系統提供了動态調整行為的能力,而配置管理系統基本固有的特性一定要實作。
曾經我也傻傻分不清楚其差別是啥,這很正常。動态和靜态這是一個相對的概念,海枯石爛,永遠不變的那不叫配置,可能是撩妹的鬼話,即使這個配置可能是放在一個看起來很像配置檔案的文本裡,配置一定是可能修改其值的,而是否是動态配置主要是看這個配置是不是跟應用的版本建構釋出(build-deploy lifetime)強綁定的。如果一個配置項,跟軟體的版本建構是不耦合的,在應用程序運作時,可能需要變更配置值的就是動态配置,哪怕是變更頻率可能非常低,也許你設計了一個配置項,發現最後下來3年也沒變更過一次,那也是動态配置,相反,配置變更隻發生在軟體版本建構和釋出的那個點,那麼就是靜态配置,哪怕你建構很頻繁,1個小時就來一回,那也是個靜态配置,舉個簡單的例子:
這個配置項,永遠隻在某個軟體版本被建構出來時會變更其值,一旦這個版本被建構出來,并且在程式運作時,是一定沒有變更訴求的,這就是一個跟建構綁定的靜态配置。而文章開始時舉得loglevel的例子,則是一個動态配置的例子。
是以看一下你的系統的配置項,你會發現動态配置其實更多,而跟行為演進相關的幾乎都是動态配置。
我在進來阿裡做diamond之後,思考過一個有意思的事情,為什麼獨立的配置中心這個東西會首先出現在淘寶? 你去國内著名的競價排名搜尋引擎百度上搜”配置中心”,你會發現資訊不是特别多,但是排在前面的都是xdiamond, superdiamond這種diamond一族, 反正我們沒有為讓配置中心跟diamond這個名字關聯給百度付過1毛錢,是以這個搜尋結果應該是個自然結果,側面也反應了在國内說起配置中心在生産上大規模運用是獨此一家,别無分号。
而在業界,如下圖,spring boot/cloud微服務将注冊中心(discovery service)和配置中心(configuration service)提出來還處在布道階段,
而且從spring的實作方式的技術局限性來看,應該是還沒有哪個公司基于這個配置中心的方案在生産上實際支援大規模分布式系統,畢竟,翻遍所有blog和文章,還沒有哪個老外開始提到,這個基于git的方案應該怎麼去做多資料中心以及容災相關的非功能性需求。
回到那個問題,為什麼是淘寶,我們都知道在國内業界淘寶率先開啟了去ioe,全面采用mysql,在這個過程中,在國内,大規模的系統性的解決分庫分表這個命題的毫無疑問是阿裡以及阿裡中間件,在這個過程中,誕生了業内著名的tddl.而與tddl關聯的一個核心問題是,分庫分表之後,這多個庫的資料源的配置資訊存放在哪裡,并對應用屏蔽多庫這個事實? 好吧後面的事情也許你知道了,放在配置中心裡! 但還是要提的是曾經并沒有diamond, 都在注冊中心(configserver)裡,後來diamond從configserver分了出來,這個過程,很多人看到的是資料是持久化和非持久化的差別以及當時産品的穩定性方面的考量,直到今天也還是如此,但是,通過這麼多年實踐和演進下來,才恍然大悟,拆分的背後其實是服務發現(service discovery)和動态配置管理服務(dynamic configuration management)根本就是兩個不同的東西,而在當時可能僅是一種直覺。
有時候我們會因為在某個領域我們走的早一點而産生一點點的”優越感”和“虛榮感”, 曾經我們以為dynamic configuration for distributed system這個領域的實踐我們不能說在業界獨占鳌頭,但是絕對位居前列。但是下面這兩個老哥再次提醒我們,技術人踏實前行,不要有不必要的想法:
這兩位老哥在1985年4月,在ieee transactions on software engineering 上發表了一篇名為 dynamic configuration for distributed systems的論文(paper),奶奶的,1985年!!什麼概念,當時我4歲,還在玩泥巴,穿開裆褲。而diamond現在的主力技術架構研發同學都還沒出生呢!!我們能做的,隻能是向這兩位前輩再次緻敬!
在這篇論文中,雖然從現在的觀點來看,當時人們對分布式系統的認識跟現在有很大的差別,但是其中的問題識别的非常的準确:
“….dynamic systemc onfiguration is the ability to modify and extend a system while it is running. the facility is a requirement in large distributed systems where it may not be possible or economic to stop the entire system to allow modification to part of its hardware or software. it is also useful during production of the system to aid incremental integration of component parts, and during operation to aid system evolution.the paper introduces a model of the configuration process which permits dynamic incremental modification and extension. using this model we determine the properties required by languages and their execution environments to support dynamic configuration…”
并且很清晰的區分了靜态配置和動态配置的基本模型:
另一個值得從技術上玩味的是關于“配置”的“環境”屬性,這個表達可能有點抽象,比較難了解,這有點像技術上常提的一個叫context的概念,很多component會關聯一個context,component+context才是一個完整的運作時故事。環境恰恰也是熱帖中大家可能會産生的疑問之一,為何diamond會暴露這麼多的環境讓應用去選擇? 而進一步對中間件更熟稔一點的人會問,在單元化場景中,為何注冊中心是一個大叢集模式,而配置中心又是一個小叢集模式?
另一方面,多個環境恰恰也是加重分布式系統需要依賴一個獨立的配置管理系統的要素之一,可以說哪個公司的環境越複雜,分布式應用和服務越多,哪個公司誕生出獨立的配置中心系統的可能性也就越大。
舉幾個容易了解的表述,來幫助了解配置的環境屬性,
“在開發環境中将loglevel設定為debug,在預發環境loglevel設定為info,生産環境裡loglevel設定為warning” “在日常環境執行線程池的最大線程數應該設定為15,而生産環境上這個值應該大一點,預設設為150” “線上上環境中,中心機房,應用資料源需要連接配接a庫,而s機房,應用應該就近連接配接使用b庫” “隻有在t環境,雙向同步開關才應該關閉” “這次的改動有點大,新的特性僅線上上的h單元把該特性開放出來,其它的單元環境先不要開放出來”
是的,相信你一定發現了,我們的某個配置項,其具體的值域的定義往往跟具體的環境相關聯,現實中相當一部配置設定置在不同的環境必須設定不同的值,但是也有相當的另一部配置設定置在不同的環境要設定為完全一緻的值。是以從某個應用的視角看,其100個配置項,可能有50個是每個環境要不同的值的,而另50個是不區分環境,所有環境其配置值都是需要完全一緻的。這種異化給配置管理系統的設計帶來了複雜性,而且這個最終語義的解釋,很顯然不應該在配置中心系統本身,應該交給應用,配置管理系統應該做的是提供友善的互動方式保證這兩種不同的一緻性訴求同時得到很好的滿足,這種訴求分為3個方面,如下示意圖:
diamond 這三個能力都有提供,其中1,2一般都是在配置中心的提供的用戶端類庫和ops中展現。其中3這個實作是比較困難的,因為多個環境之間一般來說,都是有一些諸如遠距離網絡或者網絡隔離之類的實體限制的,要做分布式一緻性以及諸如分區容忍性之類的考量,目前diamond隻支援線上多單元一緻性限制規則,但是因為曆史原因大家沒有真正用起來,規則本身的抽象度也不夠好,不夠通用。現在我們正在做改造,未來會将一緻性規則做的更通用,後面會引導大家用起來,這樣對于那些多環境保持一緻的那些配置項,環境複雜性就可以對應用屏蔽掉,如果一個應用的配置項全是要各環境一緻的,那麼你就有福了,天空飄來五個字,”這麼多環境就不是個事”。
另外,一個配置中心也應該具備的能力是配置集的導出\導入功能,可以讓應用将a環境中的配置集友善的導出和導入到環境b中的能力,這對3個場景都有重大意義,一個場景是線上的配置值是經過實踐驗證的,現在在日常或者預發建立了應用環境,希望将線上的配置copy到線下用起來,第二個是,線下的應用終于調通要發預發或線上了,調較好的配置希望一下子發到線上去,當然這個根據我們的經驗,一定要慎重,第三個是建立站或者機房,應用需要在新的機房将所有配置遷移過去,diamond很快就會将這種能力開放出來。
了解了上面講的這些,相信你就更能了解spring framework 裡的兩把刷子(抽象) environment 和 propertysource 是咋回事了, 詳細參見:
spring 3.1 m1: unified property management
<a href="https://spring.io/blog/2011/02/15/spring-3-1-m1-unified-property-management/" target="_blank">https://spring.io/blog/2011/02/15/spring-3-1-m1-unified-property-management/</a>
環境屬性
稀疏變更屬性
快速傳播
環境屬性我們上文已經讨論過。
稀疏變更講的是配置的變更基本上都是稀疏的,因為系統的行為不可能非常頻繁的需要動态調整,你每100毫秒調整一次系統的行為,估計系統要對你罵娘了。
而快速傳播講的是配置不變則已,一變往往要求目标叢集的所有節點要幾乎同時收到變更,然後幾乎整齊劃一的統一調整行為。切庫的場景來講,主備切換之後,應用叢集寫新的主庫這個行為切換的稀稀拉拉,整個收斂了一天,應用肯定是受不了的,而這個屬性決定了對配置中心對配置變更推送sla的高要求。
在我們的眼裡,用土話講,這就是烏龜與王八的差別,想用拜金一點的話講,這就是金條和鑽石的差別,說的洋氣一點這叫apple and pear,但是當初起的名字的給我們帶來了大麻煩,現在我們的服務注冊中心現在叫config server, 你說坑不坑。不過很多中間件産品的名字同時承載了一段8年的曆史,這名字也展現中間件持續做技術産品,堅持就是一種力量的信念在裡面,n代人持續發展一個産品,說實話,隻管生不管養的現象在中間件不能說沒有,但确實是很少的。1個8年的産品就像八歲的孩子,已經上國小了,硬要給它改個名字,從朱屎山改成朱寶山,他的同學認不認還要打個非常大的問号,而且還要跑到派出所重新上戶口,也是個麻煩事。
是以産品的取名字有大學問和大恐怖,大家取名之前一定要找算命先生給好好算一算,本來我在成為碼農之前那也是仙風道骨,江湖人送外号郭半仙,那時候可以釘釘發個紅包找我算一下。但成為碼農之後嘛,就特麼不說了,說起來全是淚,以前get到的很多技能點全丢了,現在就瞅着電腦和代碼最順眼。
2者具體的不同,參見未來會寫的<<應用配置中心和服務注冊中心究竟有什麼不一樣?>>
業界著名的專職配置中心産品幾乎沒有(diamond傲嬌ing~), 基本都是在用git, redis, zookeeper, consul 這些湊活着搞一下,是以要了解配置中心的同學,直接了解diamond就可以了。:-)
但是針對于配置管理的用戶端程式設計類庫這一塊有一些類庫牛吹得是很大的,感興趣的同學可以了解一下:
這個類庫是在是太繁瑣了,用起來總感覺有點殺雞用牛刀,力用的太大的感覺。
簡單易上手,特性看起來很多,但是在很多關鍵常用的特性反倒是沒有。
簡單易上手,cfg4j 支援跟多種後端內建,做配置中心的解決方案,api設計也非常的不錯,我們正在設計的新diamond
annotation api的時候借鑒了不少其想法。
spring的東西一般都還是很不錯的,如果你的應用本身在用spring,毫無疑問,就這個了,用上面的那些類庫實在沒有必要。
spring cloud config server
如果你仔細讀一下其内容,而你又了解diamond的話,你會發現這就是diamond這些年在解決的問題啊,spring 終于從大量配置檔案逐漸走向了配置中心(externalized configuration in a distributed system),而這一次我們走在了前面。
看看owner 的宣傳,
java 他媽 properties reinvented! java properties的重新發明! 屌不屌?! 我僧僧的覺得,我們中國碼農有時候就是差了這種提煉和升華的能力,剛入行時覺得維護和修改前人留下的爛代碼實在是個很苦逼,很low的事情,但是martin fowler把這叫做”重構”,然後還寫了一本書,然後我們讀了之後,居然還覺得他媽的,講的真的非常的有道理!把改爛代碼變成叫重構之後,有了理論指導,突然覺得這真是個高逼格的事情!
很多人沒有這種這兩個概念的區分,但是對于配置中心,二者其實是有微妙的差别的.
配置如前文有闡述,配置的修改基本上都是由人來驅動,并且在ops上實作變更。
而中繼資料的本質是一小段程式中繼資料,它很多時候是程式産生,程式消費,由程式通過調用diamond的用戶端api來實作變更,中間不會有ops 或者人的介入。
知道這個有什麼意義?毫無疑問,配置這種需求選型比較明确,而中繼資料這種,可以選的pub-sub系統太多了,諸如消息隊列産品,分布式coordinator産品如zookeeper, 帶pub-sub 能力的k-v store 如redis等等都可以,是以如果是中繼資料這種,選什麼需要慎重,其間運用之妙,存乎一心,要充分評估和把握自己的需求。
diamond 不光是應用配置存儲,其目前存儲的資料,很大一部分是metadata,是以diamond 其實也是一個中繼資料存儲中心。
這麼長的文章,你居然能堅持看到這裡,說明你是真正的、脫離了低級趣味的,純粹的碼農,猿類中的精英!配置中心,它沒有高精尖的技術,難懂的算法,海量的資料,做這個東西隻需要一個精神就夠了。
owner之前一直在搞配置檔案的支援,現在owner也開始轉型搞跟zookeeper內建之類的,做配置中心的解決方案了,是以本文開頭說業界正在走向配置中心解決方案不是在忽悠,是确實是這個趨勢。