Dubbo 源文件主要包含以上這麼多包,其中:java
首先對dubbo-2.8.4.jar 源碼的一個截圖spring
公共邏輯模塊,包括 Util 類和通用模型。網絡
遠程通信模塊,至關於 Dubbo 協議的實現,若是 RPC 用 RMI 協議 則不須要使用此包。併發
Dubbo缺省協議採用單一長鏈接和NIO異步通信,適合於小數據量大併發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的狀況。app
鏈接個數:單鏈接
鏈接方式:長鏈接
傳輸協議:TCP
傳輸方式:NIO異步傳輸
序列化:Hessian二進制序列化
適用範圍:傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多,單一消費者沒法壓滿提供者,儘可能不要用dubbo協議傳輸大文件或超大字符串。
適用場景:常規遠程服務方法調用負載均衡
一、爲何要消費者比提供者個數多
因dubbo協議採用單一長鏈接,
假設網絡爲千兆網卡(1024Mbit=128MBytae),
根據測試經驗數據每條鏈接最多隻能壓滿7MByte(不一樣的環境可能不同,供參考),
理論上1個服務提供者須要20個服務消費者才能壓滿網卡。異步
二、爲何不能傳大包
因dubbo協議採用單一長鏈接,若是每次請求的數據包大小爲500KByte,假設網絡爲千兆網卡(1024Mbit=128MByte),每條鏈接最大7MByte(不一樣的環境可能不同,供參考),
單個服務提供者的TPS(每秒處理事務數)最大爲:128MByte / 500KByte = 262。
單個消費者調用單個服務提供者的TPS(每秒處理事務數)最大爲:7MByte / 500KByte = 14。
若是能接受,能夠考慮使用,不然網絡將成爲瓶頸。ide
爲何採用異步單一長鏈接:
由於服務的現狀大都是服務提供者少,一般只有幾臺機器, 而服務的消費者多,可能整個網站都在訪問該服務,
好比Morgan的提供者只有6臺提供者,卻有上百臺消費者,天天有1.5億次調用, 若是採用常規的hessian服務,服務提供者很容易就被壓跨, 經過單一鏈接,保證單一消費者不會壓死提供者,長鏈接,減小鏈接握手驗證等,
並使用異步IO,複用線程池,防止C10K問題。函數
約束:測試
參數及返回值需實現Serializable接口
參數及返回值需有無參構造函數(能夠是private的)或者有參構造全部函數容許傳入null值。
參數及返回值不能自定義實現List, Map, Number, Date, Calendar等接口,只能用JDK自帶的實現,由於hessian會作特殊處理,自定義實現類中的屬性值都會丟失。
Hessian序列化,只傳成員屬性值和值的類型,不傳方法或靜態變量,兼容狀況:
數據通信 狀況 結果
A->B 類A多一種 屬性(或者說類B少一種 屬性) 不拋異常,A多的那 個屬性的值,B沒有, 其餘正常
A->B 枚舉A多一種 枚舉(或者說B少一種 枚舉),A使用多 出來的枚舉進行傳輸 拋異常
A->B 枚舉A多一種 枚舉(或者說B少一種 枚舉),A不使用 多出來的枚舉進行傳輸 不拋異常,B正常接 收數據
A->B A和B的屬性 名相同,但類型不相同 拋異常
A->B serialId 不相同 正常傳輸
遠程調用模塊,抽象各類協議,以及動態代理,只包含一對一的調用, 不關心集羣的管理。
集羣模塊,將多個服務提供方假裝爲一個提供方,包括:負載均衡, 容 錯,路由等,集羣的地址列表能夠是靜態配置的,也能夠是由註冊中心下發。
監控模塊,統計服務調用次數,調用時間的,調用鏈跟蹤的服務。
容器模塊,是一個 Standlone 的容器,以簡單的 Main 加載 Spring 啓動,由於服務一般不須要 Tomcat/JBoss 等 Web 容器的特性,不必用 Web 容器去加 載服務。
服務容器只是一個簡單的Main方法,並加載一個簡單的Spring容器,用於暴露服務。
服務容器的加載內容能夠擴展,內置了spring, jetty, log4j等加載,可經過Container擴展點進行擴展
Container 包含:Spring Container Jetty Container Log4j Container
簡單介紹一下Spring Container的使用
1)自動加載META-INF/spring目錄下的全部Spring配置。
或者 2)配置:(配在java命令-D參數或者dubbo.properties中)
dubbo.spring.config=classpath*:META-INF/spring/*.xml ----配置spring配置加載位置
默認缺省加載Spring Container 緣由:
在dubbo-2.8.4.jar中 在META-INT/dubbo/internal/com.alibba.dubbo.container.Container
spring=com.alibaba.dubbo.container.spring.SpringContainer 有此配置!!!
代碼:
/**
* 主線程啓動
*/
public class TestMain {
public static void main(String[] args) throws Exception {
com.alibaba.dubbo.container.Main.main(args);
}
}
註冊中心模塊,基於註冊中心下發地址的集羣方式,以及對各類注 冊中心的抽象。
對於服務提供方,它須要發佈服務,並且因爲應用系統的複雜性,服務的數量、類型也不斷膨脹;對於服務消費方,它最關心如何獲取到它所須要的服務,而面對複雜的應用系統,須要管理大量的服務調用。並且,對於服務提供方和服務消費方來講,他們還有可能兼具這兩種角色,即既須要提供服務,有須要消費服務。
經過將服務統一管理起來,能夠有效地優化內部應用對服務發佈/使用的流程和管理。服務註冊中心能夠經過特定協議來完成服務對外的統一。Dubbo提供的註冊中心有以下幾種類型可供選擇:
服務首先暴露在服務端,而後調用Registry的register方法在註冊中心(它是一個服務協調中心,dubbo之外的獨立服務端,dubbo提供了客戶端實現)註冊服務,而後用戶經過配置文件中配置的service的url去subscribe(訂閱服務),Registry接收到訂閱消息後會往url對應的的List<NotifyListener>中塞入當前NotifyListener,反之從這個list中移除listener就是取消訂閱。registry會調用據consumer的訂閱狀況調用notify方法推送服務列表給Consumer。
Provider初始化時會調用doRegister方法向註冊中心發起註冊。那麼客戶端又是怎麼subscribe在註冊中心訂閱服務的呢?答案是服務消費者在初始化ConsumerConfig時會調用RegistryProtocol的refer方法進一步調用RegistryDirectory的subscribe方法最終調用ZookeeperRegistry的subscribe方法向註冊中心訂閱服務。
注意:
看以下配置發佈服務:
<dubbo:registry protocol=」dubbo」 address="127.0.0.1:9090" />
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" protocol=」dubbo」 />
1. 指定了哪一種的註冊中心,是基於dubbo協議的,指定了註冊中心的地址以及端口號
2. 發佈DemoService服務,服務的實現爲DemoServiceImpl
每一個<dubbo:service/>在spring內部都會生成一個ServiceBean實例,ServiceBean的實例化過程當中調用export方法來暴露服務
1. 經過loadRegistries獲取註冊中心registryUrls
registry://127.0.0.1:9090/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT&owner=william&pid=7084®istry=dubbo×tamp=1415711791506
用統一數據模型URL表示:
protocol=registry表示一個註冊中心url
註冊中心地址127.0.0.1:9090
調用註冊中心的服務RegistryService
註冊中心協議是registry=dubbo
2. 構建發佈服務的URL
dubbo://192.168.0.102:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=7084&side=provider×tamp=1415712331601
發佈協議protocol =dubbo
服務提供者的地址爲192.168.0.102:20880
發佈的服務爲com.alibaba.dubbo.demo.DemoService
3. 遍歷registryUrls向註冊中心註冊服務
給每一個registryUrl添加屬性key爲export,value爲上面的發佈服務url獲得以下registryUrl
registry://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT& export=dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.5.4-SNAPSHOT%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26loadbalance%3Droundrobin%26methods%3DsayHello%26owner%3Dwilliam%26pid%3D7084%26side%3Dprovider%26timestamp%3D1415712331601&owner=william&pid=7084®istry=dubbo×tamp=1415711791506
4. 由發佈的服務實例,服務接口以及registryUrl爲參數,經過代理工廠proxyFactory獲取Invoker對象,Invoker對象是dubbo的核心模型,其餘對象都向它靠攏或者轉換成它。
5. 經過Protocol對象暴露服務protocol.export(invoker)
經過DubboProtocol暴露服務的監聽(不是此節內容)
經過RegistryProtocol將服務地址發佈到註冊中心,並訂閱此服務
RegistryProtocol.export(Invoker)暴露服務
< dubbo:registry protocol = 」dubbo」 address = "127.0.0.1:9098" />
< dubbo:reference id = "demoService" interface = "com.alibaba.d ubbo.demo.DemoService" />
1. 指定了哪一種的註冊中心,是基於dubbo協議的,指定了註冊中心的地址以及端口號
2. 引用遠程DemoService服務
每一個<dubbo:reference/>標籤spring加載的時候都會生成一個Referenc eBean。
如上圖ReferenceBean實現了spring的FactoryBean接口, 實現了此接口的Bean經過spring的BeanFactory.getBean(「beanName」)獲取的對象不是配置的bean自己而是經過FactoryBean.getObject()方法返回的對象,此接口在spring內部被普遍使用,用來獲取代理對象等等。這裏getObjec t方法用來生成對遠程服務調用的代理
1. loadRegistries()獲取配置的註冊中心的registryUrls
2. 遍歷registryUrls集合,給registryUrl加上refer key就是要引用的遠程服務
[ registry ://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.0&pid=2484& refer =application%3Ddemo-consumer%26dubbo%3D2.0.0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D2484%26side%3Dconsumer%26timestamp%3D1415879965901®istry=dubbo×tamp=1415879990670]
3. 遍歷registryUrls集合,使用Protocol.refer(interface,regist ryUrl)的到可執行對象invoker
4. 若是註冊中心有多個的話, 經過集羣策略Cluser.join()將多個invoke r假裝成一個可執行invoker, 這裏默認使用available策略
5. 利用代理工廠生成代理對象proxyFactory.getProxy(invoker)
以上標籤
未完待續.........