微服務(wù)配置中心之道

轉(zhuǎn)載自:GitHub 9K Star!Apollo作者手把手教你微服務(wù)配置中心之道

作者 | 宋順
編輯 | 小智

隨著微服務(wù)的流行睬愤,應(yīng)用和機(jī)器數(shù)量急劇增長(zhǎng),程序配置也愈加繁雜:各種功能的開(kāi)關(guān)稳懒、參數(shù)的配置舌菜、服務(wù)器的地址等等。在這樣的大環(huán)境下澈蚌,傳統(tǒng)的通過(guò)配置文件摹芙、數(shù)據(jù)庫(kù)等方式已經(jīng)越來(lái)越無(wú)法滿足我們對(duì)配置管理的需求。配置中心宛瞄,應(yīng)運(yùn)而生浮禾!在一定程度上交胚,配置中心就成為了微服務(wù)的大腦,如何用好這個(gè)大腦盈电,讓微服務(wù)更智能蝴簇?本文整理自攜程框架架構(gòu)研發(fā)部技術(shù)專家宋順在 QCon 上海 2018 站的演講。

背景介紹

隨著微服務(wù)的流行匆帚,應(yīng)用和機(jī)器數(shù)量急劇增長(zhǎng)熬词,程序配置也愈加繁雜:各種功能的開(kāi)關(guān)、參數(shù)的配置吸重、服務(wù)器的地址等等互拾。同時(shí),我們對(duì)程序配置的期望值也越來(lái)越高:配置修改后實(shí)時(shí)生效嚎幸,灰度發(fā)布颜矿,分環(huán)境、分集群管理嫉晶,完善的權(quán)限骑疆、審核機(jī)制等等。

在這樣的大環(huán)境下替废,傳統(tǒng)的通過(guò)配置文件箍铭、數(shù)據(jù)庫(kù)等方式已經(jīng)越來(lái)越無(wú)法滿足我們對(duì)配置管理的需求。

配置中心舶担,應(yīng)運(yùn)而生!

通過(guò)配置中心彬呻,我們可以方便地管理微服務(wù)在不同環(huán)境中的配置衣陶,從而可以在運(yùn)行時(shí)動(dòng)態(tài)調(diào)整服務(wù)行為,真正實(shí)現(xiàn)配置即『控制』的目標(biāo)闸氮。所以剪况,在一定程度上,配置中心就成為了微服務(wù)的大腦蒲跨,如何用好這個(gè)大腦译断,讓微服務(wù)更『智能』,也就成為了一項(xiàng)比較重要的議題或悲。

為什么需要配置中心孙咪?

\color{#00CED1}{配置即『控制』}

程序的發(fā)布其實(shí)和衛(wèi)星的發(fā)射有一些相似之處。

當(dāng)衛(wèi)星發(fā)射升天后巡语,基本就處于自主駕駛狀態(tài)了翎蹈,一般情況下就是按照預(yù)設(shè)的軌道運(yùn)行,間歇可能會(huì)收到一些來(lái)自地面的『控制』信號(hào)對(duì)運(yùn)行姿態(tài)進(jìn)行一定的調(diào)整男公。

程序發(fā)布其實(shí)也是這樣荤堪,當(dāng)程序發(fā)布到生產(chǎn)環(huán)境后,一般就是按照預(yù)設(shè)的邏輯運(yùn)行,我們無(wú)法直接去干預(yù)程序的行為澄阳,不過(guò)可以通過(guò)調(diào)整配置參數(shù)來(lái)動(dòng)態(tài)調(diào)整程序的行為拥知。這些配置參數(shù)就代表著我們對(duì)程序的『控制』信號(hào)。

由此可見(jiàn)碎赢,配置對(duì)程序的運(yùn)行非常重要低剔,我們需要一種可靠性高、實(shí)時(shí)性好的手段揩抡,從而可以隨時(shí)對(duì)程序『發(fā)號(hào)施令』户侥。

\color{#00CED1}{配置需要治理}

鑒于配置對(duì)程序正確運(yùn)行的重要性,所以配置的治理就顯得尤為重要了峦嗤,比如:

1蕊唐、權(quán)限控制、審計(jì)日志

由于配置能改變程序的行為烁设,不正確的配置甚至能引起災(zāi)難替梨,所以對(duì)配置的修改必須有比較完善的權(quán)限控制。同時(shí)也需要有一套完善的審計(jì)機(jī)制装黑,能夠方便地追溯是誰(shuí)改的配置副瀑、改了什么、什么時(shí)候改的等等恋谭。

2糠睡、灰度發(fā)布、配置回滾

對(duì)于一些比較重要的配置變更疚颊,我們一般會(huì)傾向于先在少量機(jī)器上修改看看效果狈孔,如果沒(méi)問(wèn)題再推給所有機(jī)器。同時(shí)如果發(fā)現(xiàn)配置改得有問(wèn)題的話材义,需要能夠方便地回滾配置均抽。

3、不同環(huán)境其掂、集群管理

同一份程序在不同的環(huán)境(開(kāi)發(fā)油挥,測(cè)試,生產(chǎn))款熬、不同的集群(如不同的數(shù)據(jù)中心)經(jīng)常需要有不同的配置深寥,所以需要有完善的環(huán)境、集群配置管理贤牛。

\color{#00CED1}{微服務(wù)的復(fù)雜性}

單體應(yīng)用時(shí)代翩迈,應(yīng)用數(shù)量比較少,配置也相對(duì)比較簡(jiǎn)單盔夜,還有可能讓運(yùn)維登上機(jī)器一臺(tái)一臺(tái)修改程序的配置文件负饲。

隨著微服務(wù)的流行堤魁,大應(yīng)用拆成小應(yīng)用,小應(yīng)用拆成多個(gè)獨(dú)立的服務(wù)返十,導(dǎo)致微服務(wù)的節(jié)點(diǎn)數(shù)量非常多妥泉,配置也隨著服務(wù)數(shù)量增加而急劇增長(zhǎng),再讓運(yùn)維登上機(jī)器一臺(tái)一臺(tái)手工修改配置不僅效率低洞坑,而且還容易出錯(cuò)盲链。如果碰到了緊急事件需要大規(guī)模迅速修改配置,估計(jì)運(yùn)維人員也只能兩手一攤了迟杂。

所以刽沾,綜合以上幾個(gè)要素,我們 需要一個(gè)統(tǒng)一的配置中心來(lái)管理微服務(wù)的配置排拷。

配置中心的一般模樣

那么侧漓,我們應(yīng)該需要一個(gè)什么樣的配置中心呢?

接下來(lái)就以 開(kāi)源配置中心 Apollo 為例监氢,來(lái)看一下配置中心的一般模樣布蔗。

\color{#00CED1}{治理能力}

如前面所論述的:配置需要治理,所以配置中心需要具備完善的治理能力浪腐,比如:

  1. 統(tǒng)一管理不同環(huán)境纵揍、不同集群的配置

  2. 支持灰度發(fā)布

  3. 支持已發(fā)布的配置回滾

  4. 完善的權(quán)限管理、操作審計(jì)日志

Apollo 配置中心的管理界面如下圖所示议街,可以發(fā)現(xiàn)相應(yīng)的治理功能還是非常齊全的泽谨。

\color{#00CED1}{可用性}

配置即『控制』,所以在一定程度上特漩,配置中心已經(jīng)成為了微服務(wù)的大腦吧雹,作為大腦,可用性顯然是要求非常高的拾稳。

接下來(lái)我們一起看一下 Apollo 是怎么實(shí)現(xiàn)高可用的吮炕。

Apollo at a glance

如下即是 Apollo 的基礎(chǔ)模型:

  1. 用戶在配置中心對(duì)配置進(jìn)行修改并發(fā)布

  2. 配置中心通知 Apollo 客戶端有配置更新

  3. Apollo 客戶端從配置中心拉取最新的配置腊脱、更新本地配置并通知到應(yīng)用

服務(wù)端高可用

上圖簡(jiǎn)要描述了 Apollo 的服務(wù)端設(shè)計(jì)访得,我們可以從下往上看:

  • 首先最下面是一個(gè) DB,我們的配置是放在 DB 里的陕凹,然后在 DB 之上有兩個(gè)服務(wù):Config Service 和 Admin Service悍抑;

  • Config Service 提供配置的讀取、推送等功能杜耙,服務(wù)對(duì)象是 Apollo 客戶端搜骡;

  • Admin Service 提供配置的修改、發(fā)布等功能佑女,服務(wù)對(duì)象是 Apollo Portal(管理界面)记靡;

  • Config Service 和 Admin Service 都是多實(shí)例谈竿、無(wú)狀態(tài)部署,所以需要將自己注冊(cè)到 Eureka 中并保持心跳摸吠;

  • 在 Eureka 之上我們架了一層 Meta Server 用于封裝 Eureka 的服務(wù)發(fā)現(xiàn)接口空凸,主要是為了讓客戶端和 Eureka 解耦;

  • Client 通過(guò)域名訪問(wèn) Meta Server 獲取 Config Service 服務(wù)列表(IP+Port)寸痢,而后直接通過(guò) IP+Port 訪問(wèn)服務(wù)呀洲,同時(shí)在 Client 側(cè)會(huì)做 load balance、錯(cuò)誤重試啼止;

  • Portal 通過(guò)域名訪問(wèn) Meta Server 獲取 Admin Service 服務(wù)列表(IP+Port)道逗,而后直接通過(guò) IP+Port 訪問(wèn)服務(wù),同時(shí)在 Portal 側(cè)會(huì)做 load balance献烦、錯(cuò)誤重試滓窍;

  • 為了簡(jiǎn)化部署,我們實(shí)際上會(huì)把 Config Service仿荆、Eureka 和 Meta Server 三個(gè)邏輯角色部署在同一個(gè) JVM 進(jìn)程中贰您;

  • 通過(guò)上述的設(shè)計(jì),可以看到整個(gè)服務(wù)端是無(wú)單點(diǎn)拢操,有效地保證了服務(wù)端的可用性锦亦。

客戶端高可用

上圖簡(jiǎn)要描述了 Apollo 客戶端的實(shí)現(xiàn)原理:

  1. 客戶端和服務(wù)端保持了一個(gè)長(zhǎng)連接,從而能第一時(shí)間獲得配置更新的推送令境。(通過(guò) Http Long Polling 實(shí)現(xiàn))杠园;

  2. 客戶端還會(huì)定時(shí)從 Apollo 配置中心服務(wù)端拉取應(yīng)用的最新配置;

    這是一個(gè) fallback 機(jī)制舔庶,為了防止推送機(jī)制失效導(dǎo)致配置不更新抛蚁;

    客戶端定時(shí)拉取會(huì)上報(bào)本地版本,所以一般情況下惕橙,對(duì)于定時(shí)拉取的操作瞧甩,服務(wù)端都會(huì)返回 304 - Not Modified。

  3. 客戶端從 Apollo 配置中心服務(wù)端獲取到應(yīng)用的最新配置后弥鹦,會(huì)保存在內(nèi)存中肚逸,所以我們的應(yīng)用程序來(lái)獲取配置的時(shí)候其實(shí)始終是從內(nèi)存中獲取的;

  4. 客戶端還會(huì)把從服務(wù)端獲取到的配置在本地文件系統(tǒng)緩存一份彬坏;

    這主要是為了容災(zāi)朦促,假設(shè)應(yīng)用程序重啟的時(shí)候,恰好遠(yuǎn)端服務(wù)全掛了栓始,或者網(wǎng)絡(luò)有故障务冕,應(yīng)用程序依然能從本地恢復(fù)配置。

  5. 通過(guò)這種推拉結(jié)合的機(jī)制幻赚,以及內(nèi)存和本地文件雙緩存的方式禀忆,有效地保證了客戶端的可用性臊旭。

可用性場(chǎng)景舉例

\color{#00CED1}{實(shí)時(shí)性}

配置即『控制』,所以我們希望我們的控制指令能迅速箩退、準(zhǔn)確地傳達(dá)到應(yīng)用程序巍扛,我們來(lái)看看 Apollo 是如何實(shí)現(xiàn)實(shí)時(shí)性的。

上圖簡(jiǎn)要描述了配置發(fā)布的大致過(guò)程:

  1. 用戶在 Portal 操作配置發(fā)布乏德;

  2. Portal 調(diào)用 Admin Service 的接口操作發(fā)布撤奸;

  3. Admin Service 發(fā)布配置后,發(fā)送 ReleaseMessage 給各個(gè) Config Service喊括;

  4. Config Service 收到 ReleaseMessage 后胧瓜,通知對(duì)應(yīng)的客戶端。

發(fā)送 ReleaseMessage 的實(shí)現(xiàn)方式

Admin Service 在配置發(fā)布后郑什,需要通知所有的 Config Service 有配置發(fā)布府喳,從而 Config Service 可以通知對(duì)應(yīng)的客戶端來(lái)拉取最新的配置。

從概念上來(lái)看蘑拯,這是一個(gè)典型的消息使用場(chǎng)景钝满,Admin Service 作為 producer 發(fā)出消息,各個(gè) Config Service 作為 consumer 消費(fèi)消息申窘。通過(guò)一個(gè)消息組件(Message Queue)就能很好的實(shí)現(xiàn) Admin Service 和 Config Service 的解耦弯蚜。

在實(shí)現(xiàn)上,考慮到 Apollo 的實(shí)際使用場(chǎng)景剃法,以及為了盡可能減少外部依賴碎捺,我們沒(méi)有采用外部的消息中間件,而是通過(guò)數(shù)據(jù)庫(kù)實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的消息隊(duì)列贷洲。

實(shí)現(xiàn)方式如下:

  1. Admin Service 在配置發(fā)布后會(huì)往 ReleaseMessage 表插入一條消息記錄收厨,消息內(nèi)容就是配置發(fā)布的 AppId+Cluster+Namespace

  2. Config Service 有一個(gè)線程會(huì)每秒掃描一次 ReleaseMessage 表,看看是否有新的消息記錄

  3. Config Service 如果發(fā)現(xiàn)有新的消息記錄优构,解析得到配置發(fā)布的 AppId+Cluster+Namespace 后诵叁,通知到對(duì)應(yīng)的客戶端

示意圖如下:

如何讓微服務(wù)更『智能』?

接下來(lái)我們來(lái)看一下結(jié)合配置中心钦椭,我們能做哪些有趣的事情拧额,讓微服務(wù)更智能。

\color{#00CED1}{開(kāi)關(guān)}
發(fā)布開(kāi)關(guān)

發(fā)布開(kāi)關(guān)一般用于發(fā)布過(guò)程中玉凯,比如:

  1. 有些新功能依賴于其它系統(tǒng)的新接口势腮,而其它系統(tǒng)的發(fā)布周期未必和自己的系統(tǒng)一致联贩,可以加個(gè)發(fā)布開(kāi)關(guān)漫仆,默認(rèn)把該功能關(guān)閉,等依賴系統(tǒng)上線后再打開(kāi)泪幌;

  2. 有些新功能有較大風(fēng)險(xiǎn)盲厌,可以加個(gè)發(fā)布開(kāi)關(guān)署照,上線后一旦有問(wèn)題可以迅速關(guān)閉。

需要注意的是吗浩,發(fā)布開(kāi)關(guān)應(yīng)該是短暫存在的(1-2 周)建芙,一旦功能穩(wěn)定后需要及時(shí)清除開(kāi)關(guān)代碼。

實(shí)驗(yàn)開(kāi)關(guān)

實(shí)驗(yàn)開(kāi)關(guān)通常用于對(duì)比測(cè)試或功能測(cè)試懂扼,比如:

  1. A/B 測(cè)試

    針對(duì)特定用戶應(yīng)用新的推薦算法禁荸;

    針對(duì)特定百分比的用戶使用新的下單流程;

  2. QA 測(cè)試

    有些重大功能已經(jīng)對(duì)外宣稱在某年某日發(fā)布

    可以事先發(fā)到生產(chǎn)環(huán)境阀湿,只對(duì)內(nèi)部用戶打開(kāi)赶熟,測(cè)試沒(méi)問(wèn)題后按時(shí)對(duì)全部用戶開(kāi)放

實(shí)驗(yàn)開(kāi)關(guān)應(yīng)該也是短暫存在的,一旦實(shí)驗(yàn)結(jié)束了需要及時(shí)清除實(shí)驗(yàn)開(kāi)關(guān)代碼陷嘴。

運(yùn)維開(kāi)關(guān)

運(yùn)維開(kāi)關(guān)通常用于提升系統(tǒng)穩(wěn)定性映砖,比如:

  1. 大促前可以把一些非關(guān)鍵功能關(guān)閉來(lái)提升系統(tǒng)容量;

  2. 當(dāng)系統(tǒng)出現(xiàn)問(wèn)題時(shí)可以關(guān)閉非關(guān)鍵功能來(lái)保證核心功能正常工作灾挨。

運(yùn)維開(kāi)關(guān)可能會(huì)長(zhǎng)期存在邑退,而且一般會(huì)涉及多個(gè)系統(tǒng),所以需要提前規(guī)劃劳澄。

\color{#00CED1}{服務(wù)治理}
限流

服務(wù)就像高速公路一樣地技,在正常情況下非常通暢,不過(guò)一旦流量突增(比如大促秒拔、遭受 DDOS 攻擊)時(shí)乓土,如果沒(méi)有做好限流,就會(huì)導(dǎo)致系統(tǒng)整個(gè)被沖垮溯警,所有用戶都無(wú)法訪問(wèn)趣苏。

正常的高速公路

超出容量的高速公路

所以我們需要限流機(jī)制來(lái)應(yīng)對(duì)此類問(wèn)題,一般的做法是在網(wǎng)關(guān)或 RPC 框架層添加限流邏輯梯轻,結(jié)合配置中心的動(dòng)態(tài)推送能力實(shí)現(xiàn)動(dòng)態(tài)調(diào)整限流規(guī)則配置食磕。

黑白名單

對(duì)于一些關(guān)鍵服務(wù),哪怕是在內(nèi)網(wǎng)環(huán)境中一般也會(huì)對(duì)調(diào)用方有所限制喳挑,比如:

  1. 有敏感信息的服務(wù)可以通過(guò)配置白名單來(lái)限制只有某些應(yīng)用或 IP 才能調(diào)用

  2. 某個(gè)調(diào)用方代碼有問(wèn)題導(dǎo)致超大量調(diào)用彬伦,對(duì)服務(wù)穩(wěn)定性產(chǎn)生了影響,可以通過(guò)配置黑名單來(lái)暫時(shí)屏蔽這個(gè)調(diào)用方或 IP

一般的做法是在 RPC 框架層添加校驗(yàn)邏輯伊诵,結(jié)合配置中心的動(dòng)態(tài)推送能力來(lái)實(shí)現(xiàn)動(dòng)態(tài)調(diào)整黑白名單配置单绑。

\color{#00CED1}{數(shù)據(jù)庫(kù)遷移}

數(shù)據(jù)庫(kù)的遷移也是挺普遍的,比如:原來(lái)使用的 SQL Server曹宴,現(xiàn)在需要遷移到 MySQL搂橙,這種情況就可以結(jié)合配置中心來(lái)實(shí)現(xiàn)平滑遷移:

  1. 單寫(xiě) SQL Server,100% 讀 SQL Server笛坦;

  2. 初始化 MySQL区转;

  3. 雙寫(xiě) SQL Server 和 MySQL苔巨,100% 讀 SQL Server;

  4. 線下校驗(yàn)废离、補(bǔ)齊 MySQL 數(shù)據(jù)侄泽;

  5. 雙寫(xiě) SQL Server 和 MySQL,90% 讀 SQL Server蜻韭,10% 讀 MySQL悼尾;

  6. 雙寫(xiě) SQL Server 和 MySQL,100% 讀 MySQL肖方;

  7. 單寫(xiě) MySQL诀豁,100% 讀 MySQL;

  8. 切換完成窥妇。

上述的讀寫(xiě)開(kāi)關(guān)和比例配置都可以通過(guò)配置中心實(shí)現(xiàn)動(dòng)態(tài)調(diào)整舷胜。

\color{#00CED1}{動(dòng)態(tài)日志級(jí)別}

服務(wù)運(yùn)行過(guò)程中,經(jīng)常會(huì)遇到需要通過(guò)日志來(lái)排查定位問(wèn)題的情況活翩,然而這里卻有個(gè)兩難:

  1. 如果日志級(jí)別很高(如:ERROR)烹骨,可能對(duì)排查問(wèn)題也不會(huì)有太大幫助

  2. 如果日志級(jí)別很低(如:DEBUG),日常運(yùn)行會(huì)帶來(lái)非常大的日志量材泄,造成系統(tǒng)性能下降

為了兼顧性能和排查問(wèn)題沮焕,我們可以借助于日志組件和配置中心實(shí)現(xiàn)日志級(jí)別動(dòng)態(tài)調(diào)整。

以 Spring Boot 和 Apollo 結(jié)合為例:

  @ApolloConfigChangeListener
  private void onChange(ConfigChangeEvent changeEvent) {
    refreshLoggingLevels(changeEvent.changedKeys());
  }

  private void refreshLoggingLevels(Set<String> changedKeys) {
    boolean loggingLevelChanged = false;
    for (String changedKey : changedKeys) {
      if (changedKey.startsWith("logging.level.")) {
        loggingLevelChanged = true;
        break;
      }
    }

    if (loggingLevelChanged) {
      // refresh logging levels
      this.applicationContext.publishEvent(new EnvironmentChangeEvent(changedKeys));
    }
  }

詳細(xì)樣例代碼可以參考:

https://github.com/ctripcorp/apollo-use-cases/tree/master/spring-cloud-logger

\color{#00CED1}{動(dòng)態(tài)網(wǎng)關(guān)路由}

網(wǎng)關(guān)的核心功能之一就是路由轉(zhuǎn)發(fā)拉宗,而其中的路由信息也是經(jīng)常會(huì)需要變化的峦树,我們也可以結(jié)合配置中心實(shí)現(xiàn)動(dòng)態(tài)更新路由信息。

以 Spring Cloud Zuul 和 Apollo 結(jié)合為例:

  @ApolloConfigChangeListener
  public void onChange(ConfigChangeEvent changeEvent) {
    boolean zuulPropertiesChanged = false;
    for (String changedKey : changeEvent.changedKeys()) {
      if (changedKey.startsWith("zuul.")) {
        zuulPropertiesChanged = true;
        break;
      }
    }

    if (zuulPropertiesChanged) {
      refreshZuulProperties(changeEvent);
    }
  }

  private void refreshZuulProperties(ConfigChangeEvent changeEvent) {
    // rebind configuration beans, e.g. ZuulProperties
    this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));

    // refresh routes
    this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator));
  }

詳細(xì)樣例代碼可以參考:

https://github.com/ctripcorp/apollo-use-cases/tree/master/spring-cloud-zuul

\color{#00CED1}{動(dòng)態(tài)數(shù)據(jù)源}

數(shù)據(jù)庫(kù)是應(yīng)用運(yùn)行過(guò)程中的一個(gè)非常重要的資源旦事,承擔(dān)了非常重要的角色魁巩。

在運(yùn)行過(guò)程中,我們會(huì)遇到各種不同的場(chǎng)景需要讓?xiě)?yīng)用程序切換數(shù)據(jù)庫(kù)連接姐浮,比如:數(shù)據(jù)庫(kù)維護(hù)谷遂、數(shù)據(jù)庫(kù)宕機(jī)主從切換等。

切換過(guò)程如下圖所示:

以 Spring Boot 和 Apollo 結(jié)合為例:

@Configuration
public class RefreshableDataSourceConfiguration {

  @Bean
  public DynamicDataSource dataSource(DataSourceManager dataSourceManager) {
    DataSource actualDataSource = dataSourceManager.createDataSource();
    return new DynamicDataSource(actualDataSource);
  }
}
public class DynamicDataSource implements DataSource {
  private final AtomicReference<DataSource> dataSourceAtomicReference;

  public DynamicDataSource(DataSource dataSource) {
    dataSourceAtomicReference = new AtomicReference<>(dataSource);
  }

  // set the new data source and return the previous one
  public DataSource setDataSource(DataSource newDataSource){
    return dataSourceAtomicReference.getAndSet(newDataSource);
  }

  @Override
  public Connection getConnection() throws SQLException {
    return dataSourceAtomicReference.get().getConnection();
  }

  ...
}
  @ApolloConfigChangeListener
  public void onChange(ConfigChangeEvent changeEvent) {
    boolean dataSourceConfigChanged = false;
    for (String changedKey : changeEvent.changedKeys()) {
      if (changedKey.startsWith("spring.datasource.")) {
        dataSourceConfigChanged = true;
        break;
      }
    }

    if (dataSourceConfigChanged) {
      refreshDataSource(changeEvent.changedKeys());
    }
  }

  private synchronized void refreshDataSource(Set<String> changedKeys) {
    try {
      // rebind configuration beans, e.g. DataSourceProperties
      this.applicationContext.publishEvent(new EnvironmentChangeEvent(changedKeys));

      DataSource newDataSource = dataSourceManager.createAndTestDataSource();
      DataSource oldDataSource = dynamicDataSource.setDataSource(newDataSource);
      asyncTerminate(oldDataSource);
    } catch (Throwable ex) {
      logger.error("Refreshing data source failed", ex);
    }
  }

詳細(xì)樣例代碼可以參考:

https://github.com/ctripcorp/apollo-use-cases/tree/master/dynamic-datasource

最佳實(shí)踐

\color{#00CED1}{公共組件的配置}

公共組件是指那些發(fā)布給其它應(yīng)用使用的客戶端代碼卖鲤,比如 RPC 客戶端肾扰、DAL 客戶端等。

這類組件一般是由單獨(dú)的團(tuán)隊(duì)(如中間件團(tuán)隊(duì))開(kāi)發(fā)蛋逾、維護(hù)集晚,但是運(yùn)行時(shí)是在業(yè)務(wù)實(shí)際應(yīng)用內(nèi)的,所以本質(zhì)上可以認(rèn)為是應(yīng)用的一部分区匣。

這類組件的特殊之處在于大部分的應(yīng)用都會(huì)直接使用中間件團(tuán)隊(duì)提供的默認(rèn)值偷拔,少部分的應(yīng)用需要根據(jù)自己的實(shí)際情況對(duì)默認(rèn)值進(jìn)行調(diào)整。

比如數(shù)據(jù)庫(kù)連接池的最小空閑連接數(shù)量(minimumIdle),出于對(duì)數(shù)據(jù)庫(kù)資源的保護(hù)条摸,DBA 要求將全公司默認(rèn)的 minimumIdle 設(shè)為 1,對(duì)大部分的應(yīng)用可能都適用铸屉,不過(guò)有些核心 / 高流量應(yīng)用可能覺(jué)得太小钉蒲,需要設(shè)為 10。

針對(duì)這種情況彻坛,可以借助于 Apollo 提供的 Namespace 實(shí)現(xiàn):

  1. 中間件團(tuán)隊(duì)創(chuàng)建一個(gè)名為dal的公共 Namespace顷啼,設(shè)置全公司的數(shù)據(jù)庫(kù)連接池默認(rèn)配置

    minimumIdle = 1
    maximumPoolSize = 20
    
  2. dal 組件的代碼會(huì)讀取dal公共 Namespace 的配置

  3. 對(duì)大部分的應(yīng)用由于默認(rèn)配置已經(jīng)適用,所以不用做任何事情

  4. 對(duì)于少量核心 / 高流量應(yīng)用如果需要調(diào)整 minimumIdle 的值昌屉,只需要關(guān)聯(lián)dal公共 Namespace钙蒙,然后對(duì)需要覆蓋的配置做調(diào)整即可,調(diào)整后的配置僅對(duì)該應(yīng)用自己生效

minimumIdle = 10

通過(guò)這種方式的好處是不管是中間件團(tuán)隊(duì)间驮,還是應(yīng)用開(kāi)發(fā)躬厌,都可以靈活地動(dòng)態(tài)調(diào)整公共組件的配置。

\color{#00CED1}{灰度發(fā)布}

對(duì)于重要的配置一定要做灰度發(fā)布竞帽,先在一臺(tái)或多臺(tái)機(jī)器上生效后觀察效果扛施,如果沒(méi)有問(wèn)題再推給所有的機(jī)器。

對(duì)于公共組件的配置屹篓,建議先在一個(gè)或多個(gè)應(yīng)用上生效后觀察效果疙渣,沒(méi)有問(wèn)題再推給所有的應(yīng)用。

\color{#00CED1}{發(fā)布審核}

生產(chǎn)環(huán)境建議啟用發(fā)布審核功能堆巧,簡(jiǎn)單而言就是如果某個(gè)人修改了配置妄荔,那么必須由另一個(gè)人審核后才可以發(fā)布,以避免由于頭腦不清醒谍肤、手一抖之類的造成生產(chǎn)事故啦租。

結(jié) 語(yǔ)

本文主要介紹了以下幾方面:

  1. 為什么需要配置中心?

    配置即『控制』

    配置需要治理

    微服務(wù)帶來(lái)的配置復(fù)雜性

  2. 配置中心的一般模樣

    以 Apollo 為例子荒揣,介紹了配置中心所具備的特征

    介紹了 Apollo 是如何實(shí)現(xiàn)高可用和實(shí)時(shí)性的

  3. 如何讓微服務(wù)更『智能』刷钢?

    通過(guò)幾個(gè)案例,分享了如何借助于配置中心使微服務(wù)更『智能』

  4. 配置中心的最佳實(shí)踐

    公共組件的配置

    灰度發(fā)布

    發(fā)布審核

最后乳附,希望大家在平時(shí)工作中都能用好配置中心内地,更好地服務(wù)于業(yè)務(wù)場(chǎng)景,使微服務(wù)更『智能』赋除,實(shí)現(xiàn)從青銅到王者的跨越阱缓!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市举农,隨后出現(xiàn)的幾起案子荆针,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件航背,死亡現(xiàn)場(chǎng)離奇詭異喉悴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玖媚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)箕肃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人今魔,你說(shuō)我怎么就攤上這事勺像。” “怎么了错森?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵吟宦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我涩维,道長(zhǎng)殃姓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任瓦阐,我火速辦了婚禮辰狡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垄分。我一直安慰自己宛篇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布薄湿。 她就那樣靜靜地躺著叫倍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豺瘤。 梳的紋絲不亂的頭發(fā)上吆倦,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音坐求,去河邊找鬼蚕泽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛桥嗤,可吹牛的內(nèi)容都是我干的须妻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼泛领,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荒吏!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起渊鞋,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绰更,失蹤者是張志新(化名)和其女友劉穎瞧挤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體儡湾,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡特恬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徐钠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癌刽。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丹皱,靈堂內(nèi)的尸體忽然破棺而出妒穴,到底是詐尸還是另有隱情宋税,我是刑警寧澤摊崭,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站杰赛,受9級(jí)特大地震影響呢簸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乏屯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一根时、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辰晕,春花似錦蛤迎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至窘问,卻和暖如春辆童,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惠赫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工把鉴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人儿咱。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓庭砍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親混埠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逗威,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容