<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:啥是集群策略???

          共 8534字,需瀏覽 18分鐘

           ·

          2021-06-08 10:32


          你好呀,我是why。

          之前有讀者問了 Dubbo Cluster 集群的一些問題。

          那么本文聊一聊 Dubbo 的 Cluster 集群和 Failover Cluster (失敗自動切換)策略。

          如果沒有特別說明的地方,源碼均是來自 2.7.5 版本。

          在閱讀之前先拋出幾個問題:

          • 1.Dubbo Cluster集群的作用是什么?
          • 2.Dubbo Cluster的10個實現(xiàn)類你能說出來幾個,其中哪幾個是集群容錯的方法實現(xiàn)?
          • 3.默認(rèn)的集群實現(xiàn)類是什么呢?
          • 4.Failover Cluster調(diào)用失敗之后,會自動進行幾次重試呢?
          • 5.什么是Dubbo的粘滯連接?
          • 6.粘滯連接在Cluster中是怎么應(yīng)用的?
          • 7.Cluster選擇出一個可用的Invoker最多要進行幾次選擇?
          • 8.請問幾次選擇分別是什么?

          注意:上面的8個問題,前3個是非常常見的面試題。后面的都是你閱讀完本文后就可以知道問題的答案,面試中并不常見,但是后面的問題可以綜合成一個非常高頻的面試題:有看過什么源碼嗎,能給我講講嗎?

          本文會對上面的問題進行逐一的、詳細(xì)的解讀。文章的最后會進行一個問題和答案的匯總。

          走起。

          Dubbo Cluster集群的作用是什么?

          在生產(chǎn)環(huán)境,我們常常是多個服務(wù)器跑相同的應(yīng)用,這種做的目的其一是為了避免單點故障。

          為了避免單點故障,現(xiàn)在的應(yīng)用通常至少會部署在兩臺服務(wù)器上。而對于一些負(fù)載比較高的服務(wù),比如網(wǎng)關(guān)服務(wù),會部署更多的服務(wù)器。

          這樣,在同一環(huán)境下的服務(wù)提供者數(shù)量會大于 1 。對于服務(wù)消費者來說,同一環(huán)境下出現(xiàn)了多個服務(wù)提供者。

          這時會出現(xiàn)幾個問題:

          • 對于一次請求,我作為消費者到底調(diào)用哪個提供者呢?
          • 服務(wù)調(diào)用失敗的時候我怎么做呢?是重試?是拋出異常?或者僅僅是打印出異常?

          為了處理這些問題,Dubbo 定義了集群接口 Cluster 以及 Cluster Invoker。

          集群 Cluster 的用途是將多個服務(wù)提供者合并為一個 Cluster Invoker,并將這個 Invoker 暴露給服務(wù)消費者。

          這樣的好處就是對服務(wù)消費者來說,只需通過這個 Cluster Invoker 進行遠程調(diào)用即可,至于具體調(diào)用哪個服務(wù)提供者,以及調(diào)用失敗后如何處理等問題,現(xiàn)在都交給集群模塊去處理。

          集群模塊是服務(wù)提供者和服務(wù)消費者的中間層,為服務(wù)消費者屏蔽了服務(wù)提供者的情況,這樣服務(wù)消費者就可以專心處理遠程調(diào)用相關(guān)事宜。比如發(fā)請求,接受服務(wù)提供者返回的數(shù)據(jù)等。這就是Dubbo Cluster集群的作用。

          Dubbo Cluster的10個實現(xiàn)類是什么?

          根據(jù)配置可以知道Dubbo集群接口Cluster有10種實現(xiàn)方法如下:

          需要注意的是,十種實現(xiàn)方法其中只有failover、failfast、failsafe、failback、forking、broadcast這6種才屬于集群容錯的范疇。另外的實現(xiàn)均有其他的應(yīng)用場景。

          下面我們先說6種集群容錯的實現(xiàn)方法:

          Failover Cluster:

          failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster

          失敗自動切換,在調(diào)用失敗時,失敗自動切換,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器。通常用于讀操作,但重試會帶來更長延遲。可通過retries="2"來設(shè)置重試次數(shù)(不含第一次)。

          Failfast Cluster:

          failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster

          快速失敗,只發(fā)起一次調(diào)用,失敗立即報錯。通常用于非冪等性的寫操作,比如新增記錄。

          Failsafe Cluster:

          failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster

          失敗安全,出現(xiàn)異常時,直接忽略。通常用于寫入審計日志等操作。

          Failback Cluster:

          failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster

          失敗自動恢復(fù),后臺記錄失敗請求,定時重發(fā)。通常用于消息通知操作。

          Forking Cluster:

          forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster

          并行調(diào)用多個服務(wù)器,只要一個成功即返回。通常用于實時性要求較高的讀操作,但需要浪費更多服務(wù)資源??赏ㄟ^ forks="2" 來設(shè)置最大并行數(shù)。

          Broadcast Cluster:

          broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster

          廣播調(diào)用所有提供者,逐個調(diào)用,任意一臺報錯則報錯。通常用于通知所有提供者更新緩存或日志等本地資源信息。

          所以對于這個問題你也可以回答上來了:10個實現(xiàn)類中有哪幾個是集群容錯的方法實現(xiàn)?

          接下來再說說另外四個實現(xiàn)類:

          Available Cluster:

          available=org.apache.dubbo.rpc.cluster.support.AvailableCluster

          獲取可用的服務(wù)方。遍歷所有Invokers通過invoker.isAvalible判斷服務(wù)端是否活著,只要一個有為true,直接調(diào)用返回,不管成不成功。

          Mergeable Cluster:

          mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster

          分組聚合,將集群中的調(diào)用結(jié)果聚合起來,然后再返回結(jié)果。比如菜單服務(wù),接口一樣,但有多種實現(xiàn),用group區(qū)分,現(xiàn)在消費方需從每種group中調(diào)用一次返回結(jié)果,合并結(jié)果返回,這樣就可以實現(xiàn)聚合菜單項。

          Mock Cluster:

          mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper

          本地偽裝,通常用于服務(wù)降級,比如某驗權(quán)服務(wù),當(dāng)服務(wù)提供方全部掛掉后,客戶端不拋出異常,而是通過 Mock 數(shù)據(jù)返回授權(quán)失敗。

          zone-aware Cluster:

          zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster

          zone-aware的應(yīng)用場景是下面這樣的。

          業(yè)務(wù)部署假設(shè)是雙注冊中心:

          則對應(yīng)消費端,先在注冊中心間選擇,再到選定的注冊中心選址:

          所以,和之前相比,在Dubbo 2.7.5以后,對于多注冊中心訂閱的場景,選址時的多了一層注冊中心集群間的負(fù)載均衡。

          這個注冊中心集群間的負(fù)載均衡的實現(xiàn)就是:zone-aware Cluster。

          對于多注冊中心間的選址策略,根據(jù)類上的注釋可以看出,目前設(shè)計的有下面四種:

          1.指定優(yōu)先級:

          來自preferred="true"注冊中心的地址將被優(yōu)先選擇,只有該中心無可用地址時才Fallback到其他注冊中心

          <dubbo:registry address="zookeeper://${zookeeper.address1}" preferred="true" />

          2.同 zone 優(yōu)先:

          選址時會和流量中的zone key做匹配,流量會優(yōu)先派發(fā)到相同zone的地址

          <dubbo:registry address="zookeeper://${zookeeper.address1}" zone="beijing" />

          3.權(quán)重輪詢:

          來自北京和上海集群的地址,將以10:1的比例來分配流量

          <dubbo:registry id="beijing" address="zookeeper://${zookeeper.address1}" weight="100" />

          <dubbo:registry id="shanghai" address="zookeeper://${zookeeper.address2}" weight="10" />

          4.默認(rèn)方法:

          選擇第一個可用的即可。

          默認(rèn)的集群方法是什么呢?

          源碼之下無秘密。我們從源碼中尋找答案:

          首先我們可以看到,Cluster 是一個 SPI 接口。其默認(rèn)實現(xiàn)是 FailoverCluster.NAME ,如下源碼所示:

          所以默認(rèn)的實現(xiàn)方法就是:

          org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker

          由于Cluster是一個SPI接口,所以我們也可以根據(jù)實際需求去擴展自己的實現(xiàn)類。

          FailoverCluster doInvoke源碼解析

          接下來我們就對 FailoverClusterInvoker 的 doInvoke 方法的源碼進行解析。

          這一小節(jié)主要回答這一個問題:Failover Cluster調(diào)用失敗之后,會自動切換Invoker進行幾次重試呢?

          通過源碼,我們可以知道默認(rèn)的重試次數(shù)是2次。

          有人就問了:為什么第61行的最后還有一個"+1"呢?

          你想一想。我們想要在接口調(diào)用失敗后,重試 n 次,這個 n 就是 DEFAULT_RETRIES,默認(rèn)為 2。

          那么我們總的調(diào)用次數(shù)就是 n+1 次了。所以這個"+1"是這樣來的,很小的一個點。

          另外圖中標(biāo)記了紅色五角星 ★ 的地方,第 62 到 64 行,也是很關(guān)鍵的地方。

          對于retries參數(shù),在官網(wǎng)上的描述是這樣的:

          不需要重試請設(shè)為0。我們前面分析了,當(dāng)設(shè)置為0的時候,只會調(diào)用一次。

          但是我也看見過retries配置為"-1"的。-1+1=0。調(diào)用0次明顯是一個錯誤的含義。但是程序也正常運行,且只調(diào)用一次。

          這就是標(biāo)記了紅色五角星★的地方的功勞了。防御性編程。哪怕你設(shè)置為-10086也只會調(diào)用一次。

          接下來對 doInvoke 方法進行一個全面的解讀,下面是2.7.5版本的源碼,我基本上每一行主要的代碼都加了注釋,可以點開大圖查看:

          org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke

          如上所示,F(xiàn)ailoverClusterInvoker 的 doInvoke 方法主要的工作流程是:

          首先是獲取重試次數(shù),然后根據(jù)重試次數(shù)進行循環(huán)調(diào)用,在循環(huán)體內(nèi),如果失敗,則進行重試。

          在循環(huán)體內(nèi),首先是調(diào)用父類 AbstractClusterInvoker 的 select 方法,通過負(fù)載均衡組件選擇一個 Invoker ,然后再通過這個 Invoker 的 invoke 方法進行遠程調(diào)用。

          如果失敗了,記錄下異常,并進行重試。

          注意一個細(xì)節(jié):在進行重試前,重新獲取最新的invoker集合,這樣做的好處是,如果在重試的過程中某個服務(wù)掛了,可以通過調(diào)用list方法可以保證copyInvokers是最新的可用的invoker列表。

          整個流程大致如此,不是很難理解。

          什么是Dubbo的粘滯連接?

          接下來我們要看的是父類 AbstractClusterInvoker 的 select 方法的邏輯。

          但是在看 select 方法的邏輯之前,我必須得先鋪墊一下 Dubbo 粘滯連接特性的知識。

          官網(wǎng)上的解釋是這樣的:

          可以看出,這是一個服務(wù)治理類型的參數(shù)。

          當(dāng)設(shè)置 true 時,該接口上的所有方法使用同一個 provider。

          官方文檔中說明可以用在接口和方法級別。

          這些都是一些比較簡單的服務(wù)治理的規(guī)則。如果需求更復(fù)雜,則需要使用路由功能。

          官方文檔已經(jīng)說的很清楚了。我就只簡單的解釋一下第一句話:粘滯連接用于有狀態(tài)服務(wù)。

          那么什么是有狀態(tài)服務(wù),什么又是無狀態(tài)服務(wù)呢?

          根據(jù)我簡單的理解。對服務(wù)提供者來說,究竟是有狀態(tài)的服務(wù)提供者,還是無狀態(tài)服務(wù),其判斷依據(jù)就一句話:

          從客戶端發(fā)起的兩個或者多個請求,在服務(wù)端是否具備上下文關(guān)系。

          舉個例子,我們經(jīng)常會用到的 session。

          眾所周知,HTTP 協(xié)議是無狀態(tài)的。

          那么當(dāng)在一個電商場景下,將用戶挑選的商品放到購物車,保存到 session 里,當(dāng)付款的時候,再從購物車?yán)锶〕錾唐沸畔ⅰ?/p>

          這樣通過 session 就實現(xiàn)了有狀態(tài)的服務(wù)。

          當(dāng)一個服務(wù)被設(shè)計為無狀態(tài)的時候,對于客戶端來說,可以隨意調(diào)用。所以無狀態(tài)的服務(wù)可以很容易的進行水平擴容。

          當(dāng)一個服務(wù)被設(shè)計為有狀態(tài)的時候,想要水平擴容的時候就不是那么簡單了。因為客戶端和服務(wù)端存在著上下文關(guān)系,所以客戶端每次都需要請求那一臺服務(wù)端。

          把一個有狀態(tài)的服務(wù)修改為無狀態(tài)的服務(wù)的方案也很簡單。

          還是拿 session 舉例,這個時候,我們的分布式 session 就呼之欲出了。

          把 session 集中存儲起來,比如放到 Redis 中,弄一個獨立于服務(wù)的 session 共享層。

          這樣,一個有狀態(tài)的服務(wù)就可以變?yōu)橐粋€無狀態(tài)的服務(wù)。

          AbstractClusterInvoker select源碼解析

          看完這一小節(jié),你也就知道了粘滯連接在 Cluster 中是怎么應(yīng)用的了。

          有了粘滯連接的知識儲備后,再看 select 方法就比較輕松了,首先需要知道的是select 方法是一個關(guān)鍵的公共方法,其作用就是選擇出一個可用的 invoke,有下面這幾個 Cluster 的實現(xiàn)類都在調(diào)用:

          代碼片段不長,邏輯也比較清楚,具體代碼解析如下:

          根據(jù)代碼畫出select方法的流程圖如下:

          結(jié)合代碼和流程圖,再進行一個文字描述。

          先介紹一下select的四個入?yún)?,分別是:

          • loanbalance:負(fù)載均衡策略。
          • invocation:它持有調(diào)用過程中的變量,比如方法名,參數(shù)等。
          • invokers:這里的invokers列表可以看做是存活著的服務(wù)提供者列表。
          • selected:已經(jīng)被選擇過的invoker集合。

          通過源碼我們可以看出,select 方法的主要邏輯集中在了對粘滯連接特性的支持上。

          首先是獲取 sticky 配置,然后再檢測 invokers 列表中是否包含 stickyInvoker,如果不包含,則認(rèn)為該 stickyInvoker 不可用,此時將其置空。

          為什么可以置空?

          因為這里的 invokers 列表是存活著的服務(wù)提供者列表,如果這個列表不包含 stickyInvoker,那自然而然的認(rèn)為 stickyInvoker 掛了,所以置空。

          接下來,如果 stickyInvoker 存在于 invokers 列表中,說明 stickyInvoker 還活著,此時要進行下一項檢測。

          檢測 selected(選擇過的服務(wù)提供者列表)中是否包含 stickyInvoker。

          如果包含的話,說明 stickyInvoker 在此之前沒有成功提供服務(wù)(但其仍然處于存活狀態(tài))。

          此時我們認(rèn)為這個服務(wù)不可靠,不應(yīng)該在重試期間內(nèi)再次被調(diào)用,因此這個時候不會返回該 stickyInvoker。

          如果 selected 不包含 stickyInvoker,此時還需要進行可用性檢測。

          比如檢測服務(wù)提供者網(wǎng)絡(luò)連通性等。當(dāng)可用性檢測通過,才可返回 stickyInvoker,否則調(diào)用 doSelect 方法選擇 Invoker。

          如果 sticky 為 true,此時會將 doSelect 方法選出的 Invoker 賦值給 stickyInvoker。

          關(guān)于粘滯連接和可用性檢測的默認(rèn)配置如下:

          即默認(rèn)情況下粘滯連接是關(guān)閉狀態(tài)。當(dāng)粘滯連接開啟時,默認(rèn)會進行可用性檢查。

          關(guān)于select方法先分析這么多,繼續(xù)向下分析。

          AbstractClusterInvoker doSelect源碼解析

          讀完這一小節(jié)你可以回答出這兩個問題:

          • 1.Cluster選擇出一個可用的Invoker最多要進行幾次選擇?
          • 2.請問幾次選擇分別是什么?

          doSelect 方法的源碼解析如下:

          Failover Cluster 選擇出一個可用的 Invoker 最多要進行三次選擇,也是 doSelect 的主要邏輯,三次分別是(圖中標(biāo)號了 ①②③ 的地方):

          • ①:通過負(fù)載均衡組件選擇 Invoker。②:如果選出來的 Invoker 不穩(wěn)定,或不可用,此時需要調(diào)用reselect 方法進行重選。
          • ③:reselect選出來的Invoker為空,此時定位invoker在invokers列表中的位置index,然后獲取index+1處的 invoker。

          AbstractClusterInvoker reselect源碼解析

          下面我們來看一下 reselect 方法的邏輯。

          根據(jù)源碼做出流程圖如下:

          所以,reselect 方法總結(jié)下來其實做了四件事情:

          • 第一:查找可用的 invoker,并將其添加到 reselectInvokers 集合中。這個 reselectInvokers 集合你可以理解為里面放的是所有的可用的 invoker 的集合與 selected 集合的差集。
          • 第二:如果經(jīng)過篩選后,reselectInvokers 不為空,則通過負(fù)載均衡組件再次進行選擇并返回。
          • 第三:如果經(jīng)過篩選后,reselectInvokers 為空,則再從 selected 集合(已經(jīng)被調(diào)用過的集合)中選出所有可用的 invoker,放到 reselectInvokers 中,再次通過負(fù)載均衡組件進行選擇并返回。
          • 第四:如果進過上面的步驟后,沒有選擇出合適的 invoker,reselectInvokers 還是為空,說明所有的 invoker 都不可用了,返回為 null。

          好了,到這里就把最開始拋出的8個問題都解答完畢了,接下來對問題、答案進行一個匯總。

          問題、答案匯總

          1.Dubbo Cluster 集群的作用是什么?

          簡單來說:集群模塊是服務(wù)提供者和服務(wù)消費者的中間層,為服務(wù)消費者屏蔽了服務(wù)提供者的情況,這樣服務(wù)消費者就可以專心處理遠程調(diào)用相關(guān)事宜。

          比如發(fā)請求,接受服務(wù)提供者返回的數(shù)據(jù)等。

          這就是 Dubbo Cluster 集群的作用。

          2.Dubbo Cluster的10個實現(xiàn)類你能說出來幾個,其中哪幾個是集群容錯的方法實現(xiàn)?

          根據(jù)配置可以知道 Dubbo 集群接口 Cluster 有10種實現(xiàn)方法如下:

          其中 failover、failfast、failsafe、failback、forking、broadcast 這 6 種才屬于集群容錯的范疇。

          另外的實現(xiàn)均有其他的應(yīng)用場景。

          3.默認(rèn)的集群實現(xiàn)類是什么呢?

          失敗自動切換:org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker

          4.Failover Cluster 調(diào)用失敗之后,會自動切換 Invoker 進行幾次重試呢?

          自動進行 2 次重試,共計調(diào)用 3 次。

          5.什么是 Dubbo 的粘滯連接?

          粘滯連接用于有狀態(tài)服務(wù),盡可能讓客戶端總是向同一提供者發(fā)起調(diào)用,除非該提供者掛了,再連另一臺。粘滯連接將自動開啟延遲連接,以減少長連接數(shù)。

          6.粘滯連接在 Cluster 中是怎么應(yīng)用的?

          參照 AbstractClusterInvoker select 源碼解析。

          select 方法的主要邏輯集中在了對粘滯連接特性的支持上。

          7.Cluster 選擇出一個可用的 Invoker 最多要進行幾次選擇?

          最多進行三次選擇。

          8.請問幾次選擇分別是什么?

          • ①:通過負(fù)載均衡組件選擇 Invoker。
          • ②:如果選出來的 Invoker 不穩(wěn)定,或不可用,此時需要調(diào)用 reselect 方法進行重選。
          • ③:reselect 選出來的 Invoker 為空,此時定位 invoker 在 invokers 列表中的位置 index,然后獲取 index+1 處的 invoker。

          最后說一句

          這一期的荒腔走板昨天發(fā)了,今天就不寫了,有興趣的可以看看呀:今天,我在汶川跑馬拉松

          好了,看到了這里安排個“一鍵三連” (轉(zhuǎn)發(fā)、在看、點贊)吧,周更很累的,需要一點正反饋。

          才疏學(xué)淺,難免會有紕漏,如果你發(fā)現(xiàn)了錯誤的地方,可以在留言區(qū)提出來,我對其加以修改。

          感謝您的閱讀,我堅持原創(chuàng),十分歡迎并感謝您的關(guān)注。

          — 【 THE END 】—
          本公眾號全部博文已整理成一個目錄,請在公眾號里回復(fù)「m」獲取!

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)


          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性爱一级棒 | 一级内射片在线网站观看 | 亚洲av免费在线 亚洲免费观看在线 | 亚洲黄页视频 | 青娱乐娱乐屏一区 |