1. 程式人生 > 實用技巧 >基於Dubbo框架構建分散式服務 (二) 【轉】

基於Dubbo框架構建分散式服務 (二) 【轉】

>>> hot3.png

Dubbo是Alibaba開源的分散式服務框架,我們可以非常容易地通過Dubbo來構建分散式服務,並根據自己實際業務應用場景來選擇合適的叢集容錯模式,這個對於很多應用都是迫切希望的,只需要通過簡單的配置就能夠實現分散式服務呼叫,也就是說服務提供方(Provider)釋出的服務可以天然就是叢集服務,比如,在實時性要求很高的應用場景下,可能希望來自消費方(Consumer)的呼叫響應時間最短,只需要選擇Dubbo的Forking Cluster模式配置,就可以對一個呼叫請求並行傳送到多臺對等的提供方(Provider)服務所在的節點上,只選擇最快一個返回響應的,然後將呼叫結果返回給服務消費方(Consumer),顯然這種方式是以冗餘服務為基礎的,需要消耗更多的資源,但是能夠滿足高實時應用的需求。

有關Dubbo服務框架的簡單使用,可以參考我的其他兩篇文章(《基於Dubbo的Hessian協議實現遠端呼叫》,《Dubbo實現RPC呼叫使用入門》,後面參考連結中已給出連結),這裡主要圍繞Dubbo分散式服務相關配置的使用來說明與實踐。

Dubbo服務叢集容錯

假設我們使用的是單機模式的Dubbo服務,如果在服務提供方(Provider)釋出服務以後,服務消費方(Consumer)發出一次呼叫請求,恰好這次由於網路問題呼叫失敗,那麼我們可以配置服務消費方重試策略,可能消費方第二次重試呼叫是成功的(重試策略只需要配置即可,重試過程是透明的);但是,如果服務提供方釋出服務所在的節點發生故障,那麼消費方再怎麼重試呼叫都是失敗的,所以我們需要採用叢集容錯模式,這樣如果單個服務節點因故障無法提供服務,還可以根據配置的叢集容錯模式,呼叫其他可用的服務節點,這就提高了服務的可用性。

首先,根據Dubbo文件,我們引用文件提供的一個架構圖以及各元件關係說明,如下所示:

上述各個元件之間的關係(引自Dubbo文件)說明如下:

  • 這裡的Invoker是Provider的一個可呼叫Service的抽象,Invoker封裝了Provider地址及Service介面資訊。
  • Directory代表多個Invoker,可以把它看成List,但與List不同的是,它的值可能是動態變化的,比如註冊中心推送變更。
  • Cluster將Directory中的多個Invoker偽裝成一個Invoker,對上層透明,偽裝過程包含了容錯邏輯,呼叫失敗後,重試另一個。
  • Router負責從多個Invoker中按路由規則選出子集,比如讀寫分離,應用隔離等。
  • LoadBalance負責從多個Invoker中選出具體的一個用於本次呼叫,選的過程包含了負載均衡演算法,呼叫失敗後,需要重選。

我們也簡單說明目前Dubbo支援的叢集容錯模式,每種模式適應特定的應用場景,可以根據實際需要進行選擇。Dubbo內建支援如下6種叢集模式:

  • Failover Cluster模式

配置值為failover。這種模式是Dubbo叢集容錯預設的模式選擇,呼叫失敗時,會自動切換,重新嘗試呼叫其他節點上可用的服務。對於一些冪等性操作可以使用該模式,如讀操作,因為每次呼叫的副作用是相同的,所以可以選擇自動切換並重試呼叫,對呼叫者完全透明。可以看到,如果重試呼叫必然會帶來響應端的延遲,如果出現大量的重試呼叫,可能說明我們的服務提供方釋出的服務有問題,如網路延遲嚴重、硬體裝置需要升級、程式演算法非常耗時,等等,這就需要仔細檢測排查了。
例如,可以這樣顯式指定Failover模式,或者不配置則預設開啟Failover模式,配置示例如下:

<dubbo:service interface="org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService" version="1.0.0" cluster="failover" retries="2" timeout="100" ref="chatRoomOnlineUserCounterService" protocol="dubbo" > <dubbo:method name="queryRoomUserCount" timeout="80" retries="2" /> </dubbo:service>

上述配置使用Failover Cluster模式,如果呼叫失敗一次,可以再次重試2次呼叫,服務級別呼叫超時時間為100ms,呼叫方法queryRoomUserCount的超時時間為80ms,允許重試2次,最壞情況呼叫花費時間160ms。如果該服務介面org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService還有其他的方法可供呼叫,則其他方法沒有顯式配置則會繼承使用dubbo:service配置的屬性值。

  • Failfast Cluster模式

配置值為failfast。這種模式稱為快速失敗模式,呼叫只執行一次,失敗則立即報錯。這種模式適用於非冪等性操作,每次呼叫的副作用是不同的,如寫操作,比如交易系統我們要下訂單,如果一次失敗就應該讓它失敗,通常由服務消費方控制是否重新發起下訂單操作請求(另一個新的訂單)。

  • Failsafe Cluster模式

配置值為failsafe。失敗安全模式,如果呼叫失敗, 則直接忽略失敗的呼叫,而是要記錄下失敗的呼叫到日誌檔案,以便後續審計。

  • Failback Cluster模式

配置值為failback。失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。

  • Forking Cluster模式

配置值為forking。並行呼叫多個伺服器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。

  • Broadcast Cluster模式

配置值為broadcast。廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯(2.1.0開始支援)。通常用於通知所有提供者更新快取或日誌等本地資源資訊。
上面的6種模式都可以應用於生產環境,我們可以根據實際應用場景選擇合適的叢集容錯模式。如果我們覺得Dubbo內建提供的幾種叢集容錯模式都不能滿足應用需要,也可以定製實現自己的叢集容錯模式,因為Dubbo框架給我提供的擴充套件的介面,只需要實現介面com.alibaba.dubbo.rpc.cluster.Cluster即可,介面定義如下所示:

@SPI(FailoverCluster.NAME) public interface Cluster { /** * Merge the directory invokers to a virtual invoker. * @param <T> * @param directory * @return cluster invoker * @throws RpcException */ @Adaptive <T> Invoker<T> join(Directory<T> directory) throws RpcException; }

關於如何實現一個自定義的叢集容錯模式,可以參考Dubbo原始碼中內建支援的汲取你容錯模式的實現,6種模式對應的實現類如下所示:

com.alibaba.dubbo.rpc.cluster.support.FailoverCluster com.alibaba.dubbo.rpc.cluster.support.FailfastCluster com.alibaba.dubbo.rpc.cluster.support.FailsafeCluster com.alibaba.dubbo.rpc.cluster.support.FailbackCluster com.alibaba.dubbo.rpc.cluster.support.ForkingCluster com.alibaba.dubbo.rpc.cluster.support.AvailableCluster

可能我們初次接觸Dubbo時,不知道如何在實際開發過程中使用Dubbo的叢集模式,後面我們會以Failover Cluster模式為例開發我們的分散式應用,再進行詳細的介紹。

Dubbo服務負載均衡

Dubbo框架內建提供負載均衡的功能以及擴充套件介面,我們可以透明地擴充套件一個服務或服務叢集,根據需要非常容易地增加/移除節點,提高服務的可伸縮性。Dubbo框架內建提供了4種負載均衡策略,如下所示:

  • Random LoadBalance:隨機策略,配置值為random。可以設定權重,有利於充分利用伺服器的資源,高配的可以設定權重大一些,低配的可以稍微小一些
  • RoundRobin LoadBalance:輪詢策略,配置值為roundrobin。
  • LeastActive LoadBalance:配置值為leastactive。根據請求呼叫的次數計數,處理請求更慢的節點會受到更少的請求
  • ConsistentHash LoadBalance:一致性Hash策略,具體配置方法可以參考Dubbo文件。相同呼叫引數的請求會發送到同一個服務提供方節點上,如果某個節點發生故障無法提供服務,則會基於一致性Hash演算法對映到虛擬節點上(其他服務提供方)

在實際使用中,只需要選擇合適的負載均衡策略值,配置即可,下面是上述四種負載均衡策略配置的示例:

<dubbo:service interface="org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService" version="1.0.0" cluster="failover" retries="2" timeout="100" loadbalance="random" ref="chatRoomOnlineUserCounterService" protocol="dubbo" > <dubbo:method name="queryRoomUserCount" timeout="80" retries="2" loadbalance="leastactive" /> </dubbo:service>

上述配置,也體現了Dubbo配置的繼承性特點,也就是dubbo:service元素配置了loadbalance=”random”,則該元素的子元素dubbo:method如果沒有指定負載均衡策略,則預設為loadbalance=”random”,否則如果dubbo:method指定了loadbalance=”leastactive”,則使用子元素配置的負載均衡策略覆蓋了父元素指定的策略(這裡呼叫queryRoomUserCount方法使用leastactive負載均衡策略)。
當然,Dubbo框架也提供了實現自定義負載均衡策略的介面,可以實現com.alibaba.dubbo.rpc.cluster.LoadBalance介面,介面定義如下所示:

/** * LoadBalance. (SPI, Singleton, ThreadSafe) * * <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a> * * @see com.alibaba.dubbo.rpc.cluster.Cluster#join(Directory) * @author qian.lei * @author william.liangf */ @SPI(RandomLoadBalance.NAME) public interface LoadBalance { /** * select one invoker in list. * @param invokers invokers. * @param url refer url * @param invocation invocation. * @return selected invoker. */ @Adaptive("loadbalance") <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; }

如何實現一個自定義負載均衡策略,可以參考Dubbo框架內建的實現,如下所示的3個實現類:

com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance

Dubbo服務叢集容錯實踐

手機應用是以聊天室為基礎的,我們需要收集使用者的操作行為,然後計算聊天室中線上人數,並實時在手機應用端顯示人數,整個系統的架構如圖所示:

上圖中,主要包括了兩大主要流程:日誌收集並實時處理流程、呼叫讀取實時計算結果流程,我們使用基於Dubbo框架開發的服務來提供實時計算結果讀取聊天人數的功能。上圖中,實際上業務介面伺服器叢集也可以基於Dubbo框架構建服務,就看我們想要構建什麼樣的系統來滿足我們的需要。
如果不使用註冊中心,服務消費方也能夠直接呼叫服務提供方釋出的服務,這樣需要服務提供方將服務地址暴露給服務消費方,而且也無法使用監控中心的功能,這種方式成為直連。
如果我們使用註冊中心,服務提供方將服務釋出到註冊中心,而服務消費方可以通過註冊中心訂閱服務,接收服務提供方服務變更通知,這種方式可以隱藏服務提供方的細節,包括伺服器地址等敏感資訊,而服務消費方只能通過註冊中心來獲取到已註冊的提供方服務,而不能直接跨過註冊中心與服務提供方直接連線。這種方式的好處是還可以使用監控中心服務,能夠對服務的呼叫情況進行監控分析,還能使用Dubbo服務管理中心,方便管理服務,我們在這裡使用的是這種方式,也推薦使用這種方式。使用註冊中心的Dubbo分散式服務相關元件結構,如下圖所示:

框架/平臺構成:
Maven+Springmvc + Mybatis + Shiro(許可權)+ Tiles(模板) +ActiveMQ(訊息佇列) + Rest(服務) + WebService(服務)+ EHcache(快取) + Quartz(定時排程)+ Html5(支援PC、IOS、Android)

使用者許可權系統:
組織結構:角色、使用者、使用者組、組織機構;許可權點:頁面、方法、按鈕、資料許可權、分級授權

專案管理新體驗:
快速出原型系統、元件樹、版本控制、模組移植、協同開發、實時監控、釋出管理

可持續整合:
所有元件可移植、可定製、可擴充,開發成果不斷積累,形成可持續發展的良性迴圈

支援平臺平臺:
Windows XP、Windows 7 、Windows 10 、 Linux 、 Unix

伺服器容器:
Tomcat 5/6/7 、Jetty、JBoss、WebSphere 8.5

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

JEESZ通用版本分散式模組化開發平臺 - zookeeperflume - zookeeperflume的部落格

轉載於:https://my.oschina.net/grthrj/blog/754419