微服務理論知識匯總-dubbo

Dubbo

Dubbo架構圖

Dubbo層次結構圖

第一層:service層,接口層,給服務提供者和消費者來實現(xiàn)的
第二層:config層,配置層,主要是對dubbo進行各種配置的
第三層:proxy層,服務代理層,透明生成客戶端的stub和服務單的skeleton
第四層:registry層,服務注冊層,負責服務的注冊與發(fā)現(xiàn)
第五層:cluster層,集群層,封裝多個服務提供者的路由以及負載均衡,將多個實例組合成一個服務
第六層:monitor層,監(jiān)控層,對rpc接口的調用次數(shù)和調用時間進行監(jiān)控
第七層:protocol層,遠程調用層,封裝rpc調用
第八層:exchange層,信息交換層,封裝請求響應模式,同步轉異步
第九層:transport層,網(wǎng)絡傳輸層,抽象mina和netty為統(tǒng)一接口
第十層:serialize層,數(shù)據(jù)序列化層

Dubbo支持的通信協(xié)議

協(xié)議名 序列化 連接 適用場景
Dubbo協(xié)議 hessian2 單一長連接,NIO異步通信 傳輸數(shù)據(jù)量很?。看握埱笤?00kb以內),但是并發(fā)量很高,消費者遠大于提供者
rmi協(xié)議 java二進制序列化 多個短連接 消費者和提供者數(shù)量差不多,文件的傳輸
hessian協(xié)議 hessian序列化協(xié)議 多個短連接 傳輸數(shù)據(jù)量較大,提供者數(shù)量比消費者數(shù)量還多,文件的傳輸
http協(xié)議 json序列化 多個短連接 需同時給應用程序和瀏覽器 JS 使用的服務
webservice SOAP文本序列化 多個短連接 系統(tǒng)集成,跨語言調用

Dubbo不好用的地方

不好用的地方 說明 原因 解決方案
參數(shù)及返回值需要實現(xiàn)Serializable接口 默認協(xié)議是Dubbo協(xié)議,通過netty傳輸,需要轉換成二機制數(shù)據(jù) 實現(xiàn)Serializable接口
參數(shù)及返回值不能自定義實現(xiàn)List, Map, Number, Date, Calendar等接口 - 默認協(xié)議是Dubbo協(xié)議,采用的是hessian序列化&反序列化方式,遇上以上接口時會做特殊處理,自定義實現(xiàn)類中的屬性值都會丟失 使用java原生接口
父子類有相同屬性時值丟失 - 默認采用hessian序列化,獲取屬性時,采用了map去重,但是讀值時,根據(jù)序列化順序,對于同名字段,子類的該字段值會被賦值兩次,總是被父類的值覆蓋,導致子類的字段值丟失 不要重名
自定義異常被包裝成RuntimeException - dubbo提供端對異常進行了統(tǒng)一封裝導致的 將自定義異常和接口類放到一個包中/方法簽名上申明自定義異常
IP暴露問題 Docker、雙網(wǎng)卡、虛擬機等環(huán)境下,Dubbo默認綁定的IP可能并不是我們期望的正確IP 跟Dubbo綁定IP默認行為有關 通過添加啟動參數(shù)和配置解決
Data length too large 請求或者響應的報文體長度超過了8k dubbo協(xié)議適合小數(shù)據(jù)傳輸,建議更改協(xié)議
線程耗盡 Dubbo提供者線程池為fix類型,默認線程數(shù)為200,隊列為0 解決業(yè)務耗時原因/擴容

dubbo存在的坑

Dubbo服務提供端異常統(tǒng)一處理邏輯

目的是為了保證拋出的異常,消費端都能識別,具體邏輯如下:

  1. 如果是checked異常(不是RuntimeException但是是Exception.java類型的異常),直接拋出;
  2. 在方法簽名上有聲明(例如String saySomething()throws MyException ),直接拋出;
  3. 異常類和接口類在同一jar包里,直接拋出;
  4. 是JDK自帶的異常(全類名以java或者javax開頭,例如java.lang.IllegalStateException),直接拋出;
  5. 是Dubbo本身的異常RpcException,直接拋出;
  6. 否則,Dubbo通過如下代碼將異常包裝成RuntimeException拋給客戶端

Dubbo常用性能調優(yōu)屬性

C90DBB86-152E-4D54-A388-106EB095A321.jpeg
image.png

注意表中參數(shù)與圖中的對應關系:

    1、當consumer發(fā)起一個請求時,首先經(jīng)過active limit(參數(shù)actives)進行方法級別的限制,其實現(xiàn)方式為CHM中存放計數(shù)器(AtomicInteger),請求時加1,請求完成(包括異常)減1,如果超過actives則等待有其他請求完成后重試或者超時后失??;

    2、從多個連接(connections)中選擇一個連接發(fā)送數(shù)據(jù),對于默認的netty實現(xiàn)來說,由于可以復用連接,默認一個連接就可以。不過如果你在壓測,且只有一個consumer,一個provider,此時適當?shù)募哟骳onnections確實能夠增強網(wǎng)絡傳輸能力。但線上業(yè)務由于有多個consumer多個provider,因此不建議增加connections參數(shù);

    3、連接到達provider時(如dubbo的初次連接),首先會判斷總連接數(shù)是否超限(acceps),超過限制連接將被拒絕;

    4、連接成功后,具體的請求交給io thread處理。io threads雖然是處理數(shù)據(jù)的讀寫,但io部分為異步,更多的消耗的是cpu,因此iothreads默認cpu個數(shù)+1是比較合理的設置,不建議調整此參數(shù);

    5、數(shù)據(jù)讀取并反序列化以后,交給業(yè)務線程池處理,默認情況下線程池為fixed,且排隊隊列為0(queues),這種情況下,最大并發(fā)等于業(yè)務線程池大小(threads),如果希望有請求的堆積能力,可以調整queues參數(shù)。如果希望快速失敗由其他節(jié)點處理(官方推薦方式),則不修改queues,只調整threads;

    6、execute limit(參數(shù)executes)是方法級別的并發(fā)限制,原理與actives類似,只是少了等待的過程,即受限后立即失?。?

Dubbo負載均衡策略

策略名 實現(xiàn)邏輯
隨機 生成隨機值,判斷落在哪個權重范圍內
輪詢 維護一個總調用次數(shù),對總權重取模,判斷落在哪個權重范圍內
最少活躍數(shù) 維護每個服務器的活躍數(shù),取最小值
一致性Hash

Dubbo的集群及容錯策略

容錯策略名 說明 適用場景
failover 失敗自動切換 讀操作
failfast 失敗立即返回 寫操作
failsafe 失敗則忽略 允許丟失的操作,例如日志
failback 失敗定時重發(fā) 消息隊列
forking 并行調用多個provider,某個成功就返回
broadcast 廣播,逐個調用所有的provider

Dubbo的動態(tài)代理

  • 默認使用javassist動態(tài)字節(jié)碼生成,創(chuàng)建代理類

java的spi機制的原理(ServiceLoader)

  • 獲取classloader
  • 讀取META-INF/services/+全限定接口名的文件內容
  • 循環(huán)創(chuàng)建實現(xiàn)類對象并加入緩存
  • 返回實現(xiàn)類對象集合

springboot的spi機制

  • spring.factories文件

Dubbo的spi機制的使用

  • 三個路徑都可以放以接口全限定類為名的文件, META-INF/services/ 、META-INF/dubbo/和META-INF/dubbo/internal/
  • 文件內容是鍵值對格式
  • 接口需要用@SPI注解修飾
  • 通過接口類找到一個 ExtensionLoader
  • 通過ExtensionLoader.getExtension(key) 得到指定key的實現(xiàn)類實例

Dubbo的spi機制的原理

image.png
  • 通過接口類找到一個 ExtensionLoader
  • 通過定義key到實例緩存中查找是否存在該實例,如果存在則返回
  • 實現(xiàn)類緩存中查找是否存在該類,沒有則掃描約定的三個目錄并加載
  • 放射創(chuàng)建指定實現(xiàn)類對象
  • 經(jīng)過注入和包裝后返回

Dubbo的服務降級

通過mock屬性實現(xiàn)服務降級

Dubbo的服務熔斷

無熔斷機制,可通過hystrix實現(xiàn)。

Dubbo的服務限流

限流方式 使用客戶端 標簽 含義
executes 提供端 service、method 并發(fā)執(zhí)行不能超過指定數(shù)
accepts 提供端 protocol 指定協(xié)議的連接數(shù)不能超過指定數(shù)
actives 提供端/消費端 service、reference、method 長鏈接時:最多可以處理的請求個數(shù);短鏈接時:可以同時處理的短連接數(shù)量
connections 提供端/消費端 service、reference、method 最大連接數(shù)

spring與Dubbo搭配使用時,在什么時候開始服務注冊

  • spring啟動過程中刷新上下文操作時
  • bean實例化結束后會發(fā)送上下文刷新完成事件
  • Dubbo的ServiceBean類實現(xiàn)了ApplicationListener接口監(jiān)聽了該事件
  • 故此時會去執(zhí)行onApplicationEvent方法,也是在此時進行了服務注冊

Dubbo 服務暴露的流程

服務暴露

服務暴露的大致流程
  1. 根據(jù)配置得到 URL
  2. 通過 javassist 動態(tài)封裝服務實現(xiàn)類,統(tǒng)一暴露出 Invoker 使得調用方便,屏蔽底層實現(xiàn)細節(jié)(ProxyFactory)
  3. 利用 Dubbo SPI 機制根據(jù) URL 的參數(shù)選擇對應的插件實現(xiàn)類(例如protocol)
  4. 然后將invoker封裝成 exporter 存儲起來,等待消費者的調用
  5. 最后將URL 注冊到注冊中心,使得消費者可以獲取服務提供者的信息(ExporterListener)

Dubbo服務引用的過程(注冊中心方式舉例)

服務引用詳細流程

服務引用大致流程
  1. 通過配置組成URL
  2. 向注冊中心注冊消費者,訂閱節(jié)點(Directory)
  3. 監(jiān)聽注冊中心獲取提供者信息(Directory實現(xiàn)了NotifyListener接口)
  4. 通過SPI機制獲取對應協(xié)議,生成Invoker(Directory.refer)
  5. Invoker中加入負載,容錯等處理 (RegistryProtocol.merge)
  6. 最后通過動態(tài)代理封裝得到代理類(ProxyFactory)

如何實現(xiàn)鏈路追蹤

  1. 通過brave生成和傳遞traceId
  2. zipkin匯總traceId
  3. Logstash采集日志
  4. ElasticSearch+Kibana 可視化分析日志

dubbo的線程模型

  • all 所有消息都派發(fā)到線程池
  • direct 所有消息都不派發(fā)到線程池,全部在 IO 線程上直接執(zhí)行
  • message 只有請求、響應消息派發(fā)到業(yè)務線程池,其他連接斷開事件/心跳等消息,直接在IO線程上執(zhí)行
  • execution 只請求消息派發(fā)到業(yè)務線程池,響應和連接、斷開事件、心跳等消息,直接在 IO 線程上執(zhí)行
  • connection 在 IO 線程上,將連接、斷開事件放入隊列,有序逐個執(zhí)行,其它消息派發(fā)到線程池

dubbo的線程模型圖

dubbo的線程模型圖

dubbo停機的過程

dubbo停機的過程
  1. 收到 kill PID 進程退出信號,Spring 容器會觸發(fā)容器銷毀事件。
  2. provider 端會注銷服務元數(shù)據(jù)信息(刪除ZK節(jié)點)。
  3. consumer 會拉取最新服務提供者列表。
  4. provider 會發(fā)送 readonly 事件報文通知 consumer 服務不可用。
  5. 服務端等待已經(jīng)執(zhí)行的任務結束并拒絕新任務執(zhí)行。
  6. TCP連接斷開

dubbo優(yōu)雅停機方案

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容