爱奇艺在 Dubbo 生态下的微服务架构实践
作者 | 周曉軍? 愛奇藝中間件團(tuán)隊負(fù)責(zé)人
導(dǎo)讀:本文整理自作者于 2020 年云原生微服務(wù)大會上的分享《愛奇藝在 Dubbo 生態(tài)下的微服務(wù)架構(gòu)實踐》,重點(diǎn)介紹了愛奇藝在 Dubbo、Sentinel 等開發(fā)框架方面的使用經(jīng)驗以及微服務(wù)生態(tài)體系的建設(shè)經(jīng)驗。
阿里巴巴云原生公眾號后臺回復(fù)?818?即可獲取直播回看地址和大會 PPT 合集。
本文將主要圍繞以下幾個主題展開:
- Apache Dubbo 簡介及其在愛奇藝的發(fā)展歷史
- 愛奇藝內(nèi)部對 Dubbo SDK 的擴(kuò)展及圍繞 Dubbo 相關(guān)的微服務(wù)生態(tài)建設(shè)
- 后續(xù)規(guī)劃
Apache Dubbo 簡介及其在愛奇藝的發(fā)展歷史
1. Apache Dubbo 簡介
Apache Dubbo 是一款由阿里開源的高性能 RPC 框架。Dubbo 框架本身除了通信外,還內(nèi)置了微服務(wù)治理的多項功能(如注冊發(fā)現(xiàn),路由規(guī)則等)。
自從 2017 年重啟維護(hù)以來,Dubbo 社區(qū)一直保持了較高的活躍度。從周邊生態(tài)來看也相對比較完善,比如 Nacos、Sentinel 等開源框架都對其提供了支持。在語言支持方面,除了 Java 語言之外,Dubbo-go 社區(qū)目前也非常活躍,且針對 python,nodejs 等主流開發(fā)語言 Dubbo 也有一些開源實現(xiàn)。基于以上這些因素,我們決定引入 Dubbo 框架,用以替換原先自研的 RPC 框架。
愛奇藝是在 2019 年 6 月正式開始引入 Dubbo 框架的。我們將其與對接公司內(nèi)部的基礎(chǔ)設(shè)施做了對接,如注冊中心、監(jiān)控系統(tǒng)等等,并在 2019 年 8 月正式發(fā)布了第一個內(nèi)部版本。
這里值得一提的是我們并沒有維護(hù)自己的 Dubbo 分支,而是利用 Dubbo 強(qiáng)大的擴(kuò)展機(jī)制開發(fā)我們的新特性,這樣使得我們能夠在跟進(jìn) Dubbo 社區(qū)新版本方面沒有障礙。在這個內(nèi)部版本發(fā)布后,很快就有第一個生產(chǎn)應(yīng)用在同年 9 月份上線。后續(xù)我們在進(jìn)一步擴(kuò)展 Dubbo SDK 功能的同時,在周邊生態(tài)建設(shè)方面也做了不少工作,其中就包括在 2020 年 3 月份上線的 Nacos 注冊中心等。
2. Apache Dubbo 在愛奇藝的發(fā)展歷史
優(yōu)秀的微服務(wù)開發(fā)框架是業(yè)務(wù)服務(wù)化的基石,但是由于微服務(wù)應(yīng)用的復(fù)雜性,要幫助業(yè)務(wù)團(tuán)隊更好地實踐微服務(wù)架構(gòu),還需要一個相對完善的微服務(wù)生態(tài)體系作為支撐。
微服務(wù)生態(tài)體系
下圖展示了目前愛奇藝內(nèi)部微服務(wù)生態(tài)體系的全景。
這里面分為幾個層面:
-
首先是開發(fā)框架層面,Dubbo SDK 集成了注冊發(fā)現(xiàn)、通信及負(fù)載均衡的能力,但是類似熔斷及限流功能還是需要采用 Sentinel 等框架來進(jìn)行支持;
-
在基礎(chǔ)設(shè)施層面,注冊中心/配置中心均是微服務(wù)生態(tài)中重要組件;此外為了保證應(yīng)用的可用性,完整的監(jiān)控體系也必不可少,如指標(biāo)監(jiān)控、日志監(jiān)控、鏈路追蹤等;
-
最后,為了方便運(yùn)維人員管理微服務(wù)應(yīng)用,還需要一套功能完善的管理平臺,其中包括了服務(wù)管理、配置下發(fā)、監(jiān)控告警及一些對開發(fā)人員的支持功能。
可以看到,整個微服務(wù)的生態(tài)體系還是非常龐大的,限于篇幅,以下的演講會主要會集中在以下幾個方面展開:
- Dubbo SDK 的擴(kuò)展
- 生態(tài)體系建設(shè)
- 注冊中心的演進(jìn)
- 監(jiān)控體系的建設(shè)
- 熔斷限流方面的支持
1. Dubbo SDK 的擴(kuò)展
根據(jù)愛奇藝內(nèi)部的實際情況,以及各個業(yè)務(wù)團(tuán)隊的需求,我們主要對 Dubbo SDK 做了以下幾方面的擴(kuò)展:
- 基礎(chǔ)設(shè)施的適配:包括注冊中心、監(jiān)控系統(tǒng)、內(nèi)部的容器平臺等等;
- 可用性增強(qiáng):包括非健康實例隔離以及區(qū)域就近路由的機(jī)制;
- 安全性增強(qiáng):支持了服務(wù)間調(diào)用的認(rèn)證機(jī)制;
- 序列化:增加了對 protobuf 序列化方式的支持。
1)非健康實例隔離機(jī)制
首先介紹非健康實例隔離機(jī)制。
Dubbo SDK 默認(rèn)采用隨機(jī)的負(fù)載均衡策略,并通過失敗重試的策略來保證調(diào)用的成功率。通過實踐發(fā)現(xiàn),生產(chǎn)環(huán)境中有時會出現(xiàn)少數(shù) Provider 節(jié)點(diǎn)雖然已經(jīng)處于不健康的狀態(tài)(比如磁盤寫滿等),但是還是能與注冊中心進(jìn)行正常通信,這樣 Consumer 端還是能發(fā)現(xiàn)這些實例,導(dǎo)致部分請求還是會被分發(fā)過去。這些請求由于實例本身的問題,可能會出現(xiàn)響應(yīng)時間變慢或者錯誤率上升,從而引起整個服務(wù)質(zhì)量的下降(響應(yīng)時間抖動或整體調(diào)用成功率下降)。
為了解決這樣一個問題,我們的思路是引入客戶端健康檢查機(jī)制,即 Consumer 端會對每個 Provider 實例的請求成功率進(jìn)行統(tǒng)計,判斷其是否健康;對于不健康的 Provider 實例,Consumer 端會對其進(jìn)行隔離一段時間,后續(xù)的請求不再通過負(fù)載均衡策略發(fā)送到這些實例上。另外 Consumer 端會維護(hù)每個 Provider 實例被隔離的次數(shù),如果某個實例被多次隔離,每次隔離的時間也會相應(yīng)變長。
我們的擴(kuò)展機(jī)制中提供了默認(rèn)的健康檢查策略,包括檢查最近一次調(diào)用是否出現(xiàn)服務(wù)端異常,或者一段時間內(nèi)是否有大量發(fā)出的請求未被返回。用戶也可以通過擴(kuò)展我們提供的接口來實現(xiàn)自己的檢查策略。
為了避免因為網(wǎng)絡(luò)抖動等造成的意外影響,我們還設(shè)計了一套兜底機(jī)制。即當(dāng) Provider 實例中不健康的比例超過一定閾值時,Consumer 會忽略實例隔離的策略,避免集中的流量將剩余的實例打垮。
2)區(qū)域就近路由機(jī)制
接下來介紹一下區(qū)域就近路由機(jī)制。
愛奇藝在多地都建有機(jī)房,為了確保在單個機(jī)房出現(xiàn)故障時各業(yè)務(wù)系統(tǒng)仍能正常工作,核心業(yè)務(wù)一般會采用兩地三中心的架構(gòu)進(jìn)行部署。在這種場景下,系統(tǒng)如果產(chǎn)生跨地域的訪問請求,由于網(wǎng)絡(luò)延時的原因勢必導(dǎo)致請求延時增大,所以各業(yè)務(wù)一般都有客戶端就近訪問服務(wù)端實例的需求。
我們通過擴(kuò)展 Dubbo 的路由機(jī)制實現(xiàn)了這樣的策略。大致的實現(xiàn)原理是,Provider 和 Consumer 實例在啟動時,會先從一個公共的地域服務(wù)中獲取實例當(dāng)前所在地域信息(比如可用區(qū)等)。Provider 實例在服務(wù)注冊時會將上述的地域信息作為 URL 的一部分注冊到注冊中心,這樣 Consumer 實例就能夠在服務(wù)發(fā)現(xiàn)時獲知每個 Provider 實例的地域信息并和自身的地域信息進(jìn)行比對,優(yōu)先選擇臨近的實例就近訪問。
此外,Consumer 實例也會通過上文中提到的健康檢查機(jī)制對服務(wù)端實例進(jìn)行檢查,如果發(fā)現(xiàn)本地域健康的 provider 實例低于設(shè)定比例時,則會忽略就近路由的策略,改為在所有的 Provider 實例中進(jìn)行負(fù)載均衡,從而實現(xiàn)自動的 failover 機(jī)制。
3)認(rèn)證機(jī)制
部分內(nèi)部服務(wù)有安全認(rèn)證相關(guān)的需求,不希望非授權(quán)應(yīng)用對其進(jìn)行訪問。為了解決這個問題,我們開發(fā)了一套基于數(shù)字簽名及 AK/SK 的認(rèn)證體系。
其基本原理是:
- Provider 服務(wù)可以通過配置在某個service上開啟鑒權(quán);
- 需要訪問敏感服務(wù)的 Consumer 應(yīng)用,需要在微服務(wù)平臺上進(jìn)行申請,審批后會在這個授權(quán)關(guān)系上生成一對 AK/SK 并同步至鑒權(quán)服務(wù);
- Provider/Consumer 與鑒權(quán)服務(wù)進(jìn)行通信,獲取相關(guān)的 AK/SK,這個過程使用 HTTPS 進(jìn)行通信;
- Consumer 在發(fā)起調(diào)用時,會對請求參數(shù)等生成一個數(shù)字簽名,連同時間戳、AK 等信息一起發(fā)送給 Provider 端;
- Provider 在收到請求時,會對其數(shù)字簽名等信息進(jìn)行核對,確認(rèn)請求信息的來源及數(shù)據(jù)的完整性。
以上介紹的是我們針對 Dubbo SDK 的擴(kuò)展內(nèi)容,接下來主要介紹我們在微服務(wù)生態(tài)方面的建設(shè)。
2. 生態(tài)體系建設(shè)
注冊中心在微服務(wù)應(yīng)用中是最重要的基礎(chǔ)設(shè)施之一,在 Dubbo SDK 引入之初,為了快速落地,我們使用了 ZooKeeper 作為注冊中心。當(dāng)然實際上 ZooKeeper 并不是微服務(wù)注冊中心的最佳選型,它的主要缺點(diǎn)包括:
- 無法橫向擴(kuò)展;
- 作為一個一致性的系統(tǒng),在網(wǎng)絡(luò)分區(qū)會產(chǎn)生不可用。
1)注冊中心演進(jìn)
在調(diào)研了業(yè)界的各個方案后,我們選用了 Nacos 作為我們下一代的微服務(wù)注冊中心。下圖右下角是 Nacos 的整體介紹圖,選用 Nacos 的主要原因是:
- 高性能,可以橫向擴(kuò)展;
- 既適用于傳統(tǒng)為服務(wù)架構(gòu),也能適用于云原生環(huán)境,包括支持與 Istio 控制面對接;
- 提供了 Nacos-Sync 組件,可以用較低的成本進(jìn)行注冊中心的遷移。
在部署 Nacos 服務(wù)時,我們充分考慮了服務(wù)部署架構(gòu)方面的高可用性。目前我們的 Nacos 服務(wù)是一個大集群,實例分布在多個不同的可用區(qū)中,在每個可用區(qū)內(nèi)部,我們會申請不同的 VIP,最終的內(nèi)網(wǎng)域名是綁定在這些 VIP 上。另外其底層所使用的 MySQL 也采用了多機(jī)房部署。這樣的架構(gòu)可以避免單個 Nacos 實例或者單機(jī)房故障造成整個 Nacos 服務(wù)的不可用。
以下是一些可能的故障場景的模擬:
- 單個 Nacos 實例故障:利用 Load Balancer 集群提供的健康檢查能力自動從 VIP 中摘除;
- 某個 VIP 集群故障:利用客戶端重試機(jī)制解決;
- 單個 AZ 故障:利用客戶端重試機(jī)制解決;
- MySQL 集群故障:MySQL 與注冊發(fā)現(xiàn)過程無關(guān),不受影響;
- 整個 Nacos 服務(wù)故障:客戶端兜底機(jī)制,如服務(wù)實例緩存等。
接下來將簡單介紹一下如何使用 Nacos-Sync 進(jìn)行注冊中心的平滑遷移。
-
首先要部署一個 Nacos-Sync 服務(wù),從舊的注冊中心向 Nacos 同步數(shù)據(jù)。Nacos-Sync 支持集群化部署,部署多個實例時,其向新注冊中心的寫入時冪等的,并且它原生支持 Dubbo 的注冊數(shù)據(jù)格式;
-
檢查數(shù)據(jù)無誤后,首先升級 Consumer 端,改為從 Nacos 注冊中心進(jìn)行發(fā)現(xiàn)。這時的服務(wù)發(fā)現(xiàn)的數(shù)據(jù)均是由 Nacos-Sync 從舊的注冊中心同步過來的;
-
再升級 Provider 端,改為向 Nacos 進(jìn)行服務(wù)注冊;
-
下線 Nacos-Sync 服務(wù)及舊的注冊中心,整個遷移流程就結(jié)束了。
2)監(jiān)控體系建設(shè)
接下來主要介紹我們內(nèi)部微服務(wù)監(jiān)控體系的建設(shè)。完整的微服務(wù)監(jiān)控體系一般由以下 3 個方面組成:
-
指標(biāo)監(jiān)控:包括 QPS / 響應(yīng)延時 / 錯誤率等黃金指標(biāo)、業(yè)務(wù)的自定義指標(biāo)、JAVA 應(yīng)用的 JVM 指標(biāo),此外還需要采集和基礎(chǔ)環(huán)境的相關(guān)指標(biāo),包括 CPU / 內(nèi)存利用率等;
-
日志監(jiān)控:如錯誤日志的數(shù)量;也可以利用 AI 技術(shù),對日志的模式進(jìn)行統(tǒng)計分析等;
-
鏈路監(jiān)控:由于微服務(wù)調(diào)用關(guān)系的復(fù)雜性,調(diào)用鏈追蹤也是非常必要的,它可以幫助業(yè)務(wù)人員更好地分析應(yīng)用間的依賴關(guān)系,并能夠監(jiān)控各個調(diào)用關(guān)系上的核心指標(biāo)。
指標(biāo)監(jiān)控方面,我們內(nèi)部圍繞著 Prometheus 建設(shè)了一套較為完整的監(jiān)控和告警的方案。這里面要解決幾個問題:
首先是指標(biāo)計算的問題,為了降低侵入性,我們在 skywalking agent 的基礎(chǔ)上進(jìn)行了二次開發(fā),可以自動攔截 Dubbo 的調(diào)用,統(tǒng)計其調(diào)用次數(shù)、處理耗時、是否錯誤等等。
其次是指標(biāo)采集的問題,Prometheus 是采用拉模式采集指標(biāo)的,對于微服務(wù)場景一般是利用 Prometheus 的服務(wù)發(fā)現(xiàn)機(jī)制。Prometheus 默認(rèn)集成了 consul、K8s 等服務(wù)發(fā)現(xiàn)方式,不過并未對 Nacos 注冊中心直接提供支持,我們在開源的 Nacos adapter 的基礎(chǔ)上進(jìn)行了改造,使得 Prometheus 能夠從 Nacos 中發(fā)現(xiàn)要采集的應(yīng)用實例信息。
指標(biāo)查看主要采用了 grafana,我們提供了一套通用化的配置模板,業(yè)務(wù)也可以根據(jù)需要自行擴(kuò)展。
告警方面,我們將告警策略設(shè)置在 Prometheus 中,具體的告警會由 alert-manager 通過 adapter 發(fā)送給內(nèi)部的監(jiān)控告警平臺。
監(jiān)控 dashboard 查看、告警策略設(shè)置、訂閱的入口統(tǒng)一設(shè)置在我們內(nèi)部的全鏈路監(jiān)控平臺上,用戶可以在該平臺上查看進(jìn)行相應(yīng)的操作。
下圖展示的是服務(wù)監(jiān)控界面:
鏈路追蹤的基本原理也和 google 關(guān)于 Dapper 的論文一致,應(yīng)用程序通過埋點(diǎn)的 agent 產(chǎn)生調(diào)用鏈數(shù)據(jù),通過日志采集或者網(wǎng)絡(luò)直接上報的方式統(tǒng)一匯總至 kafka,通過我們的實時分析程序進(jìn)行分析。
分析結(jié)果大致可以分為三類:
- 原始的調(diào)用鏈數(shù)據(jù)我們會使用 ES+HBase 進(jìn)行存儲;
- 調(diào)用關(guān)系上的實時監(jiān)控數(shù)據(jù)我們采用時序數(shù)據(jù)庫 druid 進(jìn)行存儲;
- 拓?fù)潢P(guān)系采用圖數(shù)據(jù)存儲。
3)熔斷限流
最后簡單介紹一下利用 sentinel 框架進(jìn)行熔斷和限流的相關(guān)內(nèi)容。
由于微服務(wù)架構(gòu)的特點(diǎn),上下游依賴和網(wǎng)絡(luò)通信都比較多,這些因素都會對應(yīng)用本身產(chǎn)生一定的風(fēng)險,比如上游系統(tǒng)的突發(fā)流量或者熱點(diǎn)參數(shù);下游系統(tǒng)服務(wù)不可用、延時增大、錯誤率升高等等。如果缺少對自身系統(tǒng)的保護(hù),有可能產(chǎn)生雪崩的效應(yīng)。為了應(yīng)對這些場景,我們主要引入了 Sentinel 框架進(jìn)行解決。
Sentinel 的核心原理是用戶可以定義各類資源(資源可以是本地的一個接口,或者遠(yuǎn)程的某個依賴),并在資源上設(shè)置各種規(guī)則(比如限流規(guī)則),在訪問某個資源時,Sentinel 組件會檢查這些規(guī)則是否滿足,在不滿足的情況下會拋出特定的異常。用戶可以通過捕捉這些異常實現(xiàn)快速失敗或者降級等業(yè)務(wù)邏輯。Sentinel 還提供了一個控制臺,可以用來管理規(guī)則的參數(shù)設(shè)置以及查看實時監(jiān)控等。
為了適應(yīng)內(nèi)部業(yè)務(wù)團(tuán)隊的需求,我們對 sentinel 框架也做了一些擴(kuò)展,下面的例子即是我們實現(xiàn)的復(fù)雜參數(shù)限流功能。Sentinel 框架本身就自帶熱點(diǎn)參數(shù)限流的功能,不過僅支持一些簡單類型的參數(shù)(如 String、int 等)。在有些情況下,限流的場景可能比較復(fù)雜,比如下圖中,可能要根據(jù)第一個參數(shù)的 id 屬性進(jìn)行限流,這種場景原生的 sentinel 并未提供支持。針對這種情況,我們提供了一個抽象的接口,允許用戶通過自己的實現(xiàn)從參數(shù)中提取出需要限流的資源。
為了實現(xiàn)規(guī)則參數(shù)的動態(tài)下發(fā),我們將 sentinel 與內(nèi)部的配置中心進(jìn)行了適配。在 sentinel dashboard 上進(jìn)行的參數(shù)改動,最后都會保存至配置中心,業(yè)務(wù)系統(tǒng)通過引入配置中心的 SDK,即可實現(xiàn)在不重啟應(yīng)用的前提下進(jìn)行參數(shù)的動態(tài)調(diào)整。
在我們的微服務(wù)管理平臺上,還提供了 sentinel dashboard 的托管功能。
發(fā)展現(xiàn)狀及開源貢獻(xiàn)
愛奇藝引入 Dubbo 的時間并不長,但是由于其較為穩(wěn)定的線上表現(xiàn)使得的各個業(yè)務(wù)團(tuán)隊的整體接受度較高,上線的規(guī)模也在快速增長。短短一年內(nèi)累計已上線了一百多個線上服務(wù),實例數(shù)也已經(jīng)超過五千個。
此外,我們也在使用過程中積極回饋社區(qū),截止目前共提交了三十個左右的補(bǔ)丁,上文中提到的認(rèn)證機(jī)制也已貢獻(xiàn)給社區(qū),成為 Dubbo 2.7.6 版本的新特性之一。在這個過程中,團(tuán)隊中也誕生了一位社區(qū)的 committer。
未來規(guī)劃
對于未來的規(guī)劃,大概有以下幾方面的工作:
-
云原生與 service mesh 已經(jīng)是微服務(wù)技術(shù)演進(jìn)的一個趨勢了,且在一些公司已經(jīng)有了比較大規(guī)模的實踐。如何將 dubbo 與 service mesh 結(jié)合,如何提供平滑過渡的解決方案,將會是我們今后工作的一個重點(diǎn);
-
在服務(wù)治理方面,后續(xù)我們希望能夠建立一個對 service mesh 和傳統(tǒng)微服務(wù)都適用的控制面;
-
在開發(fā)者支持方面,我們計劃推出項目腳手架以及在線調(diào)試等服務(wù),使得開發(fā)人員能更方便地進(jìn)行項目開發(fā),以及線上問題的排查等。
阿里巴巴云原生公眾號后臺回復(fù)?818?即可獲取直播回看地址和大會 PPT 合集。
“阿里巴巴云原生關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢、云原生大規(guī)模的落地實踐,做最懂云原生開發(fā)者的公眾號。”
總結(jié)
以上是生活随笔為你收集整理的爱奇艺在 Dubbo 生态下的微服务架构实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记 Arthas 实现一次 CPU 排查
- 下一篇: 打造数字化服务能力,中国联通如何借助云原