- 👏作者簡介:大家好,我是愛吃芝士的土豆倪,24屆校招生Java選手,很高興認識大家
- 📕系列專欄:Spring源碼、JUC源碼、Kafka原理、分布式技術原理
- 🔥如果感覺博主的文章還不錯的話,請👍三連支持👍一下博主哦
- 🍂博主正在努力完成2023計劃中:源碼溯源,一探究竟
- 📝聯系方式:nhs19990716,加我進群,大家一起學習,一起進步,一起對抗互聯網寒冬👀
文章目錄
- Dubbo進階
- 多序列化支持
- 性能優化參數
- Dubbo緩存文件
- Dubbo是如何實現的
- Dubbo模塊說明
- Dubbo 流程分析及擴展
Dubbo進階
對于我們使用這個框架來說,如果會用了以后,更多的可能是需要關心一下為什么要使用這個功能?
它是怎么實現服務的注冊,怎么實現服務的發現,以及怎么去動態的更新服務、怎么去負載均衡。
對于一個技術的使用來說,我們可以不去了解這個技術本身原理性的東西就可以去使用了,對于實際的應用開發來說,可能只有項目開始的時候才會去搭建這些技術的整合,配置這些組件和各種工具類等等。搭建好之后,后面大部分的開發都是 ctrl cv的動作,在框架整合來說都是可以復制粘貼的,但是對于業務來說Controller、Service本質上沒什么變化。
多序列化支持
Dubbo支持多種序列化方式,包括Hessian、Java原生序列化、JSON、FastJSON、Kryo等。用戶可以根據自己的需求選擇合適的序列化方式來進行數據交換。這樣可以提高系統的靈活性和性能,使得Dubbo可以適應不同的應用場景。
- 添加jar包支持
<dependency><groupId>com.esotericsoftware</groupId><artifactId>kryo</artifactId><version>4.0.2</version>
</dependency>
<dependency><groupId>de.javakaffee</groupId><artifactId>kryo-serializers</artifactId><version>0.45</version>
</dependency>
- 添加序列化支持
dubbo.protocol.serialization=kryo
客戶端在調用的時候也需要加入以上操作。
多序列化的支持意味著Dubbo可以根據不同的應用場景和需求選擇合適的序列化方式,從而提高系統的靈活性和性能。不同的序列化方式有不同的特點,比如Hessian序列化速度快,但占用內存較多;而JSON序列化則占用內存較少,但速度可能稍慢。因此,通過支持多序列化方式,Dubbo可以根據具體情況選擇最合適的序列化方式,從而提高系統的性能和效率。另外,支持自定義序列化方式也意味著用戶可以根據自己的需求實現自己的序列化方式,從而更好地滿足特定的業務需求。因此,多序列化的支持可以使Dubbo更加靈活、高效地應對不同的應用場景和需求。
性能優化參數
dubbo服務里有很多性能優化的參數,這些參數無非就是線程、連接(客戶端和服務端建立的連接是長連接還是短連接,是共享連接還是非共享連接)因為這些比較基礎的點可能會影響整體的性能。
對應參數在實際鏈路中起作用的環節
首先當客戶端發起一個請求的時候,針對每個服務消費者每服務每方法最大并發調用數進行了設置,當超過最大并發數的時候會被拒絕掉,這里是采用一個原子計數器去實現的。
緊接著會對連接數量做限制,這個對于很多的池化的技術組件,比如數據庫連接池等都會這樣做限制,這個限制本質上就是控制資源的使用。Dubbo協議是長連接協議,當客戶端和服務端建立這個連接之后,這個連接不會關,一直會處于一個打開狀態,后續的請求如果發現Dubbo里已經有打開的連接,那就用這個連接的通道去進行數據傳輸。
經過請求之后到了服務端,判斷總的連接數是否超過限制。
接著到了線程層面,消耗的是cpu資源,而連接層面消耗的是內存 和 網絡通信延遲。其實際的調優就像普遍的線程池調優一樣,最后還有executes 對服務提供者每服務每方法最大可并行執行請求數進行限制。
Dubbo緩存文件
配置服務地址的緩存,避免注冊中心掛了之后對于服務通信的影響
dubbo.registries.shanghai.zone=shanghai
dubbo.registries.shanghai.weight=100
dubbo.registries.shanghai.file=${user.home}/dubbo_shanghai.cachedubbo.registries.hunan.address=nacos://192.168.216.128:8848
dubbo.registries.hunan.weight=10
dubbo.registries.hunan.preferred=true
dubbo.registries.hunan.file=${user.home}/dubbo_hunan.cache
Dubbo是如何實現的
對于一個技術的使用來說,使用的多了以后會更加的熟練,但是使用的過程中如果出現了問題,能不能快速的定位到問題,其次就是在用這個技術的時候,能不能去了解其底層是怎么實現的。
圖中左側藍色區域表示服務消費者,右側表示服務提供者,它們都是基于Interface。
消費服務的時候會經過這幾個層,首先經過服務層 Service,然后到了配置層Config,該層主要是為了加載Dubbo配置的屬性文件。
緊接著到了代理層,其中代理類對進行遠程調用,所以代理類要去 Registry 注冊層去得到具體要調用哪個服務。
而 Registry 注冊層 中 RegistryProtocol 基于注冊中心的協議,因為 Registry 層中有不同的注冊中心,該層通過 RegistryFactory 去獲得注冊中心的地址,然后通過 NotifyListener去動態的監聽具體要調用哪個服務的地址變化,該地址以目錄的方式存儲在 RegistryDirectory中,里面存儲了多個地址。
然后到了 Cluster 集群層,集群容錯是在這里面做的,在 Registry 層拿到地址了需要去調用,調用之前,會進行容錯的調用、負載均衡等。LoadBalance是基于上一個環節所拿到的地址,通過LoadBalance 進行 select 之后,這時候得到一個最終的 Invoker (是Dubbo里面的核心機制,可以基于此做遠程調用)
此時拿到了 Invoker ,去進行調用,調用的過程中會有一系列的過濾器,形成鏈式進行過濾,當過濾器鏈處理完成后會通過協議去處理。
而協議中有個很關鍵的類叫做 DubboProtocol ,在這里是可以去擴展的,Protocol是一個擴展點,我們在使用的時候在這個擴展點用什么協議取決于 RegistryDirectory 列表中url 中的協議,該url會一直沿著鏈路傳遞,直到Protocol來選擇要使用的協議,然后進行轉發。
轉發之后,通過 Exchange 交換層 (該層主要負責服務的通信這一塊)
Transport 就是 交換的協議,主要基于Netty,在協議以后要在 Serialize中做序列化 和 反序列化,在這之后,會拿到數據進行處理,最終會去調用我們的服務提供者。
而服務提供者這邊,其基于Interface,首先會去發布一個服務(exprot),首先也是先從config 去加載服務端的配置,然后把這個配置信息組裝成一個url 去添加到注冊中心上,這也是我們能夠在zk或者nacos上看到的基于服務發布的注冊中心地址的一個原因。
然后緊接著到了 MoiniorFactory ,這里面就是服務監控,然后就是 Exporter 發布了,發布是以什么協議發布出去?同樣也會根據當前config里所配置的信息,去選擇一個對應的協議去發布。
在我們整個框架中,不管是注冊中心也好,不管是LoadBalance也好,其都有一個核心的東西叫做擴展點,其基于SPI的機制進行選擇(包含三種擴展點:自適應擴展點、激活擴展點、指定名字的擴展點)
最終發布會通過 Netty Server去注冊一個監聽。
整體串起來的話,就是客戶端去發起請求,會通過前面講的消費者的鏈路,最終去調用 服務發布者的 Implement。
Dubbo模塊說明
- Dubbo-bom 版本管理清單
- Dubbo-build-tools 版本構建工具
- Dubbo-cluster 路由層,包含負載均衡、容錯等
- Dubbo-Common 提供一些公共包
- Dubbo-Compatible 解決兼容問題,解決com.alibaba.dubbo 升級到 org.apache.dubbo所產生的變化,其實就是將一些com.alibaba.dubbo 老的功能單獨拎出來
- Dubbo-Config 加載配置,然后提供統一的對外配置的類
- Dubbo-ConfigCenter 動態配置中心,通過第三方配置中心來統一管理dubbo的配置
- Dubbo-Container 容器 Main.main(args) //啟動dubbo
- 啟動Dubbo首先加載spring 的配置或者注解, applicationContext=new …();,再去根據配置的信息來啟動一個NettServer。
- Dubbo-Filter 過濾
- Dubbo-Metadata 元數據(配置數據)
- Dubbo-Monitor 監控模塊(針對服務的調用會產生監控的數據,然后將這些數據上報)
- Dubbo-Plugin 插件 auth(授權) qos
- Dubbo-Registry 注冊中心
- Dubbo-Remoting 遠程協議支持(包括http、netty)
- Dubbo-RPC rpc協議/通信的支持
- Dubbo-Serialization 序列化支持
Dubbo 流程分析及擴展
此圖為上面圖的簡化版本,純粹的面向整個調用鏈去工作的。
其中深綠色部分統一叫做擴展點,Dubbo的每一個點其實都可以擴展。
整個過程還是一樣,藍色部分表示消費者,綠色部分表示服務提供者,這張圖的通信部分就更加清晰了。
首先Proxy是生成一個動態代理,動態代理有兩種方式 jdk、javassist 這個是可擴展的。
然后是filter 會進行過濾,其中有緩存、權限等,這些過濾主要是針對這些請求里面進行的攔截,其可擴展。
然后就是Invoker,是Dubbo內部封裝的對象,其表示遠程通信的對象,對Invoker會有 Cluster里面對應的操作,包括failover、failsafe等,當然其本身也是一個擴展點。
然后會去拿到注冊中心上的 Directory,其表示的是服務的地址列表,所有的注冊中心都是基于 Directory進行交互。
當拿到這個列表以后,會去調用LoadBalance進行負載均衡,其也是可擴展的。
后面又經過Filter,會進行另外一個層次的過濾,比如泛化、計數器、限制等。
接下來就是針對具體遠程通信的Invoker,其會根據不同的協議,去發起通信,根據服務端是那種協議,就用那種協議去通信。
然后到了傳輸層,發起遠程通信,其也進行了擴展,可以采用的遠程通信有 netty mina,傳輸層的客戶端會建議遠程通信,其地址是通過前面在 Directory中在由 LoadBalance 獲取到的。
然后根據 codec 進行編碼,然后進行 Serialization 序列化。
以上就是在客戶端完成的動作。
首先是先線程池,這個在前面的性能優化參數圖上能夠很好的看出來。
然后是服務這邊接收到請求,主要是netty 和 mina,因為前面也是使用這兩個進行遠程通信,然后就是進行各種協議的處理,最后其服務端也會有一個過濾鏈。
然后服務端的Invoker在進行一個通信,通過動態代理去完成一個調用,當完成后,在返回。