前言
系統(tǒng)規(guī)模擴大,私有云上數(shù)百個 Dubbo 應(yīng)用,上千個 Dubbo 實例。版本沒統(tǒng)一,發(fā)生與 Dubbo 相關(guān)事故,成為升級的誘因。
一、Ephermal節(jié)點未及時刪除導(dǎo)致provider不能恢復(fù)注冊的問題修復(fù)
事故背景
各業(yè)務(wù)線共用zookeeper集群作為dubbo注冊中心。19年9月,一臺交換機故障,導(dǎo)致zk集群幾分鐘網(wǎng)絡(luò)波動。zk集群恢復(fù)后,正常dubbo的provider很快重新注冊到zk上,但小部分沒有,直到手動重啟恢復(fù)
排查過程
1、統(tǒng)計這種現(xiàn)象dubbo服務(wù)版本分布,大多數(shù)都存在,github未找到相關(guān)問題issues。推斷尚未修復(fù)的偶現(xiàn)問題。
2、應(yīng)用、zk日志與dubbo代碼邏輯相互印證。
應(yīng)用日志:應(yīng)用重連zk后provider立刻重新注冊,之后沒有日志打印。
zk日志:注冊節(jié)點被刪除后,并沒有重新創(chuàng)建注冊節(jié)點。
對應(yīng)dubbo代碼:只有在FailbackRegistry.register(url)的doRegister(url)執(zhí)行成功或線程被掛起情況下,才與日志情況吻合。

ps:dubbo默認curator為zk客戶端,curator與zk通過session連接。當(dāng)curator重連zk時,session未過期用原;過期創(chuàng)建新的。ephemeral節(jié)點與session綁定,session過期,刪除此session下ephemeral節(jié)點。
3、繼續(xù)對doRegister(url)排查,發(fā)現(xiàn)CuratorZookeeperClient.createEphemeral(path)中:在createEphemeral(path)捕獲了NodeExistsException,創(chuàng)建ephemeral節(jié)點時,若此節(jié)點已存在為創(chuàng)建成功。初看沒問題,且在以下兩種常見的場景下表現(xiàn)正常:
Session未過期,創(chuàng)建Ephemeral節(jié)點時原節(jié)點仍存在,不需要重新創(chuàng)建
Session已過期,創(chuàng)建Ephemeral節(jié)點時原節(jié)點已被zookeeper刪除,創(chuàng)建成功

極端場景,zookeeper的Session過期與刪除Ephemeral節(jié)點不是原子性的,Session過期,Ephemeral節(jié)點未被zookeeper刪除。創(chuàng)建發(fā)現(xiàn)存在,不重新創(chuàng)建。待Ephemeral節(jié)點被zookeeper刪除后,dubbo認為重新注冊成功,實際未成功。定位問題后,與 Dubbo 社區(qū)交流,考拉也遇到。
問題的復(fù)現(xiàn)與修復(fù)
在Session過期與刪除Ephemeral節(jié)點加休眠時間,復(fù)現(xiàn)。
排查問題過程中,發(fā)現(xiàn)kafka的舊版本在用zk時也遇到過類似的問題,參考kafka修復(fù)方案,確定dubbo修復(fù)方案。在創(chuàng)建Ephemeral節(jié)點捕獲到NodeExistsException時進行判斷,若Ephemeral節(jié)點的SessionId與當(dāng)前客戶端的SessionId不同,刪除并重建Ephemeral節(jié)點。
kafka類似問題issues:https://issues.apache.org/jira/browse/KAFKA-1387
dubbo注冊恢復(fù)問題issues:https://github.com/apache/dubbo/issues/5125
二、瓜子的dubbo升級歷程
決定在dubbo2.7.3版本修復(fù),兼容性好: 與其他dubbo版本均兼容,除dubboX外(對dubbo協(xié)議進行了更改)
1、為什么要統(tǒng)一dubbo版本?
在此版本上修復(fù)問題;為dubbo的多機房、統(tǒng)一管控做鋪墊。
dubbo社區(qū)發(fā)展方向與公司對dubbo訴求吻合,如支持gRPC、云原生等。
兼容性問題匯總(這部分沒看)
創(chuàng)建zk節(jié)點時提示沒有權(quán)限
dubbo配置文件中已經(jīng)配置了zookeeper的用戶名密碼,但在創(chuàng)建zookeeper節(jié)點時卻拋出KeeperErrorCode = NoAuth的異常,這種情況分別對應(yīng)兩個兼容性問題:
參考社區(qū)的pr,我們在內(nèi)部版本進行了修復(fù)。
issues:https://github.com/apache/dubbo/issues/5076
dubbo在未配置配置中心時,默認使用注冊中心作為配置中心。通過注冊中心的配置信息初始化配置中心配置時,由于遺漏了用戶名密碼,導(dǎo)致此問題。
issues:https://github.com/apache/dubbo/issues/4991
dubbo在建立與zookeeper的連接時會根據(jù)zookeeper的address復(fù)用之前已建立的連接。當(dāng)多個注冊中心使用同一個address,但權(quán)限不同時,就會出現(xiàn)NoAuth的問題。
curator版本兼容性問題
dubbo2.7.3與低版本的curator不兼容,因此我們默認將curator版本升級至4.2.0

分布式調(diào)度框架elastic-job-lite強依賴低版本的curator,與dubbo2.7.3使用的curator版本不兼容,這給dubbo版本升級工作帶來了一定阻塞??紤]到elastic-job-lite已經(jīng)很久沒有人進行維護,目前一些業(yè)務(wù)線計劃將elastic-job-lite替換為其他的調(diào)度框架。
openFeign與dubbo兼容性問題
issues:https://github.com/apache/dubbo/issues/3990
dubbo的ServiceBean監(jiān)聽spring的ContextRefreshedEvent,進行服務(wù)暴露。openFeign提前觸發(fā)了ContextRefreshedEvent,此時ServiceBean還未完成初始化,于是就導(dǎo)致了應(yīng)用啟動異常。
參考社區(qū)的pr,我們在內(nèi)部版本修復(fù)了此問題。
RpcException兼容性問題
dubbo低版本consumer不能識別dubbo2.7版本provider拋出的org.apache.dubbo.rpc.RpcException。因此,在consumer全部升級到2.7之前,不建議將provider的com.alibaba.dubbo.rpc.RpcException改為org.apache.dubbo.rpc.RpcException
qos端口占用
dubbo2.7.3默認開啟qos功能,導(dǎo)致一些混部在物理機的dubbo服務(wù)升級時出現(xiàn)qos端口占用問題。關(guān)閉qos功能后恢復(fù)。
自定義擴展兼容性問題
業(yè)務(wù)線對于dubbo的自定義擴展比較少,因此在自定義擴展的兼容性方面暫時還沒有遇到比較難處理的問題,基本上都是變更package導(dǎo)致的問題,由業(yè)務(wù)線自行修復(fù)。
skywalking agent兼容性問題
我們項目中一般使用skywalking進行鏈路追蹤,由于skywalking agent6.0的plugin不支持dubbo2.7,因此統(tǒng)一升級skywalking agent到6.1。
三、dubbo多機房方案
1、每個機房部署一套獨立zk集群。集群間信息不同步。沒有zk集群跨機房延遲與數(shù)據(jù)不同步問題。
2、dubbo僅注冊到本機房zk集群;同時訂閱兩機房zk集群。
3、同機房優(yōu)先調(diào)用(實現(xiàn)簡單):
云平臺默認將機房標志信息注入容器的環(huán)境變量中。
provider暴露服務(wù)時,讀取環(huán)境變量中的機房標志信息,追加到待暴露服務(wù)的url中。
consumer調(diào)用provider時,讀取環(huán)境變量中的機房標志信息,路由策略優(yōu)先調(diào)用相同標志provider
實現(xiàn)dubbo通過環(huán)境變量進行路由的功能,向社區(qū)提交了pr:https://github.com/apache/dubbo/pull/5348
優(yōu)點:一個故障,另一個ok; 服務(wù)同機房閉環(huán),減少時間延遲。
缺點:雙注冊中心,機器成本增加