Dubbo的前世今生
搜索關注微信公眾號”捉蟲大師”,後端技術分享,架構設計、性能優化、源碼閱讀、問題排查、踩坑實踐。
本文已收錄 //github.com/lkxiaolou/lkxiaolou 歡迎star。
背景
在很久以前,網站應用是單體應用的架構,流量小,所有功能、程式碼都部署在一起,成本低。此時資料庫訪問框架ORM是關鍵。
後來流量逐漸增大,單體應用被拆分為互不相干的多個應用,這就是垂直架構,此時加速前端頁面開發的Web框架MVC是關鍵。
再後來,垂直應用越來越大,應用間的交互不可避免,分散式服務框架RPC變成了關鍵。
dubbo
RPC,全稱Remote Procedure Call,即遠程過程調用,一句話描述就是調用遠程對象就像調用本地方法一樣方便簡單。常見的RPC框架有dubbo、grpc、thrift等。
dubbo, |ˈdʌbəʊ| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向介面的遠程方法調用,智慧容錯和負載均衡,以及服務自動註冊和發現。目前使用dubbo的公司非常多。
前世今生
dubbo的發展歷程可以總結為3個階段:
- 誕生阿里:dubbo前生2008年在阿里內部誕生,2011年開源,2012年發布2.5.3版本後停止更新
- 噹噹續命:2014年噹噹發布dubbox,是基於阿里開源的dubbo 2.5.3版本增加rest協議的dubbo版本
- 重啟登頂apache:2017年阿里重啟dubbo項目,並於2018年進入apache孵化,2019年成為apache頂級項目,同時也發布了dubbo.js,dubbo-go等多語言dubbo版本,2020年發布3.0往雲原生項目發展的戰略計劃
目前支援的版本主要是2.6.x和2.7.x:
- 2.6.x 主要以 bugfix 和少量 enhancements 為主,因此能完全保證穩定性
- 2.7.x 作為社區的主要開發版本,得到持續更新並增加了大量新 feature 和優化,同時也帶來了一些穩定性挑戰
協議
dubbo原生的協議定義如下:
- 0-15: 魔數,判斷是否是dubbo協議
- 16: 判斷是請求還是返回
- 17: 判斷是否期望返回
- 18: 判斷是否為事件消息,如心跳事件
- 19-23: 序列化標誌
- 24-31: 標誌響應狀態(類似http status)
- 32-63: 請求id
- 64-95: 內容長度(位元組)
- 96-?: 序列化後的內容(換行符分隔)
dubbo協議的優點是設計緊湊、請求響應的header一致;缺點是無法通過header定位資源,header和body中欄位存在冗餘,協議無法擴展。
當然同時也支援擴展多種協議,如噹噹擴展的rest協議,還有最新支援的grpc協議等
說到擴展,可能是dubbo設計的最大亮點,dubbo的擴展基於SPI(Service Provide Interface)設計,可以無侵入程式碼實現非常多的功能。
註冊中心
註冊中心有如下特點:
- 動態加入,服務提供者通過註冊中心動態的把自己暴露給消費者,無需消費者逐個更新配置文件。
- 動態發現服務,消費者可以動態發現新的服務,無需重啟生效。
- 統一配置,避免本地配置導致每個服務配置不一致。
- 動態調整,註冊中心支援參數動態調整,新參數自動更新到所有相關的服務節點。
- 統一管理,依靠註冊中心數據,可以統一管理配置服務節點。dubbo主流的註冊中心一般用zookeeper或者nacos,其他還有很多擴展實現。
集群
集群包含了路由、負載均衡和集群容錯三個內容,從一個例子來看這三方面的差異:
一個dubbo的用戶服務,在北京部署了10個,在上海部署了20個。一個杭州的服務消費方發起了一次調用,然後發生了以下的事情:
- 根據配置的路由規則,如果杭州發起的調用,會路由到比較近的上海的20個provider。
- 根據配置的隨機負載均衡策略,在20個provider中隨機選擇了一個來調用
- 假設隨機到了第7個provider。結果調用第7個 provider 失敗了。根據配置的failover集群容錯模式,重試其他伺服器。重試了第13個provider,調用成功。
這裡1對應了路由,2對應了負載均衡,3對應了集群容錯。
filter
在dubbo的整體設計中,filter是一個很重要的概念,包括dubbo本身的大多數功能,都是基於此擴展點實現的,在每次的調用過程中,filter的攔截都會被執行。filter是一種責任鏈的設計模式:
常見的filter:監控打點、日誌記錄、限流降級、鑒權等。
三大中心
三大中心指註冊中心,元數據中心,配置中心。為什麼需要三大中心,可以看一條dubbo註冊到註冊中心上的數據:
/dubbo/org.apache.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F172.23.234.48%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddubbo-demo-api-provider%26default%3Dtrue%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.demo.DemoService%26metadata-type%3Dremote%26methods%3DsayHello%2CsayHelloAsync%26pid%3D21563%26release%3D%26side%3Dprovider%26timestamp%3D1600336623852
可以看出數據量很大,這還是介面級的數據,當介面數量越來越多,註冊中心的壓力越來越大,變更推送的數據越來越多。
所以,我們需要元數據中心和配置中心來減輕註冊中心的壓力。不經常變化的數據可以放在元數據中心。
/dubbo/org.apache.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F172.23.234.48%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fapplication%3Ddubbo-demo-api-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26timestamp%3D1600336144382
配置中心也是如此,如果沒有配置中心需要全量將變更的url推送下去,有了配置中心只需要推送變更的配置即可。
泛化調用
我們常見的dubbo調用方式是引入provider定義的介面jar包,但如果沒有這個jar包,能否發起調用?當然是可以,也確實有這樣的場景,比如服務測試平台,dubbo服務網關等。只要知道介面名,參數等資訊即可發起調用。
未來發展
dubbo當時的未來規劃其實走了個曲線,並不是一步到現在的雲原生方向。2019年想走的方向是響應式編程(或者叫反應式編程)。IO密集型的應用,通常執行緒池是限制吞吐的重要因素之一,假設consumer執行緒池為100,provider介面響應時間為500ms,consumer的qps上限為 (1000 / 500) x 100 = 200。響應式編程就是解決這個問題。
響應式編程(reactive programming)是一種基於數據流(data stream)和變化傳遞(propagation of change)的聲明式(declarative)的編程範式。RSocket 是一個支援 reactive-stream 語義的開源網路通訊協議,它將 reactive 語義的複雜邏輯封裝了起來,使得上層可以方便實現網路程式。Dubbo 在 3.0.0-SNAPSHOT 版本里基於 RSocket 對響應式編程提供了支援,用戶可以在請求參數和返回值里使用Mono和Flux類型的對象。
但到了2020年,隨著雲原生概念的興起和大廠紛紛地落地,dubbo是否也可以朝這個方向發展呢?
雲原生是基於容器、服務網格、微服務、不可變基礎設施和聲明式API構建的可彈性擴展的應用,基於自動化技術構建具備高容錯性、易管理和便於觀察的松耦合系統,構建一個統一的開源雲技術生態,能和雲廠商提供的服務解耦。
dubbo的服務級註冊發現,與k8s容器編排的應用級服務發現相違背,dubbo是「重sdk」,與易管理相違背。
所以在最新的版本中支援了應用級的服務發現,原先是這樣的一個介面:
/dubbo/org.apache.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F172.23.234.48%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fapplication%3Ddubbo-demo-api-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26timestamp%3D1600336144382
使用應用級服務發現註冊到註冊中心上是這樣
/services/dubbo-demo-api-provider/172.23.234.48:20880
而重sdk,未來可能會被mesh改善,據說阿里內部已經有dubbo mesh落地的業務線了。
搜索關注微信公眾號”捉蟲大師”,後端技術分享,架構設計、性能優化、源碼閱讀、問題排查、踩坑實踐。
本文已收錄 //github.com/lkxiaolou/lkxiaolou 歡迎star。