1. 程式人生 > 實用技巧 >JavaEE - 11集合Map

JavaEE - 11集合Map

一 重要的概念

1.1 什麼是 Dubbo?

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高效能、輕量級的開源Java RPC 框架,它提供了三大核心能力:面向介面的遠端方法呼叫,智慧容錯和負載均衡,以及服務自動註冊和發現。簡單來說 Dubbo 是一個分散式服務框架,致力於提供高效能和透明化的RPC遠端服務呼叫方案,以及SOA服務治理方案。

Dubbo 目前已經有接近 23k 的 Star ,Dubbo的Github 地址:https://github.com/apache/incubator-dubbo 。 另外,在開源中國舉行的2018年度最受歡迎中國開源軟體這個活動的評選中,Dubbo 更是憑藉其超高人氣僅次於 vue.js 和 ECharts 獲得第三名的好成績。

Dubbo 是由阿里開源,後來加入了 Apache 。正式由於 Dubbo 的出現,才使得越來越多的公司開始使用以及接受分散式架構。

我們上面說了 Dubbo 實際上是 RPC 框架,那麼什麼是 RPC呢?

1.2 什麼是 RPC?RPC原理是什麼?

什麼是 RPC?

RPC(Remote Procedure Call)—遠端過程呼叫,它是一種通過網路從遠端計算機程式上請求服務,而不需要了解底層網路技術的協議。比如兩個不同的服務 A、B 部署在兩臺不同的機器上,那麼服務 A 如果想要呼叫服務 B 中的某個方法該怎麼辦呢?使用 HTTP請求當然可以,但是可能會比較麻煩。 RPC 的出現就是為了讓你呼叫遠端方法像呼叫本地方法一樣簡單。

RPC原理是什麼?

我這裡這是簡單的提一下。詳細內容可以檢視下面這篇文章:

http://www.importnew.com/22003.html

  1. 服務消費方(client)呼叫以本地呼叫方式呼叫服務;
  2. client stub接收到呼叫後負責將方法、引數等組裝成能夠進行網路傳輸的訊息體;
  3. client stub找到服務地址,並將訊息傳送到服務端;
  4. server stub收到訊息後進行解碼;
  5. server stub根據解碼結果呼叫本地的服務;
  6. 本地服務執行並將結果返回給server stub;
  7. server stub將返回結果打包成訊息併發送至消費方;
  8. client stub接收到訊息,並進行解碼;
  9. 服務消費方得到最終結果。

下面再貼一個網上的時序圖:

說了這麼多,我們為什麼要用 Dubbo 呢?

1.3 為什麼要用 Dubbo?

Dubbo 的誕生和 SOA 分散式架構的流行有著莫大的關係。SOA 面向服務的架構(Service Oriented Architecture),也就是把工程按照業務邏輯拆分成服務層、表現層兩個工程。服務層中包含業務邏輯,只需要對外提供服務即可。表現層只需要處理和頁面的互動,業務邏輯都是呼叫服務層的服務來實現。SOA架構中有兩個主要角色:服務提供者(Provider)和服務使用者(Consumer)。

如果你要開發分散式程式,你也可以直接基於 HTTP 介面進行通訊,但是為什麼要用 Dubbo呢?

我覺得主要可以從 Dubbo 提供的下面四點特性來說為什麼要用 Dubbo:

  1. 負載均衡——同一個服務部署在不同的機器時該呼叫那一臺機器上的服務。
  2. 服務呼叫鏈路生成——隨著系統的發展,服務越來越多,服務間依賴關係變得錯蹤複雜,甚至分不清哪個應用要在哪個應用之前啟動,架構師都不能完整的描述應用的架構關係。Dubbo 可以為我們解決服務之間互相是如何呼叫的。
  3. 服務訪問壓力以及時長統計、資源排程和治理——基於訪問壓力實時管理叢集容量,提高叢集利用率。
  4. 服務降級——某個服務掛掉之後呼叫備用服務。

另外,Dubbo 除了能夠應用在分散式系統中,也可以應用在現在比較火的微服務系統中。不過,由於 Spring Cloud 在微服務中應用更加廣泛,所以,我覺得一般我們提 Dubbo 的話,大部分是分散式系統的情況。

我們剛剛提到了分散式這個概念,下面再給大家介紹一下什麼是分散式?為什麼要分散式?

1.4 什麼是分散式?

分散式或者說 SOA 分散式重要的就是面向服務,說簡單的分散式就是我們把整個系統拆分成不同的服務然後將這些服務放在不同的伺服器上減輕單體服務的壓力提高併發量和效能。比如電商系統可以簡單地拆分成訂單系統、商品系統、登入系統等等,拆分之後的每個服務可以部署在不同的機器上,如果某一個服務的訪問量比較大的話也可以將這個服務同時部署在多臺機器上。

1.5 為什麼要分散式?

從開發角度來講單體應用的程式碼都集中在一起,而分散式系統的程式碼根據業務被拆分。所以,每個團隊可以負責一個服務的開發,這樣提升了開發效率。另外,程式碼根據業務拆分之後更加便於維護和擴充套件。

另外,我覺得將系統拆分成分散式之後不光便於系統擴充套件和維護,更能提高整個系統的效能。你想一想嘛?把整個系統拆分成不同的服務/系統,然後每個服務/系統 單獨部署在一臺伺服器上,是不是很大程度上提高了系統性能呢?

二 Dubbo 的架構

2.1 Dubbo 的架構圖解

上述節點簡單說明:

  • Provider: 暴露服務的服務提供方
  • Consumer: 呼叫遠端服務的服務消費方
  • Registry: 服務註冊與發現的註冊中心
  • Monitor: 統計服務的呼叫次數和呼叫時間的監控中心
  • Container: 服務執行容器

呼叫關係說明:

  1. 服務容器負責啟動,載入,執行服務提供者。
  2. 服務提供者在啟動時,向註冊中心註冊自己提供的服務。
  3. 服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
  4. 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
  5. 服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
  6. 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。

重要知識點總結:

  • 註冊中心負責服務地址的註冊與查詢,相當於目錄服務,服務提供者和消費者只在啟動時與註冊中心互動,註冊中心不轉發請求,壓力較小
  • 監控中心負責統計各服務呼叫次數,呼叫時間等,統計先在記憶體彙總後每分鐘一次傳送到監控中心伺服器,並以報表展示
  • 註冊中心,服務提供者,服務消費者三者之間均為長連線,監控中心除外
  • 註冊中心通過長連線感知服務提供者的存在,服務提供者宕機,註冊中心將立即推送事件通知消費者
  • 註冊中心和監控中心全部宕機,不影響已執行的提供者和消費者,消費者在本地快取了提供者列表
  • 註冊中心和監控中心都是可選的,服務消費者可以直連服務提供者
  • 服務提供者無狀態,任意一臺宕掉後,不影響使用
  • 服務提供者全部宕掉後,服務消費者應用將無法使用,並無限次重連等待服務提供者恢復

2.2 Dubbo 工作原理

圖中從下至上分為十層,各層均為單向依賴,右邊的黑色箭頭代表層之間的依賴關係,每一層都可以剝離上層被複用,其中,Service 和 Config 層為 API,其它各層均為 SPI。

各層說明

  • 第一層:service層,介面層,給服務提供者和消費者來實現的
  • 第二層:config層,配置層,主要是對dubbo進行各種配置的
  • 第三層:proxy層,服務介面透明代理,生成服務的客戶端 Stub 和伺服器端 Skeleton
  • 第四層:registry層,服務註冊層,負責服務的註冊與發現
  • 第五層:cluster層,叢集層,封裝多個服務提供者的路由以及負載均衡,將多個例項組合成一個服務
  • 第六層:monitor層,監控層,對rpc介面的呼叫次數和呼叫時間進行監控
  • 第七層:protocol層,遠端呼叫層,封裝rpc呼叫
  • 第八層:exchange層,資訊交換層,封裝請求響應模式,同步轉非同步
  • 第九層:transport層,網路傳輸層,抽象mina和netty為統一介面
  • 第十層:serialize層,資料序列化層,網路傳輸需要

三 Dubbo 的負載均衡策略

3.1 先來解釋一下什麼是負載均衡

先來個官方的解釋。

維基百科對負載均衡的定義:負載均衡改善了跨多個計算資源(例如計算機,計算機叢集,網路連結,中央處理單元或磁碟驅動的的工作負載分佈。負載平衡旨在優化資源使用,最大化吞吐量,最小化響應時間,並避免任何單個資源的過載。使用具有負載平衡而不是單個元件的多個元件可以通過冗餘提高可靠性和可用性。負載平衡通常涉及專用軟體或硬體。

上面講的大家可能不太好理解,再用通俗的話給大家說一下。

比如我們的系統中的某個服務的訪問量特別大,我們將這個服務部署在了多臺伺服器上,當客戶端發起請求的時候,多臺伺服器都可以處理這個請求。那麼,如何正確選擇處理該請求的伺服器就很關鍵。假如,你就要一臺伺服器來處理該服務的請求,那該服務部署在多臺伺服器的意義就不復存在了。負載均衡就是為了避免單個伺服器響應同一請求,容易造成伺服器宕機、崩潰等問題,我們從負載均衡的這四個字就能明顯感受到它的意義。

3.2 再來看看 Dubbo 提供的負載均衡策略

在叢集負載均衡時,Dubbo 提供了多種均衡策略,預設為 random 隨機呼叫。可以自行擴充套件負載均衡策略,參見:負載均衡擴充套件

備註:下面的圖片來自於:尚矽谷2018Dubbo 視訊。

3.2.1 Random LoadBalance(預設,基於權重的隨機負載均衡機制)

  • 隨機,按權重設定隨機概率。
  • 在一個截面上碰撞的概率高,但呼叫量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。

3.2.2 RoundRobin LoadBalance(不推薦,基於權重的輪詢負載均衡機制)

  • 輪循,按公約後的權重設定輪循比率。
  • 存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。

3.2.3 LeastActive LoadBalance

  • 最少活躍呼叫數,相同活躍數的隨機,活躍數指呼叫前後計數差。
  • 使慢的提供者收到更少請求,因為越慢的提供者的呼叫前後計數差會越大。

3.2.4 ConsistentHash LoadBalance

  • 一致性 Hash,相同引數的請求總是發到同一提供者。(如果你需要的不是隨機負載均衡,是要一類請求都到一個節點,那就走這個一致性hash策略。)
  • 當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
  • 演算法參見:http://en.wikipedia.org/wiki/Consistent_hashing
  • 預設只對第一個引數 Hash,如果要修改,請配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 預設用 160 份虛擬節點,如果要修改,請配置 <dubbo:parameter key="hash.nodes" value="320" />

3.3 配置方式

xml 配置方式

服務端服務級別

<dubbo:service interface="..." loadbalance="roundrobin" />

客戶端服務級別

<dubbo:reference interface="..." loadbalance="roundrobin" />

服務端方法級別

<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>

客戶端方法級別

<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

註解配置方式:

消費方基於基於註解的服務級別配置方式:

@Reference(loadbalance = "roundrobin")
HelloService helloService;

四 zookeeper宕機與dubbo直連的情況

zookeeper宕機與dubbo直連的情況在面試中可能會被經常問到,所以要引起重視。

在實際生產中,假如zookeeper註冊中心宕掉,一段時間內服務消費方還是能夠呼叫提供方的服務的,實際上它使用的本地快取進行通訊,這只是dubbo健壯性的一種體現。

dubbo的健壯性表現:

  1. 監控中心宕掉不影響使用,只是丟失部分取樣資料
  2. 資料庫宕掉後,註冊中心仍能通過快取提供服務列表查詢,但不能註冊新服務
  3. 註冊中心對等叢集,任意一臺宕掉後,將自動切換到另一臺
  4. 註冊中心全部宕掉後,服務提供者和服務消費者仍能通過本地快取通訊
  5. 服務提供者無狀態,任意一臺宕掉後,不影響使用
  6. 服務提供者全部宕掉後,服務消費者應用將無法使用,並無限次重連等待服務提供者恢復

我們前面提到過:註冊中心負責服務地址的註冊與查詢,相當於目錄服務,服務提供者和消費者只在啟動時與註冊中心互動,註冊中心不轉發請求,壓力較小。所以,我們可以完全可以繞過註冊中心——採用 dubbo 直連 ,即在服務消費方配置服務提供方的位置資訊。

xml配置方式:

<dubbo:reference id="userService" interface="com.zang.gmall.service.UserService" url="dubbo://localhost:20880" />

註解方式:

 @Reference(url = "127.0.0.1:20880")   
 HelloService helloService;

作者:Snailclimb
連結:Dubbo 總結:關於 Dubbo 的重要知識點
來源:github