服務(wù)治理之dubbo核心概念

1. 為什么要做系統(tǒng)拆分?如何進(jìn)行系統(tǒng)拆分?拆分后不用dubbo可以嗎?

為什么要做系統(tǒng)拆分?

  1. 單體應(yīng)用的弊端
  • 部署成本高:無論是修改一行代碼還是10行代碼,都要全量替換

  • 改動(dòng)影響大,風(fēng)險(xiǎn)高:不論是代碼改動(dòng)多少,成本都相同

  • 因成本高、風(fēng)險(xiǎn)高,所以導(dǎo)致部署頻率低:無法快速交付客戶需求

  1. 微服務(wù)架構(gòu)的特點(diǎn):
  • 針對(duì)特定服務(wù)發(fā)布,影響小、風(fēng)險(xiǎn)小、成本低

  • 頻繁發(fā)布版本,快速交付需求

  • 低成本擴(kuò)容、彈性伸縮、適應(yīng)云環(huán)境

  1. 微服務(wù)帶來的問題:
  • 分布式系統(tǒng)的復(fù)雜性:微服務(wù)團(tuán)隊(duì)的技術(shù)棧水平更高

  • 部署、測(cè)試和監(jiān)控的成本問題

  • 分布式事務(wù)和CAP的相關(guān)問題

拆分后的好處

  • 每個(gè)工程獨(dú)立的git倉庫,避免代碼沖突

  • 每個(gè)碼農(nóng)維護(hù)單獨(dú)的服務(wù),包括開發(fā)、測(cè)試、發(fā)布

  • 方便技術(shù)升級(jí),只要保持接口不變:面向接口編程?

  • 代碼量幾十萬的大中型項(xiàng)目,團(tuán)隊(duì)里有幾十個(gè)人。如果不拆分系統(tǒng),開發(fā)效率極其低下,問題很多。

  • 分布式系統(tǒng)拆分之后,可以大幅度提升復(fù)雜系統(tǒng)大型團(tuán)隊(duì)的開發(fā)效率。

如何進(jìn)行系統(tǒng)拆分?

  1. 領(lǐng)域驅(qū)動(dòng)模型

  2. 多次拆分

拆分后不用dubbo可以嗎?

dubbo 就是一種rpc框架,就是本地進(jìn)行接口調(diào)用,但是dubbo會(huì)代理這個(gè)調(diào)用請(qǐng)求,跟遠(yuǎn)程機(jī)器網(wǎng)絡(luò)通信,給你處理掉負(fù)載均衡、
服務(wù)實(shí)例上下線自動(dòng)感知、超時(shí)重試等問題。

分布式系統(tǒng)示意圖

2. 說一下 dubbo 的工作原理?注冊(cè)中心掛了可以繼續(xù)通信嗎?說說一次rpc請(qǐng)求的流程?

  • kafka高可用架構(gòu)原理、es分布式架構(gòu)原理、redis線程模型原理、dubbo工作原理

  • 系統(tǒng)設(shè)計(jì):設(shè)計(jì)MQ、設(shè)計(jì)搜索引擎、設(shè)計(jì)一個(gè)緩存、設(shè)計(jì)rpc框架

dubbo工作原理

第一層:service層:provider和consumer,接口,留給自己實(shí)現(xiàn)的

第二層:config層:任何一個(gè)框架,都需要提供配置文件,讓你進(jìn)行配置

第三層:proxy層:代理層:無論是consumer還是provider,dubbo都會(huì)幫你生成代理,代理之間進(jìn)行網(wǎng)絡(luò)通信

第四層:registry層:provider注冊(cè)自己作為一個(gè)服務(wù),consumer就可以到注冊(cè)中心去尋找自己要調(diào)用的服務(wù)

第五層:cluster層:provider可以部署在多臺(tái)機(jī)器上,多個(gè)provider就組成了一個(gè)集群

第六層:monitor層:consumer調(diào)用provider,調(diào)用了多少次?。拷y(tǒng)計(jì)信息監(jiān)控

第七層:protocol層:負(fù)責(zé)集體的providr和consumer之間調(diào)用接口。封裝rpc調(diào)用

第八層:exchange層:信息交換層,封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步

第九層:transport層:網(wǎng)絡(luò)傳輸層,抽象mina和netty為統(tǒng)一接口

第十層:serizlize層:數(shù)據(jù)序列化層

工作流程

  1. provider 向注冊(cè)中心去注冊(cè)

  2. consumer 從注冊(cè)中心訂閱服務(wù),注冊(cè)中心會(huì)通知 consumer 注冊(cè)好的服務(wù)

  3. consumer 調(diào)用 provider

  4. consumer 和 provider 都異步的通知監(jiān)控中心

注冊(cè)中心掛了可以繼續(xù)通信嗎?

可以。因?yàn)閯傞_始初始化的時(shí)候,消費(fèi)者將提供者的地址等信息拉取到本地緩存,所以注冊(cè)中心掛了可以繼續(xù)通信。

3. dubbo支持哪些通信協(xié)議和序列化協(xié)議?

image.png
  1. 默認(rèn)的 dubbo 協(xié)議,單一長連接,NIO異步通信,基于 hessian 作為序列化。
  • 適用場(chǎng)景:傳輸數(shù)據(jù)量很?。▎未握?qǐng)求在100kb以內(nèi)),但是并發(fā)量很大

  • 消費(fèi)者上百臺(tái),每天調(diào)用量達(dá)上億次。每個(gè)消費(fèi)者維持一個(gè)長連接,長連接基于NIO異步通信。

  1. rmi協(xié)議:走 java 二進(jìn)制序列化,多個(gè)短連接,適合消費(fèi)者和提供者差不多,適用于文件的傳輸。

  2. hessian 協(xié)議:走h(yuǎn)essian序列化協(xié)議

  3. http協(xié)議:json序列化

  4. webservice: SOAP 文本序列化

4. dubbo 負(fù)載均衡策略

image.png
  1. random loadbalance 基于權(quán)重的隨機(jī)算法。默認(rèn)、可設(shè)置權(quán)重

  2. roundrobin 加權(quán)輪詢算法。均勻地將流量打到機(jī)器上去。調(diào)整權(quán)重

  3. leastactive 最少活躍調(diào)用數(shù)算法。自動(dòng)感知,某個(gè)機(jī)器性能接收的請(qǐng)求越少

  4. consistanthash 一致性hash算法:相同參數(shù)的請(qǐng)求一定分發(fā)到一個(gè)provider上去,當(dāng)provider掛掉的時(shí)候,會(huì)基于虛擬節(jié)點(diǎn)均勻分布剩余的流量,抖動(dòng)不會(huì)太大。

5. dubbo 集群容錯(cuò)策略

  1. failover cluster 失敗自動(dòng)切換,自動(dòng)重試到其他機(jī)器。默認(rèn)。讀操作

  2. failfast cluster 一次調(diào)用失敗就立即失敗。寫操作

  3. failsafe cluster 出現(xiàn)異常時(shí)忽略掉。不重要的接口調(diào)用:記錄日志

  4. failback cluster 失敗了后臺(tái)自動(dòng)記錄請(qǐng)求,然后定時(shí)重發(fā)。適合寫消息隊(duì)列

  5. forking cluster 并行調(diào)用多個(gè)provider,只要一個(gè)成功就立即返回

  6. broadcast cluster 逐個(gè)調(diào)用所有的 provider

6. 動(dòng)態(tài)代理策略

  1. 默認(rèn)使用 javassist 動(dòng)態(tài)字節(jié)碼生成,創(chuàng)建代理類

  2. 可以通過 spi 擴(kuò)展機(jī)制配置自己的動(dòng)態(tài)代理策略

7. SPI service provider interface

  1. @SPI("dubbo") : 通過 SPI 機(jī)制來聽實(shí)現(xiàn)類,實(shí)現(xiàn)類是通過dubbo作為默認(rèn)key去配置文件中找到的,配置文件名稱與接口全限定名一樣。

  2. 如果要?jiǎng)討B(tài)替換掉默認(rèn)的實(shí)現(xiàn)類,需要使用 @Adaptive 接口。
    在protocol接口中,有兩個(gè)方法加了 @Adaptive 注解,就是說那兩個(gè)接口會(huì)被代理實(shí)現(xiàn)。
    通過這個(gè)URL中的參數(shù)不同,就可以控制動(dòng)態(tài)使用不同的組件實(shí)現(xiàn)類。

  3. dubbo 里面提供了大量類似以上的擴(kuò)展點(diǎn)。如果要擴(kuò)展一個(gè)東西,只要自己寫一個(gè)jar,讓 consumer 或者是 provider 工程,依賴你的jar,
    在你的jar里指定目錄下配置好接口名稱對(duì)應(yīng)的文件,里面通過key=實(shí)現(xiàn)類。

8. 如何基于 dubbo 進(jìn)行服務(wù)治理、服務(wù)降級(jí)、失敗重試以及重試?

服務(wù)治理

  1. 調(diào)用鏈路自動(dòng)生成:

將各個(gè)服務(wù)之間的調(diào)用自動(dòng)記錄下來,然后自動(dòng)將各個(gè)服務(wù)之間的依賴關(guān)系和調(diào)用鏈路生成出來,做成一張圖,顯示出來。

  1. 服務(wù)訪問壓力以及時(shí)長統(tǒng)計(jì):
  • 需要自動(dòng)統(tǒng)計(jì)各個(gè)接口和服務(wù)之間的調(diào)用次數(shù)以及訪問延時(shí),分為兩個(gè)級(jí)別:

  • 接口粒度:每個(gè)服務(wù)的每個(gè)接口每天被調(diào)用多少次。TP50,TP90,TP99,三個(gè)檔次的請(qǐng)求延時(shí)分別是多少?

  • 從源頭入口開始,一個(gè)完整的請(qǐng)求鏈路經(jīng)過幾十個(gè)服務(wù)之后,完成一次請(qǐng)求,每天全鏈路走多少次,全鏈路請(qǐng)求延時(shí)的 TP50,TP90,TP99 分別是多少?

  1. 其他的
  • 服務(wù)分層(避免循環(huán)依賴)

  • 調(diào)用鏈路失敗監(jiān)控和報(bào)警

  • 服務(wù)鑒權(quán)

  • 每個(gè)服務(wù)的可用性的監(jiān)控(接口調(diào)用成功率?幾個(gè)9?)

服務(wù)降級(jí)

    <dubbo:reference id="appServer" interface="com.gupaoedu.dubbo.IAppInterface" version="1.0.0"
                     cluster="failover"
                     timeout="10"
                     mock="com.DataBaseConnection.dubbo.TestMock"
                     retries="3"/>  

mock:服務(wù)接口實(shí)現(xiàn)類

失敗重試和超時(shí)重試

  • 如果超時(shí)了, timeout 就會(huì)設(shè)置超時(shí)時(shí)間。200ms

  • 如果是調(diào)用失敗了就會(huì)重試指定的次數(shù)

  • retries = 3 。讀請(qǐng)求,如果第一次沒讀到,報(bào)錯(cuò)。重試指定的次數(shù),嘗試再讀取兩次。

9. 分布式服務(wù)接口的冪等性如何設(shè)計(jì)?(比如不能重復(fù)扣款)

image.png
  1. 每個(gè)請(qǐng)求必須有唯一的標(biāo)識(shí):訂單ID

  2. 每次處理完請(qǐng)求之后,必須有一個(gè)記錄標(biāo)識(shí)這個(gè)請(qǐng)求處理過了:用mysql中記錄個(gè)狀態(tài),支付之前記錄一條這個(gè)訂單的支付流水。

  3. 每次接收請(qǐng)求需要進(jìn)行判斷之前是否處理過的邏輯處理。
    如果有一個(gè)訂單已經(jīng)支付了,就已經(jīng)有了一條支付流水,那么如果重復(fù)發(fā)送這個(gè)請(qǐng)求,則此時(shí)先插入支付流水,order已經(jīng)存在了,
    唯一鍵約束生效,報(bào)錯(cuò)插不進(jìn)去的。

  4. redis 支付訂單之前,先插入一條支付流水,order_id 建一個(gè)唯一鍵。重復(fù)請(qǐng)求過來時(shí),先查下 order_id 是否有值,有就不需要再重復(fù)了。

10. 分布式接口的順序性如何保證?

  1. 用 dubbo 的一致性 hash 負(fù)載均衡策略,將某一個(gè)訂單 ID 對(duì)應(yīng)的請(qǐng)求都分發(fā)到某個(gè)機(jī)器上去,接著就是在那個(gè)機(jī)器上因?yàn)?br> 可能還是多線程并發(fā)執(zhí)行的,得立即將某個(gè)訂單對(duì)應(yīng)的請(qǐng)求扔到一個(gè)內(nèi)存隊(duì)列中,強(qiáng)制排隊(duì),來保證順序性。
  • 造成的問題:機(jī)器熱點(diǎn)
  1. 合并多個(gè)操作為一個(gè)操作。

11. 如何自己設(shè)計(jì)一個(gè)類似 dubbo 的 rpc 框架?

  1. 注冊(cè)中心

  2. 消費(fèi)者需要到注冊(cè)中心拿到對(duì)應(yīng)的服務(wù)信息

  3. 發(fā)請(qǐng)求,基于動(dòng)態(tài)代理:面向接口獲取一個(gè)動(dòng)態(tài)代理,這個(gè)動(dòng)態(tài)代理就是接口在本地的一個(gè)代理,然后這個(gè)代理會(huì)找到服務(wù)對(duì)應(yīng)的機(jī)器地址

  4. 發(fā)送到哪個(gè)服務(wù)上去?負(fù)載均衡

  5. 找到一臺(tái)機(jī)器,怎么發(fā)送? netty、nio方式。發(fā)送啥格式數(shù)據(jù)? hessian 序列化協(xié)議

  6. 服務(wù)器端需要針對(duì)你自己的服務(wù)生成一個(gè)動(dòng)態(tài)代理,監(jiān)聽某個(gè)網(wǎng)絡(luò)端口了,然后代理你本地的服務(wù)代碼。接收到請(qǐng)求時(shí),就調(diào)用對(duì)應(yīng)的服務(wù)代碼。

12. dubbo 底層架構(gòu)原理

13. dubbo 底層的網(wǎng)絡(luò)通信機(jī)制原理

14. dubbo 框架從架構(gòu)設(shè)計(jì)角度,是怎么保證極高的可擴(kuò)展性的?

  1. 核心的組件全部接口化,組件和組件之間的調(diào)用,必須是依托于接口,去動(dòng)態(tài)找配置的實(shí)現(xiàn)類,如果沒有配置就用它自己默認(rèn)的。

  2. 提供一種自己實(shí)現(xiàn)的組件的配置方式。比如自己實(shí)現(xiàn)了某個(gè)組件,配置一下,人家到時(shí)候運(yùn)行時(shí)直接找配置的組件。

15. 設(shè)計(jì)一個(gè) rpc 框架,網(wǎng)絡(luò)通信、代理機(jī)制、負(fù)載均衡等該如何設(shè)計(jì)?

  1. 動(dòng)態(tài)代理:rpc 框架的一切的邏輯細(xì)節(jié),都是在這個(gè)動(dòng)態(tài)代理中實(shí)現(xiàn)的,動(dòng)態(tài)代理里面的代碼邏輯是 rpc 框架核心的邏輯。

  2. 服務(wù)注冊(cè)中心,使用什么技術(shù)實(shí)現(xiàn)?

  • 手寫。類似于map的數(shù)據(jù)結(jié)構(gòu)。服務(wù)去注冊(cè),其他服務(wù)去拉取注冊(cè)表進(jìn)行發(fā)現(xiàn)。

  • zookeeper:服務(wù)注冊(cè)表的數(shù)據(jù)結(jié)構(gòu)

  1. cluster層,從本地緩存的服務(wù)注冊(cè)列表里獲取到要調(diào)用的服務(wù)機(jī)器列表

  2. 負(fù)載均衡:注冊(cè)的服務(wù)列表中選擇一個(gè)機(jī)器返回

  3. 數(shù)據(jù)組織:協(xié)議、序列化(復(fù)雜的請(qǐng)求數(shù)據(jù)序列化為二進(jìn)制數(shù)組)機(jī)制。底層用什么網(wǎng)絡(luò)通信框架(netty、mina)

參考代碼
https://github.com/ElegantResearcher/learn/tree/master/rpc

參考文獻(xiàn)

https://gitee.com/shishan100/Java-Interview-Advanced

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

友情鏈接更多精彩內(nèi)容