前言
估算了一下,dubbo
里面涉及的東西還是比較多的.比如談到框架的時候,設(shè)計模式都是一個老生常談的話題,再比如我們開發(fā)中我們不常用的一些概念,spi
汰具、javassist
,以及和zookeeper相關(guān)的一些知識,比如ZKClient
的使用,這些和dubbo
關(guān)系很密切,但是這些假如我不做一些前戲鋪墊就直接把源碼貼出來,那真的沒啥意義.因為看源碼還是要有一些基礎(chǔ),所以我的目標(biāo)是,即使看不懂源碼,但是看我的分析思路和穿插的一些面試題,都能有一些收獲.
從標(biāo)題就知道,這次我講的是集群容錯中的第二個關(guān)鍵詞Router
,中文意思就是路由
,這個路由
是個很有意思的詞匯.因為前端的路由
和后端的路由
他們是不同的,但是思想是基本一致的.鑒于很多技術(shù)文章都有一個詬病,就是只講概念
,卻不講應(yīng)用場景
,其實Router
在應(yīng)用隔離
,讀寫分離
,灰度發(fā)布
中都有它的影子.因此本篇用灰度發(fā)布
的例子來做前期的鋪墊
灰度發(fā)布
先看看百度百科的概念
灰度發(fā)布是指在黑與白之間扑眉,能夠平滑過渡的一種發(fā)布方式续镇。AB test就是一種灰度發(fā)布方式下隧,讓一部分用戶繼續(xù)用A赖舟,一部分用戶開始用B蘑秽,如果用戶對B沒有什么反對意見宠能,那么逐步擴大范圍亚隙,把所有用戶都遷移到B上面來∥コ纾灰度發(fā)布可以保證整體系統(tǒng)的穩(wěn)定阿弃,在初始灰度的時候就可以發(fā)現(xiàn)、調(diào)整問題羞延,以保證其影響度渣淳。
說人話就是,你發(fā)布應(yīng)用的時候,不停止對外的服務(wù),也就是讓用戶感覺不到你在發(fā)布.那么下面演示一下灰度發(fā)布
1.首先在192.168.56.2
和192.168.56.3
兩臺機器上啟動Provider
,然后啟動Consumer
,如下圖
2.假設(shè)我們要升級192.168.56.2
服務(wù)器上的服務(wù),接著我們?nèi)ubbo的控制臺配置路由,切斷192.168.56.2
的流量,配置完成并且啟動之后,就看到此時只調(diào)用192.168.56.3
的服務(wù)
3.假設(shè)此時你在192.168.56.2
服務(wù)器升級服務(wù),升級完成后再次將啟動服務(wù).
4.由于服務(wù)已經(jīng)升級完成,那么我們此時我們要把剛才的禁用路由取消點,于是點了禁用
,但是此時dubbo的這個管理平臺就出現(xiàn)了bug
,如下圖所示
驚奇的發(fā)現(xiàn)點了禁用
,數(shù)據(jù)就變兩條了,繼續(xù)點禁用
,還是兩條,而且刪除還刪除不了,這樣就很蛋疼了...但是一直刪不了也不是辦法,解決辦法也是有的,那就是去zookeeper上刪除節(jié)點
5.由于我之前是從事iOS開發(fā)的,所以一直用的是Mac電腦,Mac上好像沒有特別好用的zookeeper可視化客戶端工具,于是我就用了這個idea
的zookeeper插件,只要將這個zookeeper節(jié)點刪除
然后刷新控制臺的界面,如下圖那么就只剩下一條了
6.那么此時我們再看控制臺的輸出,已經(jīng)恢復(fù)正常,整個灰度發(fā)布流程結(jié)束
直入主題
我們先來看看Router
的繼承體系圖
從圖中可以看出,他有三個實現(xiàn)類,分別是ConditionRouter
,MockInvokersSelector
,ScriptRouter
MockInvokersSelector
在dubbo源碼解析-集群容錯架構(gòu)設(shè)計中提到這里就暫時不多做敘述
ScriptRouter
在dubbo
的測試用例中就有用到,這個類的源碼不多,也就124行.引用官網(wǎng)的描述
腳本路由規(guī)則 支持 JDK 腳本引擎的所有腳本,比如:javascript, jruby, groovy 等伴箩,通過 type=javascript 參數(shù)設(shè)置腳本類型入愧,缺省為 javascript。
當(dāng)然看到這里可能你可能還是沒有感覺出這個類有什么不可替代的作用,你注意一下這個類中有個ScriptEngine
的屬性,那么我可以舉一個應(yīng)用場景給你
假如有這么個表達式如下:
double d = (1+1-(2-4)*2)/24;//沒有問題
"(1+1-(2-4)*2)/24"http://但是假如這個表達式是這樣的字符串格式,或者更復(fù)雜的運算,那么你就不好處理了,然后這個ScriptEngine類的eval方法就能很好處理這類字符串表達式的問題
本篇主要講講ConditionRouter(條件路由)
,條件路由主要就是根據(jù)dubbo管理控制臺配置的路由規(guī)則來過濾相關(guān)的invoker
,當(dāng)我們對路由規(guī)則點擊啟用
的時候,就會觸發(fā)RegistryDirectory
類的notify
方法
其實我覺得看技術(shù)類文章更重要的是看分析的思路,看的是思考過程,比如為什么這個notify
方法傳入的是List<URL>
呢?如果看過我前兩篇dubbo源碼解析dubbo源碼解析-集群容錯架構(gòu)設(shè)計和dubbo源碼解析-directory就明白,我的分析過程都是以官方文檔
為依據(jù),所以這個問題的答案自然也在官方文檔.下面引用一段官網(wǎng)文檔的描述
所有配置最終都將轉(zhuǎn)換為 URL 表示嗤谚,并由服務(wù)提供方生成棺蛛,經(jīng)注冊中心傳遞給消費方,各屬性對應(yīng) URL 的參數(shù)巩步,參見配置項一覽表中的 "對應(yīng)URL參數(shù)" 列
其實對于Router
來說,我們最關(guān)心的就是他是怎么過濾的.所以下面這些流程代碼我們先走一遍
這個條件路由有一個特點,就是他的getUrl
是有值的,同時這里分享一個IDEA
中debug
查看表達式內(nèi)容的技巧,比如router.getUrl()
表達式的值,如下圖所示
從這里我們看到,此時實現(xiàn)類是ConditionRouter
,由于接下來的邏輯如果直接讓大家看源碼圖可能不夠清晰,所以我又把這個核心的篩選過程用了一個高清無碼圖,并且用序號標(biāo)注
最后的篩選結(jié)果如下,因為我們在管理后臺配置了禁用192.168.56.2
,所以最后添加進invokers
的就只有192.168.56.3
寫在末尾
這篇文章準(zhǔn)備了好久,因為每天加班回到家都是11點多,但是我認(rèn)為越是時間緊張,才能越看出一個人做事的決心,無論加班多忙,或者過年放假,每周一篇的承諾始終不變,鑒于本人才疏學(xué)淺,不對的地方還望斧正.