4. 負載均衡
如上圖 LoadBlance 模塊所示:在集群負載均衡時,Dubbo提供了不同的策略:
- Random【默認】:隨機,按權重設置隨機概率。調用量越大越均勻,有利於動態調整權重
- RoundRobin:輪詢,按公約後的權限設置輪詢比率。如果有臺機器很慢,但沒掛,當請求到那一臺時就卡在那兒,久而久之,所有請求都卡在那臺機器上
- LeastActive:最少活躍調用數,活躍數指調用前後計數差,越慢的provider的調用前後計數差越大,使得慢的provider收到更少請求
- ConsistentHash:一致性Hash,相同參數的請求發往同一臺provider,當一臺provider掛掉時,原本發往該機器的請求,基於虛擬節點會平攤到其他機器,不會引起劇烈變動
5. 線程派發模型
如果事件處理的邏輯能迅速完成,並且不發生新的IO請求(例如在內存中記個標識),則在IO線程上處理更快,因為減少了線程池調度
如果事件處理的邏輯較慢,或需要發起新的IO請求(例如需要查詢數據庫),則必須派發到線程池,否則 IO 線程阻塞,將導致不能接受其他請求
因此需要不同的派發策略和不同的線程池組合來應對不同的場景:
Dispatcher:
- all:所有消息派發到 ThreadPool,包括請求、響應、連接事件、斷開事件、心跳等
- direct:所有消息不派發 ThreadPool,全在 IO 線程上執行
- message:只有請求響應消息派發到 ThreadPool,其他連接事件、斷開事件、心跳等,在 IO 線程上執行
- execution:只請求消息派發到 ThreadPool,其他事件包括響應事件、連接斷開事件、心跳等消息,在 IO 線程上執行
- connection:在 IO 線程上,將連接斷開事件放入隊列,有序逐個執行,其他時間派發到 ThreadPool
ThreadPool:
- fixed【默認】:固定大小線程池,啟動時建立線程,一直持有不關閉
- cached:緩存線程池,空閒一分鐘自動刪除,需要時重建
- limited:可伸縮線程池,線程數只增長不收縮,目的是為了避免收縮時大流量引起的性能問題
- eager:優先創建Worker線程池,corePoolSize < 任務數量 < maximumPoolSize時,優先創建 Worker 處理任務。任務數量 > maximumPoolSize時,任務放入阻塞隊列中,阻塞隊列充滿時拋出 RejectExecutionException
6. 上下文信息和隱式參數
上下文中存放著當前調用過程中所需的環境信息。RpcContext 是一個 ThreadLocal 的臨時狀態記錄器,當接收或發起 RPC 請求時,RpcContext 都會發生變化。比如:A調用B,B調用C,在B調C之前,B機器上 RpcContext 記錄的是A調用B的信息。
通過 RpcContext 的 setAttachment 和 getAttachment 可以在 provider 和 consumer 之間進行參數的隱式傳遞
7. 異步調用
基於NIO的非阻塞實現並行調用,客戶端不需要啟動多線程即可完成多個遠程服務的並行調用,相對比多線程開銷較小
8. 註冊中心
對於 provider,它需要發佈服務,而且由於應用系統的複雜性,服務的數量、類型也不斷膨脹;對於 consumer,它最關心如何獲取到它所需要的服務,而面對複雜的應用系統,需要管理大量的服務調用
服務註冊中心通過特性協議將服務統一管理起來,有效的優化內部應用對服務發佈/使用的流程。Dubbo提供的註冊中心有如下幾種類型可供選擇:
① ZooKeeper註冊中心
ZK是一個樹形的服務目錄,支持變更推送,適合作為Dubbo服務的註冊中心。流程如下:
- provider啟動時,向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
- consumer啟動時,訂閱 /dubbo/com.foo.BarService/providers 目錄下的 providers 地址,並向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
- 監控中心啟動時,訂閱 /dubbo/com.foo.BarService 目錄下的所有 provider 和 consumer URL地址
當 provider 出現斷電等異常停機時,註冊中心能自動刪除 provider 信息。當註冊中心重啟、或會話過期時,能自動恢復註冊數據和訂閱請求
② Multicase註冊中心
Multicast註冊中心不需要啟動任何中心節點,只要廣播地址即可互相發現
- provider 啟動時廣播自己的地址
- consumer 啟動時廣播訂閱請求
- provider 收到訂閱請求時,單播自己的地址給訂閱者,若設置了 unicast=false,則廣播給訂閱者
- consumer 收到 provider 地址時,連接地址進行 RPC 調用
組播受網絡結構限制,只適合小規模應用或開發階段
③ Redis註冊中心
使用 redis 的 Key/Map 結構存儲數據結構:
- 主 Key 為服務名和類型
- Map 中的 Key 為 URL 地址
- Map 中的 Value 為過期時間,用於判斷髒數據,髒數據由監控中心刪除
調用過程:
- provider 啟動時,向 Key:/dubbo/com.foo.BarService/providers 下,添加當前 provider 的地址
- 並向 Channel:/dubbo/com.foo.BarService/providers 發送 register 事件
- consumer 啟動時,向 Key:/dubbo/com.foo.BarService/providers 下,添加當前 consumer 的地址
- 並從 Channel:/dubbo/com.foo.BarService/providers 訂閱 register 和 unregister 事件
- consumer 收到 register 和 unregister 事件後,從 Key:/dubbo/com.foo.BarService/providers 下獲取 provider 地址列表
- 服務監控中心啟動時,從 Channel:/dubbo/* 訂閱 register 和 unregister,以及 subscribe 和 unsubscribe 事件
- 監控中心收到 register 和 unregister 事件後,從 Key:/dubbo/com.foo.BarService/providers 下獲取 provider 地址列表
- 監控中心收到 subscribe 和 unsubscribe 事件後,從 Key:/dubbo/com.foo.BarService/comsumers 下獲取 consumer 地址列表
閱讀更多 李紅 的文章