Apache Dubbo 簡(jiǎn)介及其在愛奇藝的發(fā)展歷史
1. Apache Dubbo 簡(jiǎn)介
Apache Dubbo 是一款由阿里開源的高性能 RPC 框架。Dubbo 框架本身除了通信外,還內(nèi)置了微服務(wù)治理的多項(xiàng)功能(如注冊(cè)發(fā)現(xiàn),路由規(guī)則等)。
自從 2017 年重啟維護(hù)以來,Dubbo 社區(qū)一直保持了較高的活躍度。從周邊生態(tài)來看也相對(duì)比較完善,比如 Nacos、Sentinel 等開源框架都對(duì)其提供了支持。在語言支持方面,除了 Java 語言之外,Dubbo-go 社區(qū)目前也非?;钴S,且針對(duì) python,nodejs 等主流開發(fā)語言 Dubbo 也有一些開源實(shí)現(xiàn)?;谝陨线@些因素,我們決定引入 Dubbo 框架,用以替換原先自研的 RPC 框架。
愛奇藝是在 2019 年 6 月正式開始引入 Dubbo 框架的。我們將其與對(duì)接公司內(nèi)部的基礎(chǔ)設(shè)施做了對(duì)接,如注冊(cè)中心、監(jiān)控系統(tǒng)等等,并在 2019 年 8 月正式發(fā)布了第一個(gè)內(nèi)部版本。
這里值得一提的是我們并沒有維護(hù)自己的 Dubbo 分支,而是利用 Dubbo 強(qiáng)大的擴(kuò)展機(jī)制開發(fā)我們的新特性,這樣使得我們能夠在跟進(jìn) Dubbo 社區(qū)新版本方面沒有障礙。在這個(gè)內(nèi)部版本發(fā)布后,很快就有第一個(gè)生產(chǎn)應(yīng)用在同年 9 月份上線。后續(xù)我們?cè)谶M(jìn)一步擴(kuò)展 Dubbo SDK 功能的同時(shí),在周邊生態(tài)建設(shè)方面也做了不少工作,其中就包括在 2020 年 3 月份上線的 Nacos 注冊(cè)中心等。
2. Apache Dubbo 在愛奇藝的發(fā)展歷史
優(yōu)秀的微服務(wù)開發(fā)框架是業(yè)務(wù)服務(wù)化的基石,但是由于微服務(wù)應(yīng)用的復(fù)雜性,要幫助業(yè)務(wù)團(tuán)隊(duì)更好地實(shí)踐微服務(wù)架構(gòu),還需要一個(gè)相對(duì)完善的微服務(wù)生態(tài)體系作為支撐。
微服務(wù)生態(tài)體系
下圖展示了目前愛奇藝內(nèi)部微服務(wù)生態(tài)體系的全景。
這里面分為幾個(gè)層面:
首先是開發(fā)框架層面,Dubbo SDK 集成了注冊(cè)發(fā)現(xiàn)、通信及負(fù)載均衡的能力,但是類似熔斷及限流功能還是需要采用 Sentinel 等框架來進(jìn)行支持;
在基礎(chǔ)設(shè)施層面,注冊(cè)中心/配置中心均是微服務(wù)生態(tài)中重要組件;此外為了保證應(yīng)用的可用性,完整的監(jiān)控體系也必不可少,如指標(biāo)監(jiān)控、日志監(jiān)控、鏈路追蹤等;
最后,為了方便運(yùn)維人員管理微服務(wù)應(yīng)用,還需要一套功能完善的管理平臺(tái),其中包括了服務(wù)管理、配置下發(fā)、監(jiān)控告警及一些對(duì)開發(fā)人員的支持功能。
可以看到,整個(gè)微服務(wù)的生態(tài)體系還是非常龐大的,限于篇幅,以下的演講會(huì)主要會(huì)集中在以下幾個(gè)方面展開:
Dubbo SDK 的擴(kuò)展

生態(tài)體系建設(shè)
注冊(cè)中心的演進(jìn)
監(jiān)控體系的建設(shè)
熔斷限流方面的支持
1. Dubbo SDK 的擴(kuò)展
根據(jù)愛奇藝內(nèi)部的實(shí)際情況,以及各個(gè)業(yè)務(wù)團(tuán)隊(duì)的需求,我們主要對(duì) Dubbo SDK 做了以下幾方面的擴(kuò)展:
基礎(chǔ)設(shè)施的適配:包括注冊(cè)中心、監(jiān)控系統(tǒng)、內(nèi)部的容器平臺(tái)等等;
可用性增強(qiáng):包括非健康實(shí)例隔離以及區(qū)域就近路由的機(jī)制;
安全性增強(qiáng):支持了服務(wù)間調(diào)用的認(rèn)證機(jī)制;
序列化:增加了對(duì) protobuf 序列化方式的支持。
1)非健康實(shí)例隔離機(jī)制
首先介紹非健康實(shí)例隔離機(jī)制。
Dubbo SDK 默認(rèn)采用隨機(jī)的負(fù)載均衡策略,并通過失敗重試的策略來保證調(diào)用的成功率。通過實(shí)踐發(fā)現(xiàn),生產(chǎn)環(huán)境中有時(shí)會(huì)出現(xiàn)少數(shù) Provider 節(jié)點(diǎn)雖然已經(jīng)處于不健康的狀態(tài)(比如磁盤寫滿等),但是還是能與注冊(cè)中心進(jìn)行正常通信,這樣 Consumer 端還是能發(fā)現(xiàn)這些實(shí)例,導(dǎo)致部分請(qǐng)求還是會(huì)被分發(fā)過去。這些請(qǐng)求由于實(shí)例本身的問題,可能會(huì)出現(xiàn)響應(yīng)時(shí)間變慢或者錯(cuò)誤率上升,從而引起整個(gè)服務(wù)質(zhì)量的下降(響應(yīng)時(shí)間抖動(dòng)或整體調(diào)用成功率下降)。
為了解決這樣一個(gè)問題,我們的思路是引入客戶端健康檢查機(jī)制,即 Consumer 端會(huì)對(duì)每個(gè) Provider 實(shí)例的請(qǐng)求成功率進(jìn)行統(tǒng)計(jì),判斷其是否健康;對(duì)于不健康的 Provider 實(shí)例,Consumer 端會(huì)對(duì)其進(jìn)行隔離一段時(shí)間,后續(xù)的請(qǐng)求不再通過負(fù)載均衡策略發(fā)送到這些實(shí)例上。另外 Consumer 端會(huì)維護(hù)每個(gè) Provider 實(shí)例被隔離的次數(shù),如果某個(gè)實(shí)例被多次隔離,每次隔離的時(shí)間也會(huì)相應(yīng)變長(zhǎng)。
我們的擴(kuò)展機(jī)制中提供了默認(rèn)的健康檢查策略,包括檢查最近一次調(diào)用是否出現(xiàn)服務(wù)端異常,或者一段時(shí)間內(nèi)是否有大量發(fā)出的請(qǐng)求未被返回。用戶也可以通過擴(kuò)展我們提供的接口來實(shí)現(xiàn)自己的檢查策略。
為了避免因?yàn)榫W(wǎng)絡(luò)抖動(dòng)等造成的意外影響,我們還設(shè)計(jì)了一套兜底機(jī)制。即當(dāng) Provider 實(shí)例中不健康的比例超過一定閾值時(shí),Consumer 會(huì)忽略實(shí)例隔離的策略,避免集中的流量將剩余的實(shí)例打垮。
2)區(qū)域就近路由機(jī)制
接下來介紹一下區(qū)域就近路由機(jī)制。
愛奇藝在多地都建有機(jī)房,為了確保在單個(gè)機(jī)房出現(xiàn)故障時(shí)各業(yè)務(wù)系統(tǒng)仍能正常工作,核心業(yè)務(wù)一般會(huì)采用兩地三中心的架構(gòu)進(jìn)行部署。在這種場(chǎng)景下,系統(tǒng)如果產(chǎn)生跨地域的訪問請(qǐng)求,由于網(wǎng)絡(luò)延時(shí)的原因勢(shì)必導(dǎo)致請(qǐng)求延時(shí)增大,所以各業(yè)務(wù)一般都有客戶端就近訪問服務(wù)端實(shí)例的需求。
我們通過擴(kuò)展 Dubbo 的路由機(jī)制實(shí)現(xiàn)了這樣的策略。大致的實(shí)現(xiàn)原理是,Provider 和 Consumer 實(shí)例在啟動(dòng)時(shí),會(huì)先從一個(gè)公共的地域服務(wù)中獲取實(shí)例當(dāng)前所在地域信息(比如可用區(qū)等)。Provider 實(shí)例在服務(wù)注冊(cè)時(shí)會(huì)將上述的地域信息作為 URL 的一部分注冊(cè)到注冊(cè)中心,這樣 Consumer 實(shí)例就能夠在服務(wù)發(fā)現(xiàn)時(shí)獲知每個(gè) Provider 實(shí)例的地域信息并和自身的地域信息進(jìn)行比對(duì),優(yōu)先選擇臨近的實(shí)例就近訪問。
此外,Consumer 實(shí)例也會(huì)通過上文中提到的健康檢查機(jī)制對(duì)服務(wù)端實(shí)例進(jìn)行檢查,如果發(fā)現(xiàn)本地域健康的 provider 實(shí)例低于設(shè)定比例時(shí),則會(huì)忽略就近路由的策略,改為在所有的 Provider 實(shí)例中進(jìn)行負(fù)載均衡,從而實(shí)現(xiàn)自動(dòng)的 failover 機(jī)制。

3)認(rèn)證機(jī)制
部分內(nèi)部服務(wù)有安全認(rèn)證相關(guān)的需求,不希望非授權(quán)應(yīng)用對(duì)其進(jìn)行訪問。為了解決這個(gè)問題,我們開發(fā)了一套基于數(shù)字簽名及 AK/SK 的認(rèn)證體系。
其基本原理是:
Provider 服務(wù)可以通過配置在某個(gè)service上開啟鑒權(quán);
需要訪問敏感服務(wù)的 Consumer 應(yīng)用,需要在微服務(wù)平臺(tái)上進(jìn)行申請(qǐng),審批后會(huì)在這個(gè)授權(quán)關(guān)系上生成一對(duì) AK/SK 并同步至鑒權(quán)服務(wù);
Provider/Consumer 與鑒權(quán)服務(wù)進(jìn)行通信,獲取相關(guān)的 AK/SK,這個(gè)過程使用 HTTPS 進(jìn)行通信;
Consumer 在發(fā)起調(diào)用時(shí),會(huì)對(duì)請(qǐng)求參數(shù)等生成一個(gè)數(shù)字簽名,連同時(shí)間戳、AK 等信息一起發(fā)送給 Provider 端;
Provider 在收到請(qǐng)求時(shí),會(huì)對(duì)其數(shù)字簽名等信息進(jìn)行核對(duì),確認(rèn)請(qǐng)求信息的來源及數(shù)據(jù)的完整性。
以上介紹的是我們針對(duì) Dubbo SDK 的擴(kuò)展內(nèi)容,接下來主要介紹我們?cè)谖⒎?wù)生態(tài)方面的建設(shè)。
2. 生態(tài)體系建設(shè)
注冊(cè)中心在微服務(wù)應(yīng)用中是最重要的基礎(chǔ)設(shè)施之一,在 Dubbo SDK 引入之初,為了快速落地,我們使用了 ZooKeeper 作為注冊(cè)中心。當(dāng)然實(shí)際上 ZooKeeper 并不是微服務(wù)注冊(cè)中心的最佳選型,它的主要缺點(diǎn)包括:
無法橫向擴(kuò)展;
作為一個(gè)一致性的系統(tǒng),在網(wǎng)絡(luò)分區(qū)會(huì)產(chǎn)生不可用。
1)注冊(cè)中心演進(jìn)
在調(diào)研了業(yè)界的各個(gè)方案后,我們選用了 Nacos 作為我們下一代的微服務(wù)注冊(cè)中心。下圖右下角是 Nacos 的整體介紹圖,選用 Nacos 的主要原因是:
高性能,可以橫向擴(kuò)展;
既適用于傳統(tǒng)為服務(wù)架構(gòu),也能適用于云原生環(huán)境,包括支持與 Istio 控制面對(duì)接;
提供了 Nacos-Sync 組件,可以用較低的成本進(jìn)行注冊(cè)中心的遷移。
在部署 Nacos 服務(wù)時(shí),我們充分考慮了服務(wù)部署架構(gòu)方面的高可用性。目前我們的 Nacos 服務(wù)是一個(gè)大集群,實(shí)例分布在多個(gè)不同的可用區(qū)中,在每個(gè)可用區(qū)內(nèi)部,我們會(huì)申請(qǐng)不同的 VIP,最終的內(nèi)網(wǎng)域名是綁定在這些 VIP 上。另外其底層所使用的 MySQL 也采用了多機(jī)房部署。這樣的架構(gòu)可以避免單個(gè) Nacos 實(shí)例或者單機(jī)房故障造成整個(gè) Nacos 服務(wù)的不可用。
