- 深度剖析ApacheDubbo核心技術內幕
- 翟陸續
- 2681字
- 2020-03-02 16:12:11
前言
在單體應用時,不同業務模塊部署在同一個JVM進程內,這時通過本地調用就可以解決不同業務模塊之間的相互引用;但在多體應用時,不同業務模塊大多部署到不同的機器上,這時一個高效、穩定的RPC框架就顯得特別重要了。Apache Dubbo作為阿里巴巴開源的分布式RPC框架,是眾多RPC框架中比較優秀的一個,在進入Apache孵化器項目后現已畢業,相信在開源社區的不斷貢獻下,它會成為RPC框架中的佼佼者。
為何要研究Apache Dubbo的實現原理
引用筆者在《Java并發編程之美》一書前言中的論述:研究開源框架,特別是優秀的開源框架的實現原理,可以開拓我們的技術視野,提高我們的架構能力,減少由于使用不當導致的線上故障的發生。而在微服務大行其道的今天,RPC框架作為微服務之間通信的一種手段,其在微服務架構中占有一席之地,Apache Dubbo(后面簡稱Dubbo)則是RPC框架中比較優秀的代表,為了更好地使用它,其實現原理自然值得我們去探究。
下面我們具體談談通過研究Dubbo框架的實現原理,到底能學到什么。
我們首先可以學習和深刻體會到分層架構帶來的好處。Dubbo框架從整體上分為了業務(Business)層、RPC層和遠程調用(Remoting)層,其中業務層提供API,讓使用者方便地發布與引用服務;RPC層則是對服務注冊與發現、服務代理、路由、負載均衡等功能的封裝,該層又可以被劃分為很多層;遠程調用層則是對網絡傳輸與請求數據序列/反序列化等的抽象。使用分層架構可以保證下層的改變對上層不可見,并且可以實現關注點分離,比如使用者使用Dubbo時只關心如何使用業務層的API來發布與引用服務,而不需要關心RPC層的實現,當新版本Dubbo升級了RPC層的邏輯時,使用者只需要升級Dubbo的版本就可以了,這是因為RPC層的修改對業務層使用者來說是透明的。
我們也可以學習到好的框架應該具有可擴展性。Dubbo就是一個擴展性極強的框架,其RPC層中的所有組件都是基于SPI擴展接口實現的,每個組件都可以被替換;Dubbo增強了JDK中提供的標準SPI功能,并且增加了對擴展接口的IoC(一個擴展接口可以直接使用setter()方法注入其他擴展接口)和AOP的支持(可以使用Wrapper類對擴展接口進行功能增強);增強SPI不會一次性實例化擴展點的所有實現類,從而避免了當擴展點實現類初始化很耗時但當前還沒用上它的功能時,仍進行加載實例化這種浪費資源的情況;增強的SPI是在具體用到某個實現類時才對具體實現類進行實例化。
作為高可用分布式RPC框架,其自身必須具有容錯能力,以便提高系統的可用性。Dubbo框架則提供了分布式系統中常見的集群容錯策略,并且提供了擴展接口,讓使用方方便地定制自己的集群容錯策略,通過研究Dubbo框架提供的集群容錯策略,可以讓我們對分布式系統中的容錯技術有深入的理解。
在分布式系統中,每個微服務都是以集群的方式部署的,那么當我們訪問一個具體服務時到底訪問哪一臺機器提供的服務呢?這就是分布式系統中負載均衡器與路由規則要做的事情,作為分布式RPC框架,其自身也必須具有負載均衡的能力。Dubbo框架提供了分布式系統中常見的負載均衡策略,并且提供了擴展接口,讓使用者方便地定制自己的負載均衡策略;另外,路由規則提供了服務治理的一種策略,在Dubbo中我們可以通過管理控制臺來配置路由規則,讓消費者只可訪問那些服務提供者。通過研究Dubbo框架提供的負載均衡與路由策略,可以讓我們對分布式系統中的負載均衡技術與路由規則有深入的理解。
在分布式系統中,當我們要消費某個服務時,如何找到其地址是一個要解決的問題。在分布式RPC中,一個通用解決方案是引入服務注冊中心,當服務提供者啟動時,會自動把自己的服務注冊到服務注冊中心;當消費者啟動時,會去服務注冊中心訂閱自己感興趣的服務的地址列表。在Dubbo框架中,提供了擴展接口來方便地讓我們使用ZooKeeper、Redis等作為服務注冊中心,通過研究Dubbo原理,我們可以深刻理解服務提供方到底是如何把服務注冊到服務注冊中心的,以及服務消費端是如何動態地感知服務提供方地址列表變化的。
所有RPC框架要解決的一個問題是,如何讓使用者無感知地發起遠程過程調用,也就是讓使用者在發起遠程調用時有和本地調用一樣的體驗。Dubbo框架和其他RPC框架一樣,采用代理來實現該功能。在Dubbo框架中擴展接口Proxy就是專門來做代理使用的,并且其提供了擴展接口的JDK動態代理與Cglib的實現。研究Dubbo的原理,我們可以學習到消費端如何對服務接口進行代理以實現透明調用,服務提供端如何使用代理與JavaAssist技術來減少反射調用開銷。
在Dubbo的分層架構中,Transport網絡傳輸層把Mina和Netty抽象為統一接口,并且在默認情況下使用Netty作為底層網絡通信。通過研究Dubbo,我們可以學習到Dubbo的網絡協議幀是如何設計的;服務消費端是如何啟動Netty客戶端的,是如何把RPC請求封裝為協議幀并序列化然后通過Netty客戶端發起網絡請求的;服務提供端又是如何啟動Netty服務器進行服務監聽的,是如何處理經典的半包、粘包問題的,是如何把接收到的二進制包轉換為Dubbo協議幀并反序列化為POJO對象的。另外,使用Netty時都說不要在ChannelHandler中做阻塞的事情,以免阻塞了I/O線程,使其他請求得不到及時處理,那么這到底是什么意思呢?研究完Dubbo的線程模型后,你就會明白了。
對于網絡請求來說,同步調用是比較直截了當的,但是同步調用意味著當前發起請求的調用線程在遠端機器返回結果前必須阻塞等待,這顯然很浪費資源。好的做法是發起請求的調用線程發起請求后,注冊一個回調函數,然后馬上返回去做其他事情,當遠端把結果返回后再使用I/O線程執行回調函數,也就是發起方實現了異步調用,調用線程不會被阻塞。Dubbo則基于Netty的異步非阻塞能力和JDK 8中的CompletableFuture輕松地實現RPC請求的異步調用,提高了資源利用率。通過研究Dubbo的實現原理,我們可以對異步編程帶來的好處以及實現原理有深刻的體會。
……
總之,研究透徹Dubbo框架原理實現后,你會對分布式系統中的很多技術點有深入的理解。而筆者堅信分布式系統是應用的發展方向,因為隨著業務規模的增大,為了保障系統的可伸縮性、高可用性,系統必然朝著分布式方向發展。所以,掌握一些分布式系統中的優秀RPC框架的原理及實現細節,無論現在還是將來都將成為區別于他人的核心競爭力。
如何閱讀本書
本書分為三部分:第一部分為基礎篇,首先從整體上講解使用Dubbo搭建的系統由哪些模塊組成,各模塊相互之間的調用關系是怎么樣的,然后基于本書的Demo講解如何使用Dubbo;第二部分為高級篇,主要講解Dubbo框架內部的實現原理,包含支撐Dubbo框架的適配器類原理、動態編譯原理、增強SPI原理、消費端的泛化調用實現原理、消費端異步調用與服務提供端的異步執行、Dubbo框架的線程模型、消費端負載均衡策略、消費端集群容錯策略、并發控制原理、Dubbo網絡協議等;第三部分為實踐篇,主要探討如何使用Arthas和一些Demo來為研究Dubbo框架原理提供方便,并且講解如何基于CompletableFuture和Netty模擬RPC同步與純異步調用。
讀者可以在博文視點官方網站(http://www.broadview.com.cn)下載本書的Demo源碼。
- VMware vSphere 6.7虛擬化架構實戰指南
- Python Network Programming Cookbook(Second Edition)
- 精通Scrapy網絡爬蟲
- 劍指MySQL:架構、調優與運維
- UML 基礎與 Rose 建模案例(第3版)
- PySpark Cookbook
- Visual Basic程序設計上機實驗教程
- Babylon.js Essentials
- 小程序,巧應用:微信小程序開發實戰(第2版)
- Scratch趣味編程:陪孩子像搭積木一樣學編程
- Python Interviews
- Flink技術內幕:架構設計與實現原理
- Go語言入門經典
- 邊玩邊學Scratch3.0少兒趣味編程
- Docker:容器與容器云(第2版)