摘要:我們是不是很好奇配置中心如何做到實時更新并且通知到客戶端的這也是一個面試中經(jīng)常會問到的題目??蛻舳说玫綘顟B(tài)碼是并且會根據(jù)立即去服務(wù)端拉取最新的配置。
記得我們那時候剛開始學(xué)習(xí)Java
的時候都只是一個單體項目,項目里面的配置基本都是寫在項目里面的properties文件中,比如數(shù)據(jù)庫配置啥的,各種邏輯開關(guān),一旦這些配置修改了,還需要重啟項目這修改才會生效。隨著各種微服務(wù)的誕生,服務(wù)的拆分也越來越細,可能涉及的服務(wù)成千上百,服務(wù)基本也是集群部署,這樣再去一個一個項目修改配置,然后重啟這顯然是行不通的。所以分布式配置中心就誕生了,現(xiàn)在開源的分布式配置中心也挺多的比如:開源分布式配置中心有很多,比如spring-cloud/spring-cloud-config、淘寶/diamond、百度/disconf、攜程/apollo、netflix/archaius、Qconf、XDiamond、naco
s等等。我們是不是很好奇配置中心如何做到實時更新并且通知到客戶端的這也是一個面試中經(jīng)常會問到的題目。下面我們就以apollo為例吧去分析分析它是如何實現(xiàn)的。為什么選擇Apollo
來分析列?因為現(xiàn)在的公司就在使用它作為配置中心。雖然Apollo
是攜程開源的,但是攜程內(nèi)部也不用它。
要去了解一個玩意,就要先會去使用它。它的使用基本上很簡單。雖然使用簡單方便,但是它的設(shè)計還是挺復(fù)雜的,下面我們看一個它官網(wǎng)提供的架構(gòu)圖,是不是挺復(fù)雜的。
通過上述架構(gòu)圖我們可以看到ConfigService、AdminService、Client、Portal、 Meta Server、Eureka這幾個模塊,主要的還是前面四個模塊Meta Server、Eureka這兩個模塊只是Apollo本身內(nèi)部所需要的輔助模塊,我們暫時可以不需要關(guān)注它。
介紹完了上面這些Apollo
組成的模塊回到正題,配置中心如何做到實時更新并且到客戶端如何感知配置被更新了?看這個問題之前我們先回顧下每到周末我們?nèi)ト藲獗容^旺的餐廳吃飯的時候流程是什么樣的?
client
)告訴它某某你的應(yīng)用的配置被修改了,原來的值是啥被修改后的值是啥?還是說客戶端(Client)每隔多久去問下服務(wù)端我的配置有沒有被修改呀?如果是你你會怎么選擇列?你也許會說我肯定兩種方式都要呀!小朋友才會做選擇?再回到我們使用apollo
的時候我們應(yīng)用里面引入的Apollo
的Client
在我們應(yīng)用啟動的時候會有一個線程每隔5s
向服務(wù)短發(fā)起一個http
請求,不過這個http
請求是不會立即返回的。它是一個長鏈接如果配置沒有被更新,這個請求會被阻塞掛起,這個實現(xiàn)掛起的方式是通過Spring
的DeferredResult
來實現(xiàn)的,如果對這個Spring
的DeferredResult
不是很了解的推薦看下這個文章《5種SpringMvc的異步處理方式你都了解嗎?》
掛起60s后會返回HTTP
狀態(tài)碼為304
給到客戶端,如果再阻塞的過程中服務(wù)端配置有更新,這個Http請求會立馬返回,并且把變化的nameSpace信息返回出去,并且返回的http的狀態(tài)碼是200??蛻舳说玫綘顟B(tài)碼是200并且會根據(jù)nameSpace立即去服務(wù)端拉取最新的配置。
這里其實有一個問題,為什么不直接在長鏈接中返回變更后的結(jié)果,而是返回一個變更的通知,需要客戶端根據(jù)這個變更通知立即去拉取新的配置?
感興趣的可以參考下這個issue :https://github.com/apolloconfig/apollo/issues/652
這樣推送消息就是有狀態(tài)了,做不到冪等了,會帶來很多問題。目前推送是單連接走http的,所以問題可能不大,不過在設(shè)計上而言是有這個問題的,比如如果推送是走的tcp長連接的話。另外,長輪詢和推送之間也會有沖突,如果連續(xù)兩次配置變化,就可能造成雙寫。還有一點,就是保持邏輯的簡單,目前的做法推送只負責(zé)做簡單的通知,不需要去計算客戶端的配置應(yīng)該是什么,因為計算邏輯挺復(fù)雜的,需要考慮集群,關(guān)聯(lián),灰度等,總而言之,就是在滿足冪等性,實時性的基礎(chǔ)上保持設(shè)計的簡單。
這樣是不是就是很完美了,客戶端可以實時接收到配置的更新。但是客戶端如果接收服務(wù)端的更新內(nèi)容處理失敗,比如服務(wù)異常或者空指針的時候。這時候我們的客戶端配置如果不重啟是不是永遠都不會被更新了。沒關(guān)系這種情況apollo
也幫你想到啦,你既然告訴我更新失敗,那我就自己每隔一段時間主動去把我所有的配置都拉到客服端,拉回客服端之后和客戶端的緩存配置做比較,如果一致直接結(jié)束,不一致就更新客戶端的緩存,并且還會去異步更新本地文件。通過定時任務(wù)的補充,可以讓配置達到最終的一致性。
主動輪詢,和定時任務(wù)全量拉取配置是不是就萬無一失呢?只要涉及到分布式我們就要考慮到其他系統(tǒng)的宕機,比如哪一天挖機直接把部署Apollo的機房的光纖給挖斷了,這樣整個配置服務(wù)直接掛了,這時候主動輪詢以及定時任務(wù)都沒法起到作用了。是不是拉取不了配置,整個我們的客戶端應(yīng)用也要跟著受影響列,我們的配置基本上是改動的頻率也是比較小的,即使我們的配置中心掛掉了,我們還有一份本地文件系統(tǒng)來兜底,這個文件目錄默認是/opt/data或C:/opt/data,
所以即使配置中心掛了,對應(yīng)用的影響也比較小。因為它還會去讀取本地文件來兜底。
到現(xiàn)在為止我們應(yīng)該知道Apollo客戶端是如何感知服務(wù)端配置更新了的把?
Apollo ConfigServer
端,如果Apollo ConfigServer
端有配置更改會告訴應(yīng)用端有配置修改,讓客戶端立馬去拉取全量的配置,并且把配置更新到本地緩存,并且還會異步去更新本地文件緩存。5min
執(zhí)行一次的定時任務(wù),去拉取全量的配置。拉回配置之后也是對比本地緩存和遠程是否一致,如果不一致則更新本地進程緩存為遠程的,同時還去異步更新下本地文件。文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/123979.html
摘要:我們是不是很好奇配置中心如何做到實時更新并且通知到客戶端的這也是一個面試中經(jīng)常會問到的題目。雖然是攜程開源的,但是攜程內(nèi)部也不用它。客戶端得到狀態(tài)碼是并且會根據(jù)立即去服務(wù)端拉取最新的配置。通過定時任務(wù)的補充,可以讓配置達到最終的一致性。 引言記得我們那時候剛開始學(xué)習(xí)Java的時候都只是一個單體項目,項目里面的配...
摘要:比如使用的時候指定使用哪個環(huán)境的配置在微服務(wù)架構(gòu)下,服務(wù)的數(shù)量會比之前的單體應(yīng)用多,部署的節(jié)點數(shù)量也會很多。今天主要是講下在中如何對接進行配置管理。 問題背景 在實際工作中,我們的開發(fā)環(huán)境,測試環(huán)境,生產(chǎn)環(huán)境對應(yīng)的 Mysql 數(shù)據(jù)庫,Redis 這些信息都不一樣,每個環(huán)境都有對應(yīng)的一套配置,在 Spring Boot 中我們通常會編寫多個配置文件,也就是每個環(huán)境一個配置文件。 比如:...
摘要:基于的動態(tài)配置推送。對于任務(wù)中心這種多任務(wù)平臺型的配置,有一定影響?;诨卣{(diào)和配置的擴展點流程共建在建中通過擴展點共建方式,將流程編排的能力,暴露給內(nèi)外部的開發(fā)者,完成任務(wù)中心的共建。 一、聊聊本文想說什么: ??為更好幫助商家的會員快速成長,保持用戶活性,完善用戶的成長體系,有贊用戶中心-會員成長團隊基于現(xiàn)有的業(yè)務(wù)場景,設(shè)計了一套較完備任務(wù)中心系統(tǒng)。同時也有很多通用技術(shù)組件能夠落地。...
摘要:零為何要學(xué)源碼簡單,是我現(xiàn)在看起來最簡單的源碼不會像封裝了一層又一層,把人繞暈,而沒有那么多封裝,上手快,我們學(xué)習(xí)就應(yīng)該從簡單的開始憑什么非要去學(xué)封的像粽子一樣的源碼,我們就是要去學(xué)簡簡單單,平時樸素,接地氣的源碼最接近業(yè)務(wù)代碼的源碼。 零 為何要學(xué)apollo源碼 1 簡單,Apollo是我現(xiàn)在看起來最簡單的源碼不會像spring封裝了一層又一層,把人繞暈,而apollo沒有那么多封...
摘要:這樣做的方式是簡單,缺點是無法及時獲取變更推模式規(guī)則中心統(tǒng)一推送,客戶端通過注冊監(jiān)聽器的方式時刻監(jiān)聽變化,比如使用等配置中心。 在前面的學(xué)習(xí)過程中,Sentinel 的規(guī)則,也就是我們之前定義的限流規(guī)則,是通過代碼的方式定義好的。這是初始化時需要做的事情,Sentinel 提供了基于API的方式修改規(guī)則: FlowRuleManager.loadRules(List rules); /...
閱讀 5125·2023-04-25 18:47
閱讀 2745·2021-11-19 11:33
閱讀 3494·2021-11-11 16:54
閱讀 3154·2021-10-26 09:50
閱讀 2620·2021-10-14 09:43
閱讀 736·2021-09-03 10:47
閱讀 737·2019-08-30 15:54
閱讀 1564·2019-08-30 15:44