『壹』 Dubbo簡介
Dubbo是Alibaba開源的分布式服務框架,它按照分層的方式來架構,使用這種方式可以使各層解耦。
Dubbo在調用遠程的服務的時候再本地有一個介面,就想調用本地方法一樣去調用,底層實現好參數傳輸和遠程服務運行結果傳回之後的返回。
Dubbo的特點:
(1)它主要使用高效的網路框架和序列化框架,讓分布式服務之間調用效率更高。
(2)採用注冊中心管理眾多的服務介面地址,當你想調用服務的時候只需要跟注冊中心詢問即可,不像使用WebService一樣每個服務都得記錄好介面調用方式。
(3)監控中心時實現服務方和調用方之間運行狀態的監控,還能控制服務的優先順序、許可權、權重、上下線等,讓整個龐大的分布式服務系統的維護和治理比較方便。
(4)高可用,如果有服務掛了,注冊中心就會從服務列表去掉該節點,客戶端會像注冊中心請求另一台可用的服務節點重新調用。同時注冊中心也能實現高可用(ZooKeeper)。
(5)負載均衡,採用軟負載均衡演算法實現對多個相同服務的節點的請求負載均衡。
Dubbo需要四大基本組件:Rigistry,Monitor,Provider,Consumer。
1、監控中心的配置文件-bbo.properties文件
(1)容器,監控中心是在jetty和spring環境下運行,依賴於注冊中心,日誌系統是log4j
bbo.container = log4j,spring,registry,jetty
(2)監控服務的名稱,監控系統對整個Dubbo服務系統來說也是一個服務
bbo.application.name = simple-monitor
(3)服務的所有者,這是Dubbbo的服務的功能,可以指定服務的負責人
bbo.application.owner = coselding
(4)注冊中心的地址,配置後監控中心就能通過注冊中心獲取當前可用的服務列表及其狀態,在頁面向你匯報Dubbo中的服務運行情況。
bbo.registr.address = multicast://{ip}:{port} //廣播
bbo.registr.address = zookeeper://{ip}:{port} //zookeper
bbo.registr.address = redis://{ip}:{port} //redis
bbo.registr.address = bbo://{ip}:{port} //bbo
(5)bbo協議埠號
bbo.protocol.port = 7070
(6)jetty工作埠號
bbo.jetty.port = 8082
(7)工作目錄,用於存放監控中心的數據
bbo.jetty.directory = ${user.home}/monitor
(8)監控中心報表存放目錄
bbo.charts.directory=${bbo.jetty.directory}/charts
(9)監控中心數據資料目錄
bbo.statistics.directory=${user.home}/monitor/statistics
(10)監控中心日誌文件路徑
bbo.log4j.file=logs/bbo-monitor-simple.log
(11)監控中心日誌記錄級別
bbo.log4j.level=WARN
2、Dubbo提供負載均衡方式
(1)Random,隨機,按權重配置隨機概率,調用量越大分布越均勻,默認方式。
(2)RounRobin,輪詢,按權重設置輪詢比例,如果存在比較慢的機器容易在這台機器上請求阻塞較多。
(3)LeastActive,最少活躍調用數,不支持權重,只能根據自動識別的活躍數分配,不能靈活調配。
(4)ConsistenHash,一致性hash,對相同參數的請求路由到一個服務提供者上,如果有類似灰度發布需求可採用。
3、Dubbo過濾器
Dubbo初始化過程載入ClassPath下的META-INF/bbo/internal/,META-INF/bbo/,META-INF/services/三個路徑下的com.alibaba.bbo.rpc.Filter文件。文件內容:
Name = FullClassName,這些類必須實現Filter介面。
自定義Filter類:
配置文件在配置過濾器,consumer.xml中:
Dubbo對過濾器的載入過程:
先載入三個路徑下的com.alibaba.bbo.rpc.Filter文件裡面的鍵值對,key為過濾器名稱,value為過濾器的類的全限定名(這個類必須實現Dubbo中的Filter介面)。
自定義的類中@Active註解是過濾器設定的全局基本屬性。
Spring在載入consumer.xml文件時,通過 <bbo:consumer filter="xxx" id = "xxx" retrries = "0">這個配置指定消費者端要載入的過濾器,通過filter屬性指定過濾器名稱。
@Activate註解-自動激活,group屬性是表示匹配了對應的角色才被載入,value表示表明過濾條件,不寫則表示所有條件都會被載入,寫了則只有bbo URL中包含該參數名且參數值不為空才被載入,這個參數會以bbo協議的一個參數K-V對傳到Provider。
4、Dubbo的Provider配置
5、Dubbo的Consumer配置
1、Dubbo是什麼?
Dubbo是阿里巴巴開源的基於Java的高性能RPC分布式框架。
2、為什麼使用Dubbo?
很多公司都在使用,經過很多線上的考驗,內部使用了Netty,Zookeeper,保證了高性能可用性。
使用Dubbo可以將核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,可以提高業務復用靈活性擴展,使前端應用能快速的響應對邊的市場需求。分布式架構可以承受更大規模的並發流量。
Dubbo的服務治理圖:
3、Dubbo和Spring Cloud的區別
兩個沒有關聯,但是非要說區別,有如下幾點:
(1)通信方式不同,Dubbo使用RPC通信,Spring Cloud使用HTTP Restful方式
(2)組成部分不同
4、Dubbo支持的協議
bbo:// (推薦);rmi:// ;hessian:// ;http:// ;webservice:// ;thrift:// ;memcached:// ;redis:// ;rest:// 。
5、Dubbo需要容器嗎?
不需要,如果硬要容器的話,會增加復雜性,同時也浪費資源。
6、Dubbo內置的服務容器
Spring Container;Jetty Container;Log4j Container。
7、Dubbo中節點角色
Register,Monitor,Provider,Consumer,Container(服務運行的容器)。
8、Dubbo的服務注冊和發現的流程圖
9、Dubbo的注冊中心
默認使用Zookeper作為注冊中心,還有Redis,Multicast,bbo注冊中心。
10、Dubbo的配置方式
Spring配置方式和Java API配置方式
11、Dubbo的核心配置
(1)bbo:service 服務配置
(2)bbo:referece 引用配置
(3)bbo:protocol 協議配置
(4)bbo:application 應用配置
(5)bbo:registry 注冊中心配置
(6)bbo:monitor 監控中心配置
(7)bbo:provider 提供方配置
(8)bbo:consumer 消費方配置
(9)bbo:method 方法配置
(10)bbo:argument 參數配置
12、在Provider 節點上可以配置Consumer端的屬性有哪些?
(1)timeout:方法調用超時
(2)retries:失敗重試次數,默認是2次
(3)loadbalance:負載均衡演算法,默認隨機
(4)actives消費者端,最大並發調用控制
13、Dubbo啟動時如果依賴的服務不可用會怎樣
Dubbo預設會在啟動時檢查依賴的服務是否可用,不可用時會拋出異常,阻止Spring初始化完成。默認check ="true"。
14、Dubbo序列化框架
推薦使用Hessian序列化,還有Dubbo,FastJson,Java自帶序列化。
15、Dubbo的通信框架
默認使用Netty框架,另外也提供了Mina,Grizzly。
16、Dubbo集群容錯方案
(1)Failover Cluster,失敗自動切換,自動重試其他伺服器。
(2)Failfast Cluster,快速失敗,立即報錯,只發起一次調用。
(3)Failsafe Cluster,失敗安全,出現異常時,直接忽略。
(4)Failback Cluster,失敗自動恢復,記錄失敗請求,定時重發。
(5)Forking Cluster,並行調用多個伺服器,只要一個返回成功即可。
(6)Broadcast Cluster,廣播逐個調用所有提供者,任意一個報錯則報錯。
17、Dubbo的負載均衡策略
(1)Random LoadBalance,隨機,按權重設置隨機概率,默認。
(2)RoundRobin LoadBalace,輪詢,按公約後的權重設置輪訓比例。
(3)LeastActive LoadBalace,最少活躍調用數,相同活躍數的隨機。
(4)ConsistenHash LoadBalance,一致性hash,相同參數的請求總是發到用一個伺服器。
18、指定某一個服務
可以配置環境點對點直連,繞過注冊中心,將以服務介面為單位,忽略注冊中心的提供者列表。
<bbo:reference interface="com.weidian.bbo.IMyDemo" version="1.0" id="myDemo" url="bbo://127.0.0.1:20880/"></bbo:reference>
19、Dubbo多協議
Dubbo允許配置多協議,在不同伺服器上支持不同協議,或者同一服務支持多種協議。
20、當一個服務有多種實現時怎麼做?
當一個介面有多種是現實,可以用group屬性來分組,服務提供方和消費方都指定同一個group即可。
21、兼容舊版本
使用版本號過度,多個不同版本的服務注冊到注冊中心,版本號不同的服務相互間不引用。
22、Dubbo可以緩存嗎?
Dubbo提供聲明式緩存,用於加速熱門數據的訪問速度,以減少用戶加緩存的工作量。
23、Dubbo服務之間的調用時阻塞的嗎?
默認是同步等待結果阻塞的,支持非同步調用。Dubbo是基於NIO的非阻塞實現並行調用的,客戶端不需要啟動多線程即可完成並行調用多個遠程服務,相對多線程開銷較小,非同步調用會返回一個Future對象。
24、Dubbo不支持分布式事務
25、Dubbo必須依賴的包
Dubbo必須依賴JDK,其他為可選。
26、Dubbo使用過程中的問題
Dubbo的設計目的是為了滿足高並發小數據量的rpc請求,在大數據量下性能表現不是很好,建議使用rmi或http協議。
27、Dubbo的管理控制台的作用
路由規則,動態配置,服務降級,訪問控制,權重調整,負載均衡。
28、Spring boot整合Dubbo
(1)添加依賴
<!-- https://mvnrepository.com/artifact/com.alibaba.boot/bbo-spring-boot-project -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>bbo-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
(2)配置bbo
## Dubbo 服務提供者配置
spring.bbo.application.name=provider
spring.bbo.registry.address=zookeeper://127.0.0.1:2181
spring.bbo.protocol.name=bbo
spring.bbo.protocol.port=20880
spring.bbo.scan=org.spring.springboot.bbo
## Dubbo 服務消費者配置
spring.bbo.application.name=consumer
spring.bbo.registry.address=zookeeper://127.0.0.1:2181
spring.bbo.scan=org.spring.springboot.bbo
『貳』 bbo 介面上傳文件如何去掉大小限制
在消費端增加如下配置
<bbo:provider payload="104857600" />
『叄』 android 可以使用bbo嗎
可以的
DUBBO配置規則詳解
研究DUBBO也已經大半年了,對它的大部分源碼進行了分析,以及對它的內部機制有了比較深入的了解,以及各個模塊的實現。DUBBO包含很多內容,如果想了解DUBBO第一步就是啟動它,從而可以很好的使用它,那麼如何更好的使用呢?就需要知道DUBBO的各個配置項,以及它可以通過哪些途徑進行配置。個人對配置的理解,就好比時對動物的馴服,如何很好的馴服一頭猛獸,那就需要知道它各種因子,從而調整,已達到自己期望的結果。這篇不對DUBBO有哪些配置項可以配置,但是通過這篇文章,你應該能夠知道DUBBO可以進行哪些配置。本文會通過分析DUBBO載入配置源碼的分析,來使得大家對DUBBO的配置一塊有更加深入的了解。從而達到「馴服」DUBBO,以使得它成為你們自己的DUBBO。
DUBBO在配置這一塊做的確實很完美,提供很很多參數,以及提供了多種渠道。下面進入正題,看看DUBBO怎麼載入配置的。在講這些之前,先給大家介紹一下在DUBBO源碼層面定義了哪些類來存儲各個模塊的配置項,從而了解DUBBO可以對哪些模塊進行配置。
哪些東西可以配置
由於大部分項目都會使用Spring,而且DUBBO也提供了通過Spring來進行配置,那麼先從這里進行著手。DUBBO載入Spring的集成時在bbo-config下面的bbo-config-spring模塊下面,其中有一個類DubboNamespaceHandler,它實現了Spring提供的介面NamespaceHandlerSupport。那麼Spring怎麼發現整個實現類的呢?在該模塊的META-INF文件夾下有兩個文件: spring.handlers和spring.schemas,這兩個文件裡面制定了bbo的namespace的XSD文件的位置以及bbo的namespace由DubboNamespaceHandler來處理解析。說了這么多廢話,只是想說明Spring是怎麼解析<bbo:.../>配置的。
知道了DUBBO和Spring關於配置一塊時怎麼整合的之後,那麼你應該就不會詫異Spring怎麼那麼聰明,能夠解析bbo的namespace。接下來看看DubboNamespaceHandler類裡面有什麼東西。
『肆』 Dubbo——路由機制(下)
在 Dubbo——路由機制(上) ,介紹了 Router 介面的基本功能以及 RouterChain 載入多個 Router 的實現,之後介紹了 ConditionRouter 這個類對條件路由規則的處理邏輯以及 ScriptRouter 這個類對腳本路由規則的處理邏輯。本文繼續介紹剩餘的三個 Router 介面實現類。
FileRouterFactory 是 ScriptRouterFactory 的裝飾器,其擴展名為 file,FileRouterFactory 在 ScriptRouterFactory 基礎上增加了讀取文件的能力。可以將 ScriptRouter 使用的路由規則保存到文件中,然後在 URL 中指定文件路徑,FileRouterFactory 從中解析到該腳本文件的路徑並進行讀取,調用 ScriptRouterFactory 去創建相應的 ScriptRouter 對象。
下面來看 FileRouterFactory 對 getRouter() 方法的具體實現,其中完成了 file 協議的 URL 到 script 協議 URL 的轉換,如下是一個轉換示例,首先會將 file:// 協議轉換成 script:// 協議,然後會添加 type 參數和 rule 參數,其中 type 參數值根據文件後綴名確定,該示例為 js,rule 參數值為文件內容。
可以再結合接下來這個示例分析 getRouter() 方法的具體實現:
TagRouterFactory 作為 RouterFactory 介面的擴展實現,其擴展名為 tag。但是需要注意的是,TagRouterFactory 與之前介紹的 ConditionRouterFactory、ScriptRouterFactory 的不同之處在於,它是通過繼承 CacheableRouterFactory 這個抽象類,間接實現了 RouterFactory 介面。
CacheableRouterFactory 抽象類中維護了一個 ConcurrentMap 集合(routerMap 欄位)用來緩存 Router,其中的 Key 是 ServiceKey。在 CacheableRouterFactory 的 getRouter() 方法中,會優先根據 URL 的 ServiceKey 查詢 routerMap 集合,查詢失敗之後會調用 createRouter() 抽象方法來創建相應的 Router 對象。在 TagRouterFactory.createRouter() 方法中,創建的自然就是 TagRouter 對象了。
通過 TagRouter,可以將某一個或多個 Provider 劃分到同一分組,約束流量只在指定分組中流轉,這樣就可以輕松達到流量隔離的目的,從而支持灰度發布等場景。
目前,Dubbo 提供了動態和靜態兩種方式給 Provider 打標簽,其中動態方式就是通過服務治理平台動態下發標簽,靜態方式就是在 XML 等靜態配置中打標簽。Consumer 端可以在 RpcContext 的 attachment 中添加 request.tag 附加屬性,注意保存在 attachment 中的值將會在一次完整的遠程調用中持續傳遞,我們只需要在起始調用時進行設置,就可以達到標簽的持續傳遞。
了解了 Tag 的基本概念和功能之後,再簡單介紹一個 Tag 的使用示例。
在實際的開發測試中,一個完整的請求會涉及非常多的 Provider,分屬不同團隊進行維護,這些團隊每天都會處理不同的需求,並在其負責的 Provider 服務中進行修改,如果所有團隊都使用一套測試環境,那麼測試環境就會變得很不穩定。如下圖所示,4 個 Provider 分屬不同的團隊管理,Provider 2 和 Provider 4 在測試環境測試,部署了有 Bug 的版本,這樣就會導致整個測試環境無法正常處理請求,在這樣一個不穩定的測試環境中排查 Bug 是非常困難的,因為可能排查到最後,發現是別人的 Bug。
為了解決上述問題,我們可以針對每個需求分別獨立出一套測試環境,但是這個方案會佔用大量機器,前期的搭建成本以及後續的維護成本也都非常高。
下面是一個通過 Tag 方式實現環境隔離的架構圖,其中,需求 1 對 Provider 2 的請求會全部落到有需求 1 標簽的 Provider 上,其他 Provider 使用穩定測試環境中的 Provider;需求 2 對 Provider 4 的請求會全部落到有需求 2 標簽的 Provider 4 上,其他 Provider 使用穩定測試環境中的 Provider。
在一些特殊場景中,會有 Tag 降級的場景,比如找不到對應 Tag 的 Provider,會按照一定的規則進行降級。如果在 Provider 集群中不存在與請求 Tag 對應的 Provider 節點,則默認將降級請求 Tag 為空的 Provider;如果希望在找不到匹配 Tag 的 Provider 節點時拋出異常的話,我們需設置 request.tag.force = true。
如果請求中的 request.tag 未設置,只會匹配 Tag 為空的 Provider,也就是說即使集群中存在可用的服務,若 Tag 不匹配也就無法調用。一句話總結,攜帶 Tag 的請求可以降級訪問到無 Tag 的 Provider,但不攜帶 Tag 的請求永遠無法訪問到帶有 Tag 的 Provider。
下面再來看 TagRouter 的具體實現。在 TagRouter 中持有一個 TagRouterRule 對象的引用,在 TagRouterRule 中維護了一個 Tag 集合,而在每個 Tag 對象中又都維護了一個 Tag 的名稱,以及 Tag 綁定的網路地址集合,如下圖所示:
另外,在 TagRouterRule 中還維護了 addressToTagnames、tagnameToAddresses 兩個集合(都是 Map<String, List<String>> 類型),分別記錄了 Tag 名稱到各個 address 的映射以及 address 到 Tag 名稱的映射。在 TagRouterRule 的 init() 方法中,會根據 tags 集合初始化這兩個集合。
了解了 TagRouterRule 的基本構造之後,我們繼續來看 TagRouter 構造 TagRouterRule 的過程。TagRouter 除了實現了 Router 介面之外,還實現了 ConfigurationListener 介面,如下圖所示:
ConfigurationListener 用於監聽配置的變化,其中就包括 TagRouterRule 配置的變更。當我們通過動態更新 TagRouterRule 配置的時候,就會觸發 ConfigurationListener 介面的 process() 方法,TagRouter 對 process() 方法的實現如下:
我們可以看到,如果是刪除配置的操作,則直接將 tagRouterRule 設置為 null,如果是修改或新增配置,則通過 TagRuleParser 解析傳入的配置,得到對應的 TagRouterRule 對象。TagRuleParser 可以解析 yaml 格式的 TagRouterRule 配置,下面是一個配置示例:
經過 TagRuleParser 解析得到的 TagRouterRule 結構,如下所示:
除了上圖展示的幾個集合欄位,TagRouterRule 還從 AbstractRouterRule 抽象類繼承了一些控制欄位,後面介紹的 ConditionRouterRule 也繼承了 AbstractRouterRule。
AbstractRouterRule 中核心欄位的具體含義大致可總結為如下:
我們可以看到,AbstractRouterRule 中的核心欄位與前面的示例配置是一一對應的。
我們知道,Router 最終目的是要過濾符合條件的 Invoker 對象,下面我們一起來看 TagRouter 是如何使用 TagRouterRule 路由邏輯進行 Invoker 過濾的,大致步驟如下:
上述流程的具體實現是在 TagRouter.route() 方法中,如下所示:
除了之前介紹的 TagRouterFactory 繼承了 CacheableRouterFactory 之外,ServiceRouterFactory 也繼承 CachabelRouterFactory,具有了緩存的能力,具體繼承關系如下圖所示:
ServiceRouterFactory 創建的 Router 實現是 ServiceRouter,與 ServiceRouter 類似的是 AppRouter,兩者都繼承了 ListenableRouter 抽象類(雖然 ListenableRouter 是個抽象類,但是沒有抽象方法留給子類實現),繼承關系如下圖所示:
ListenableRouter 在 ConditionRouter 基礎上添加了動態配置的能力,ListenableRouter 的 process() 方法與 TagRouter 中的 process() 方法類似,對於 ConfigChangedEvent.DELETE 事件,直接清空 ListenableRouter 中維護的 ConditionRouterRule 和 ConditionRouter 集合的引用;對於 ADDED、UPDATED 事件,則通過 ConditionRuleParser 解析事件內容,得到相應的 ConditionRouterRule 對象和 ConditionRouter 集合。這里的 ConditionRuleParser 同樣是以 yaml 文件的格式解析 ConditionRouterRule 的相關配置。ConditionRouterRule 中維護了一個 conditions 集合(List<String> 類型),記錄了多個 Condition 路由規則,對應生成多個 ConditionRouter 對象。
整個解析 ConditionRouterRule 的過程,與前文介紹的解析 TagRouterRule 的流程類似。
在 ListenableRouter 的 route() 方法中,會遍歷全部 ConditionRouter 過濾出符合全部路由條件的 Invoker 集合,具體實現如下:
ServiceRouter 和 AppRouter 都是簡單地繼承了 ListenableRouter 抽象類,且沒有覆蓋 ListenableRouter 的任何方法,兩者只有以下兩點區別。
本文我們是緊接 Dubbo——路由機制(上) 的內容,繼續介紹了剩餘 Router 介面實現的內容。
我們介紹了基於文件的 FileRouter 實現,其底層會依賴之前介紹的 ScriptRouter;接下來又講解了基於 Tag 的測試環境隔離方案,以及如何基於 TagRouter 實現該方案,同時深入分析了 TagRouter 的核心實現;最後我們還介紹了 ListenableRouter 抽象類以及 ServerRouter 和 AppRouter 兩個實現,它們是在條件路由的基礎上添加了動態變更路由規則的能力,同時區分了服務級別和服務實例級別的配置。
『伍』 SpringCloud和Dubbo的區別是什麼
springcloud和bbo的最大區別:springcloud拋棄了bbo的rpc通信,採用的是基於http的rest方式。
『陸』 為什麼bbo不適合傳送大數據量
因bbo協議採用單一長連接,
如果每次請求的數據包大小為500KByte,假設網路為千兆網卡(1024Mbit=128MByte),每條連接最大7MByte(不同的環境可能不一樣,供參考),
單個服務提供者的TPS(每秒處理事務數)最大為:128MByte / 500KByte = 262。
單個消費者調用單個服務提供者的TPS(每秒處理事務數)最大為:7MByte / 500KByte = 14。
如果能接受,可以考慮使用,否則網路將成為瓶頸。
『柒』 rpc框架都有哪些rmi bbo
Dubbo分層
config(配置層 )
proxy(服務代理層)
registry( 注冊中心層)
cluster( 路由層)
monitor( 監控層)
protocol( 遠程調用層)
exchange( 信息交換層)
transport( 網路傳輸層)
serialize( 數據序列化層)
對外配置介面
以ServiceConfig, ReferenceConfig為中心,可以直接new配置類,也可以通過spring解析配置生成配置類
Javassist ProxyFactory
Jdk ProxyFactory
服務介面透明代理,生成服務的客戶端Stub和伺服器端Skeleton
以ServiceProxy為中心,擴展介面為ProxyFactory
選擇
Zookeeper
Redis
Multicast
Simple
支持基於網路的集群方式,有廣泛周邊開源產品,建議使用bbo-2.3.3以上版本(推薦使用)
依賴於Zookeeper的穩定性
支持基於客戶端雙寫的集群方式,性能高
要求伺服器時間同步,用於檢查心跳過期臟數據
去中心化,不需要安裝注冊中心
依賴於網路拓普和路由,跨機房有風險
Dogfooding,注冊中心本身也是一個標準的RPC服務
沒有集群支持,可能單點故障
封裝服務地址的注冊與發現
以服務URL為中心,擴展介面為RegistryFactory, Registry, RegistryService
選擇
Spring
Jetty
Log4j
自動載入META-INF/spring目錄下的所有Spring配置
啟動一個內嵌Jetty,用於匯報狀態
大量訪問頁面時,會影響伺服器的線程和內存
自動配置log4j的配置,在多進程啟動時,自動給日誌文件按進程分目錄
用戶不能控制log4j的配置,不靈活
條件路由
腳本路由
基於條件表達式的路由規則,功能簡單易用
有些復雜多分支條件情況,規則很難描述
基於腳本引擎的路由規則,功能強大
沒有運行沙箱,腳本能力過於強大,可能成為後門
Random
RoundRobin
LeastActive
ConsistentHash
隨機,按權重設置隨機概率(推薦使用)
在一個截面上碰撞的概率高,重試時,可能出現瞬間壓力不均
輪循,按公約後的權重設置輪循比率
存在慢的機器累積請求問題,極端情況可能產生雪崩
最少活躍調用數,相同活躍數的隨機,活躍數指調用前後計數差,使慢的機器收到更少請求
不支持權重,在容量規劃時,不能通過權重把壓力導向一台機器壓測容量
一致性Hash,相同參數的請求總是發到同一提供者,當某一台提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動
壓力分攤不均
Failover
Failfast
Failsafe
Failback
Forking
Broadcast
失敗自動切換,當出現失敗,重試其它伺服器,通常用於讀操作(推薦使用)
重試會帶來更長延遲
快速失敗,只發起一次調用,失敗立即報錯,通常用於非冪等性的寫操作
如果有機器正在重啟,可能會出現調用失敗
失敗安全,出現異常時,直接忽略,通常用於寫入審計日誌等操作
調用信息丟失
失敗自動恢復,後台記錄失敗請求,定時重發,通常用於消息通知操作
不可靠,重啟丟失
並行調用多個伺服器,只要一個成功即返回,通常用於實時性要求較高的讀操作
需要浪費更多服務資源
廣播調用所有提供者,逐個調用,任意一台報錯則報錯,通常用於更新提供方本地狀態
速度慢,任意一台報錯則報錯
封裝多個提供者的路由及負載均衡,並橋接注冊中心
以Invoker為中心,擴展介面為Cluster, Directory, Router, LoadBalance
Cluster選擇
Router選擇
路由規則
容器
RPC調用次數和調用時間監控
以Statistics為中心,擴展介面為MonitorFactory, Monitor, MonitorService
Dubbo協議
Rmi協議
Hessian協議
連接個數:單連接
連接方式:長連接
傳輸協議:TCP
傳輸方式:NIO非同步傳輸
序列化:Hessian二進制序列化
適用范圍:傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多,單一消費者無法壓滿提供者,盡量不要用bbo協議傳輸大文件或超大字元串。
適用場景:常規遠程服務方法調用
採用NIO復用單一長連接,並使用線程池並發處理請求,減少握手和加大並發效率,性能較好(推薦使用)
適合於小數據量大並發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況
Dubbo預設協議不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低
Dubbo協議預設每服務每提供者每消費者使用單一長連接,如果數據量較大,可以使用多個連接
為防止被大量連接撐掛,可在服務提供方限制大接收連接數,以實現服務提供方自我保護
在大文件傳輸時,單一連接會成為瓶頸
總結
可與原生RMI互操作,基於TCP協議
偶爾會連接失敗,需重建Stub
參數及返回值需實現Serializable介面
參數及返回值不能自定義實現List, Map, Number, Date, Calendar等介面,只能用JDK自帶的實現,因為hessian會做特殊處理,自定義實現類中的屬性值都會丟失
連接個數:多連接
連接方式:短連接
傳輸協議:HTTP
傳輸方式:同步傳輸
序列化:Hessian二進制序列化
適用范圍:傳入傳出參數數據包較大,提供者比消費者個數多,提供者壓力較大,可傳文件
適用場景:頁面傳輸,文件傳輸,或與原生hessian服務互操作
提供者用Dubbo的Hessian協議暴露服務,消費者直接用標准Hessian介面調用
或者提供方用標准Hessian暴露服務,消費方用Dubbo的Hessian協議調用
基於Hessian的遠程調用協議
可與原生Hessian互操作,基於HTTP協議
需hessian.jar支持,http短連接的開銷大
Hessian協議用於集成Hessian的服務,Hessian底層採用Http通訊,採用Servlet暴露服務,Dubbo預設內嵌Jetty作為伺服器實現
可以和原生Hessian服務互操作
總結
約束
封裝RPC調用
以Invocation, Result為中心,擴展介面為Protocol, Invoker, Exporter
選擇
封裝請求響應模式,同步轉非同步
以Request, Response為中心,擴展介面為Exchanger, ExchangeChannel,ExchangeClient, ExchangeServer
Netty
Mina
Grizzly
性能較好(推薦使用)
一次請求派發兩種事件,需屏蔽無用事件
老牌NIO框架,穩定
待發送消息隊列派發不及時,大壓力下,會出現FullGC
Sun的NIO框架,應用於GlassFish伺服器中
線程池不可擴展,Filter不能攔截下一Filter
抽象mina和netty為統一介面
以Message為中心,擴展介面為Channel, Transporter, Client, Server, Codec
選擇
Hessian
Dubbo
Json
Java
性能較好,多語言支持(推薦使用)
Hessian的各版本兼容性不好,可能和應用使用的Hessian沖突,Dubbo內嵌了hessian3.2.1的源碼
通過不傳送POJO的類元信息,在大量POJO傳輸時,性能較好
當參數對象增加欄位時,需外部文件聲明
純文本,可跨語言解析,預設採用FastJson解析
性能較差
Java原生支持
性能較差
可復用的一些工具
擴展介面為Serialization, ObjectInput, ObjectOutput, ThreadPool
選擇
Business
RPC
Remoting
Service
Config
Proxy
Registry
Cluster
Monitor
Protocol
Exchange
Transport
Serialize
層次結構
層說明
『捌』 Dubbo高性能網關--Flurry介紹
從架構的角度來看,API網關暴露http介面服務,其本身不涉及業務邏輯,只負責包括請求路由、負載均衡、許可權驗證、流量控制、緩存等等功能。其定位類似於Nginx請求轉發、但功能要多於Nginx,背後連接了成百上千個後台服務,這些服務協議可能是rest的,也可能是rpc協議等等。
網關的定位決定了它生來就需要高性能、高效率的。網關對接著成百上千的服務介面,承受者高並發的業務需求,因此我們對其性能要求嚴苛,其基本功能如下:
Flurry是雲集自研的一款輕量級、非同步流式化、針對Dubbo的高性能API網關。與業界大多數網關不同的是,flurry自己實現了 http與bbo協議互轉的流式化的bbo-json協議,可高性能、低內存要求的對http和bbo協議進行轉換。除此之外,其基於 netty作為服務容器,提供服務元數據模型等等都是非常具有特點的。下面我們將詳細介紹 flurry的特性:
Flurry 網關請求響應基於Netty線程模型,後者是實現了Reactive,反應式模式規范的,其設計就是來榨乾CPU的,可以大幅提升單機請求響應的處理能力。
最終,Flurry通過使用Netty線程模型和NIO通訊協議實現了HTTP請求和響應的非同步化。
每一次http請求最終都會由Netty的一個Client Handler來處理,其最終以非同步模式請求後台服務,並返回一個CompletableFuture,當有結果返回時才會將結果返回給前端。
見下面一段例子:
有了服務元數據,我們就可以不必需要服務的API包,並能夠清晰的知道整個服務API的定義。
這在Dubbo服務Mock調用、服務測試、文檔站點、流式調用等等場景下都可以發揮搶到的作用。
小孩子才分對錯,成年人只看利弊。額外引入一個元數據生成機制,必然帶來運維成本、理解成本、遷移成本等問題,那麼它具備怎樣的價值,來說服大家選擇它呢?上面我們介紹元數據中心時已經提到了服務測試、服務 MOCK 等場景,這一節我們重點探討一下元數據中心的價值和使用場景。
那麼,Dubbo服務元數據能夠利用到哪些場景呢?下面我們來詳細描述。
Http請求,數據通過JSON傳輸,其格式嚴格按照介面POJO屬性。返回結果再序列化為Json返回前端。現在大多數開源的網關,在bbo協議適配上都是採用的泛化模式來做到協議轉換的,這其中就包括 Soul 等。
JsonString -> JSONObject(Map) -> Binary
將JSON 字元串轉換為 JSON 對象模型(JSONObject),此處通過第三方JSON映射框架(如Google的Gson, 阿里的FastJSON等)來做,然後將Map通過Hessian2 協議序列化為Binaray。
自定義的Dubbo-Json協議參考了 dapeng-soa 的流式解析協議的思想,詳情請參考: dapeng-json
針對上述泛化模式轉換Dubbo協議的缺點,我們在flurry-core 中的 Dubbo-Json 序列化協議做到了這點,下面我們來講解它是如何高效率的完成JsonString到 bbo hessian2 序列化buffer的轉換的。
雖然大部分情況下的JSON請求、返回都是數據量較小的場景, 但作為平台框架, 也需要應對更大的JSON請求和返回, 比如1M、甚至10M. 在這些場景下, 如果需要佔用大量的內存, 那麼勢必導致巨大的內存需求, 同時引發頻繁的GC操作, 也會聯動影響到整個網關的性能.
Dubbo-Json參考了XML SAX API的設計思想, 創造性的引入了JSON Stream API, 採用流式的處理模式, 實現JSON 對 hessian2 的雙向轉換, 無論數據包有多大, 都可以在一定固定的內存規模內完成.
流式協議,顧名思義就是邊讀取邊解析,數據像水流一樣在管道中流動,邊流動邊解析,最後,數據解析完成時,轉換成的hessian協議也已全部寫入到了buffer中。
這里處理的核心思想就是實現自己的Json to hessian2 buffer 的語法和此法解析器,並配合前文提及的元數據功能,對每一個讀取到的json片段通過元數據獲取到其類型,並使用 hessian2協議以具體的方式寫入到buffer中。
首先我們來看看JSON的結構. 一個典型的JSON結構體如下
其對應Java POJO 自然就是上述三個屬性,這里我們略過。下面是POJO生成的元數據信息
相比XML而言,JSON數據類型比較簡單, 由 Object/Array/Value/String/Boolean/Number 等元素組成, 每種元素都由特定的字元開和結束. 例如Object以'{'以及'}'這兩個字元標志開始以及結束, 而Array是'['以及']'. 簡單的結構使得JSON比較容易組裝以及解析。
如圖,我們可以清晰的了解JSON的結構,那麼對上述JSON進行解析時,當每一次解析到一個基本類型時,先解析到key,然後根據key到元數據信息中獲取到其value類型,然後直接根據對應類型的hessian2序列化器將其序列化到byte buffer中。
當解析到引用類型,即 Struct類型時,我們將其壓入棧頂,就和java方法調用壓棧操作類似。
通過上面的步驟一步一步,每解析一步Json,就將其寫入到byte buffer中,最終完成整個流式的解析過程。
拿上面json為例:
總結:
上述整個請求和響應,網關處理如下:
請求和響應中沒有像泛化模式中的中間對象轉換,直接一步到位,沒有多餘的臨時對象佔用內存,沒有多餘的數據轉換,整個過程像在管道中流式的進行。
如上圖所示,flurry bbo網關不必依賴任何bbo介面API包,而是直接通過獲取服務元數據、並通過bbo-json流式協議來調用後端服務。其本身不會耦合業務邏輯。
硬體部署與參數調整
對基於Y-Hessian的 非同步化、流式轉換的Yunji Dubbo API網關進行性能壓測,了解它的處理能力極限是多少,這樣有便於我們推斷其上線後的處理能力,以及對照現有的Tomcat接入層模式的優勢,能夠節約多少資源,做到心裡有數。
性能測試場景
上述場景均使用wrk在壓測節點上進行5~10min鍾的壓測,壓測參數基本為12線程256連接或者512連接,以發揮最大的壓測性能。
flurry集Dubbo網關、非同步、流式、高性能於一身,其目標就是替代一些以tomcat作為bbo消費者的接入層,以更少的節點獲得更多的性能提升,節約硬體資源和軟體資源。
後續在flurry的基礎上,將實現鑒權管理、流量控制、限流熔斷、監控收集等等功能
Flurry : 基於Dubbo服務的高性能、非同步、流式網關
bbo-json : 自定義的Dubbo協議,支持流式序列化模式,為flurry網關序列化/反序列化組件。
Yunji-doc-site : 與元數據集成相關的項目,以及文檔站點
dapeng-soa : Dapeng-soa 是一個輕量級、高性能的微服務框架,構建在Netty以及定製的精簡版Thrift之上。 同時,從Thrift IDL文件自動生成的服務元數據信息是本框架的一個重要特性,很多其它重要特性都依賴於服務元數據信息。 最後,作為一站式的微服務解決方案,Dapeng-soa還提供了一系列的腳手架工具以支持用戶快速的搭建微服務系統
dapeng-json :dapeng-json協議介紹