Dubbo是Alibaba開源的分佈式服務框架,咱們能夠很是容易地經過Dubbo來構建分佈式服務,並根據本身實際業務應用場景來選擇合適的集羣容錯模式,這個對於不少應用都是迫切但願的,只須要經過簡單的配置就可以實現分佈式服務調用,也就是說服務提供方(Provider)發佈的服務能夠自然就是集羣服務,好比,在實時性要求很高的應用場景下,可能但願來自消費方(Consumer)的調用響應時間最短,只須要選擇Dubbo的Forking Cluster模式配置,就能夠對一個調用請求並行發送到多臺對等的提供方(Provider)服務所在的節點上,只選擇最快一個返回響應的,而後將調用結果返回給服務消費方(Consumer),顯然這種方式是以冗餘服務爲基礎的,須要消耗更多的資源,可是可以知足高實時應用的需求。 html
1、Dubbo服務集羣容錯java
假設咱們使用的是單機模式的Dubbo服務,若是在服務提供方(Provider)發佈服務之後,服務消費方(Consumer)發出一次調用請求,剛好此次因爲網絡問題調用失敗,那麼咱們能夠配置服務消費方重試策略,可能消費方第二次重試調用是成功的(重試策略只須要配置便可,重試過程是透明的);可是,若是服務提供方發佈服務所在的節點發生故障,那麼消費方再怎麼重試調用都是失敗的,因此咱們須要採用集羣容錯模式,這樣若是單個服務節點因故障沒法提供服務,還能夠根據配置的集羣容錯模式,調用其餘可用的服務節點,這就提升了服務的可用性。
首先,根據Dubbo文檔,咱們引用文檔提供的一個架構圖以及各組件關係說明,以下所示:
上述各個組件之間的關係(引自Dubbo文檔)說明以下:web
咱們也簡單說明目前Dubbo支持的集羣容錯模式,每種模式適應特定的應用場景,能夠根據實際須要進行選擇。redis
Dubbo內置支持以下6種集羣模式:算法
(1) Failover Cluster模式spring
配置值爲failover。這種模式是Dubbo集羣容錯默認的模式選擇,調用失敗時,會自動切換,從新嘗試調用其餘節點上可用的服務。對於一些冪等性操做可使用該模式,如讀操做,由於每次調用的反作用是相同的,因此能夠選擇自動切換並重試調用,對調用者徹底透明。能夠看到,若是重試調用必然會帶來響應端的延遲,若是出現大量的重試調用,可能說明咱們的服務提供方發佈的服務有問題,如網絡延遲嚴重、硬件設備須要升級、程序算法很是耗時,等等,這就須要仔細檢測排查了。
例如,能夠這樣顯式指定Failover模式,或者不配置則默認開啓Failover模式,配置示例以下: apache
<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配置的屬性值。api
(2) Failfast Cluster模式緩存
配置值爲failfast。這種模式稱爲快速失敗模式,調用只執行一次,失敗則當即報錯。這種模式適用於非冪等性操做,每次調用的反作用是不一樣的,如寫操做,好比交易系統咱們要下訂單,若是一次失敗就應該讓它失敗,一般由服務消費方控制是否從新發起下訂單操做請求(另外一個新的訂單)。tomcat
(3) Failsafe Cluster模式
配置值爲failsafe。失敗安全模式,若是調用失敗, 則直接忽略失敗的調用,而是要記錄下失敗的調用到日誌文件,以便後續審計。
(4) Failback Cluster模式
配置值爲failback。失敗自動恢復,後臺記錄失敗請求,定時重發。一般用於消息通知操做。
(5) Forking Cluster模式
配置值爲forking。並行調用多個服務器,只要一個成功即返回。一般用於實時性要求較高的讀操做,但須要浪費更多服務資源。
(6) 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模式爲例開發咱們的分佈式應用,再進行詳細的介紹。
2、Dubbo服務負載均衡
Dubbo框架內置提供負載均衡的功能以及擴展接口,咱們能夠透明地擴展一個服務或服務集羣,根據須要很是容易地增長/移除節點,提升服務的可伸縮性。
Dubbo框架內置提供了4種負載均衡策略,以下所示:
(1)Random LoadBalance:隨機策略,配置值爲random。能夠設置權重,有利於充分利用服務器的資源,高配的能夠設置權重大一些,低配的能夠稍微小一些
(2)RoundRobin LoadBalance:輪詢策略,配置值爲roundrobin。
(3)LeastActive LoadBalance:配置值爲leastactive。根據請求調用的次數計數,處理請求更慢的節點會受到更少的請求
(4)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分佈式服務相關組件結構,以下圖所示:
下面,開發部署咱們的應用,經過以下4個步驟來完成:
服務接口將服務提供方(Provider)和服務消費方(Consumer)鏈接起來,服務提供方實現接口中定義的服務,即給出服務的實現,而服務消費方負責調用服務。咱們接口中給出了2個方法,一個是實時查詢獲取當前聊天室內人數,另外一個是查詢一天中某個/某些聊天室中在線人數峯值,接口定義以下所示:
package org.shirdrn.dubbo.api; import java.util.List; public interface ChatRoomOnlineUserCounterService { String queryRoomUserCount(String rooms); List<String> getMaxOnlineUserCount(List<String> rooms, String date, String dateFormat); }
接口是服務提供方和服務消費方公共遵照的協議,通常狀況下是服務提供方將接口定義好後提供給服務消費方。
服務提供方實現接口中定義的服務,其實現和普通的服務沒什麼區別,咱們的實現類爲ChatRoomOnlineUserCounterServiceImpl,代碼以下所示:
package org.shirdrn.dubbo.provider.service; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService; import org.shirdrn.dubbo.common.utils.DateTimeUtils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import com.alibaba.dubbo.common.utils.StringUtils; import com.google.common.base.Strings; import com.google.common.collect.Lists; public class ChatRoomOnlineUserCounterServiceImpl implements ChatRoomOnlineUserCounterService { private static final Log LOG = LogFactory.getLog(ChatRoomOnlineUserCounterServiceImpl.class); private JedisPool jedisPool; private static final String KEY_USER_COUNT = "chat::room::play::user::cnt"; private static final String KEY_MAX_USER_COUNT_PREFIX = "chat::room::max::user::cnt::"; private static final String DF_YYYYMMDD = "yyyyMMdd"; public String queryRoomUserCount(String rooms) { LOG.info("Params[Server|Recv|REQ] rooms=" + rooms); StringBuffer builder = new StringBuffer(); if(!Strings.isNullOrEmpty(rooms)) { Jedis jedis = null; try { jedis = jedisPool.getResource(); String[] fields = rooms.split(","); List<String> results = jedis.hmget(KEY_USER_COUNT, fields); builder.append(StringUtils.join(results, ",")); } catch (Exception e) { LOG.error("", e); } finally { if(jedis != null) { jedis.close(); } } } LOG.info("Result[Server|Recv|RES] " + builder.toString()); return builder.toString(); } @Override public List<String> getMaxOnlineUserCount(List<String> rooms, String date, String dateFormat) { // HGETALL chat::room::max::user::cnt::20150326 LOG.info("Params[Server|Recv|REQ] rooms=" + rooms + ",date=" + date + ",dateFormat=" + dateFormat); String whichDate = DateTimeUtils.format(date, dateFormat, DF_YYYYMMDD); String key = KEY_MAX_USER_COUNT_PREFIX + whichDate; StringBuffer builder = new StringBuffer(); if(rooms != null && !rooms.isEmpty()) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.hmget(key, rooms.toArray(new String[rooms.size()])); } catch (Exception e) { LOG.error("", e); } finally { if(jedis != null) { jedis.close(); } } } LOG.info("Result[Server|Recv|RES] " + builder.toString()); return Lists.newArrayList(); } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } }
代碼中經過讀取Redis中數據來完成調用,邏輯比較簡單。對應的Maven POM依賴配置,以下所示:
<dependencies> <dependency> <groupId>org.shirdrn.dubbo</groupId> <artifactId>dubbo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.shirdrn.dubbo</groupId> <artifactId>dubbo-commons</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> <version>3.2.7.Final</version> </dependency> </dependencies>
有關對Dubbo框架的一些依賴,咱們單獨放到一個通用的Maven Module中(詳見後面「附錄:Dubbo使用Maven構建依賴配置」),這裏再也不多說。服務提供方實現,最關鍵的就是服務的配置,由於Dubbo基於Spring來管理配置和實例,因此經過配置能夠指定服務是不是分佈式服務,以及經過配置增長不少其它特性。咱們的配置文件爲provider-cluster.xml,內容以下所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> <property name="ignoreResourceNotFound" value="true" /> <property name="locations"> <list> <value>classpath*:jedis.properties</value> </list> </property> </bean> <dubbo:application name="chatroom-cluster-provider" /> <dubbo:registry address="zookeeper://zk1:2181?backup=zk2:2181,zk3:2181" /> <dubbo:protocol name="dubbo" port="20880" /> <dubbo:service interface="org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService" version="1.0.0" cluster="failover" retries="2" timeout="1000" loadbalance="random" actives="100" executes="200" ref="chatRoomOnlineUserCounterService" protocol="dubbo" > <dubbo:method name="queryRoomUserCount" timeout="500" retries="2" loadbalance="roundrobin" actives="50" /> </dubbo:service> <bean id="chatRoomOnlineUserCounterService" class="org.shirdrn.dubbo.provider.service.ChatRoomOnlineUserCounterServiceImpl" > <property name="jedisPool" ref="jedisPool" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy"> <constructor-arg index="0"> <bean class="org.apache.commons.pool2.impl.GenericObjectPoolConfig"> <property name="maxTotal" value="${redis.pool.maxTotal}" /> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <property name="minIdle" value="${redis.pool.minIdle}" /> <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" /> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> <property name="testOnReturn" value="${redis.pool.testOnReturn}" /> <property name="testWhileIdle" value="true" /> </bean> </constructor-arg> <constructor-arg index="1" value="${redis.host}" /> <constructor-arg index="2" value="${redis.port}" /> <constructor-arg index="3" value="${redis.timeout}" /> </bean> </beans>
上面配置中,使用dubbo協議,集羣容錯模式爲failover,服務級別負載均衡策略爲random,方法級別負載均衡策略爲roundrobin(它覆蓋了服務級別的配置內容),其餘一些配置內容能夠參考Dubbo文檔。咱們這裏是從Redis讀取數據,因此使用了Redis鏈接池。
啓動服務示例代碼以下所示:
package org.shirdrn.dubbo.provider; import org.shirdrn.dubbo.provider.common.DubboServer; public class ChatRoomClusterServer { public static void main(String[] args) throws Exception { DubboServer.startServer("classpath:provider-cluster.xml"); } }
上面調用了DubboServer類的靜態方法startServer,以下所示:
public static void startServer(String config) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config); try { context.start(); System.in.read(); } catch (IOException e) { e.printStackTrace(); } finally { context.close(); } }
方法中主要是初始化Spring IoC容器,所有對象都交由容器來管理。
服務消費方就容易了,只須要知道註冊中心地址,並引用服務提供方提供的接口,消費方調用服務實現以下所示:
package org.shirdrn.dubbo.consumer; import java.util.Arrays; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService; import org.springframework.context.support.AbstractXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ChatRoomDubboConsumer { private static final Log LOG = LogFactory.getLog(ChatRoomDubboConsumer.class); public static void main(String[] args) throws Exception { AbstractXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml"); try { context.start(); ChatRoomOnlineUserCounterService chatRoomOnlineUserCounterService = (ChatRoomOnlineUserCounterService) context.getBean("chatRoomOnlineUserCounterService"); getMaxOnlineUserCount(chatRoomOnlineUserCounterService); getRealtimeOnlineUserCount(chatRoomOnlineUserCounterService); System.in.read(); } finally { context.close(); } } private static void getMaxOnlineUserCount(ChatRoomOnlineUserCounterService liveRoomOnlineUserCountService) { List<String> maxUserCounts = liveRoomOnlineUserCountService.getMaxOnlineUserCount( Arrays.asList(new String[] {"1482178010" , "1408492761", "1430546839", "1412517075", "1435861734"}), "20150327", "yyyyMMdd"); LOG.info("After getMaxOnlineUserCount invoked: maxUserCounts= " + maxUserCounts); } private static void getRealtimeOnlineUserCount(ChatRoomOnlineUserCounterService liveRoomOnlineUserCountService) throws InterruptedException { String rooms = "1482178010,1408492761,1430546839,1412517075,1435861734"; String onlineUserCounts = liveRoomOnlineUserCountService.queryRoomUserCount(rooms); LOG.info("After queryRoomUserCount invoked: onlineUserCounts= " + onlineUserCounts); } }
對應的配置文件爲consumer.xml,內容以下所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="chatroom-consumer" /> <dubbo:registry address="zookeeper://zk1:2181?backup=zk2:2181,zk3:2181" /> <dubbo:reference id="chatRoomOnlineUserCounterService" interface="org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService" version="1.0.0"> <dubbo:method name="queryRoomUserCount" retries="2" /> </dubbo:reference> </beans>
也能夠根據須要配置dubbo:reference相關的屬性值,也能夠配置dubbo:method指定調用的方法的配置信息,詳細配置屬性能夠參考Dubbo官方文檔。
開發完成提供方服務後,在本地開發調試的時候能夠怎麼簡單怎麼作,若是是要部署到生產環境,則須要打包後進行部署,能夠參考下面的Maven POM配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.4</version> <configuration> <createDependencyReducedPom>true</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" /> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.shirdrn.dubbo.provider.ChatRoomClusterServer</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
這裏也給出Maven POM依賴的簡單配置:
<dependencies> <dependency> <groupId>org.shirdrn.dubbo</groupId> <artifactId>dubbo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
咱們開發的服務應該是分佈式的,首先是經過配置內容來決定,例如設置集羣模式、設置負載均衡模式等,而後在部署的時候,能夠在多個節點上同一個服務,這樣多個服務都會註冊到Dubbo註冊中心,若是某個節點上的服務不可用了,能夠根據咱們配置的策略來選擇其餘節點上的可用服務,後面經過Dubbo服務管理中心和監控中心就能更加清楚明瞭。
Dubbo服務管理與監控
咱們須要在安裝好管理中心和監控中心之後,再將上面的開發的提供方服務部署到物理節點上,而後就可以經過管理中心和監控中心來查看對應的詳細狀況。
安裝Dubbo服務管理中心,須要選擇一個Web容器,咱們使用Tomcat服務器。首先下載Dubbo管理中心安裝文件dubbo-admin-2.5.3.war,或者直接從源碼構建獲得該WAR文件。這裏,咱們已經構建好對應的WAR文件,而後進行安裝,執行以下命令:
cd apache-tomcat-6.0.35 rm -rf webapps/ROOT unzip ~/dubbo-admin-2.5.3.war -d webapps/ROOT
修改配置文件~/apache-tomcat-6.0.35/webapps/ROOT/WEB-INF/dubbo.properties,指定咱們的註冊中心地址以及登陸密碼,內容以下所示:
dubbo.registry.address=zookeeper://zk1:2181?backup=zk2:2181,zk3:2181 dubbo.admin.root.password=root dubbo.admin.guest.password=guest
而後,根據須要修改~/apache-tomcat-6.0.35/conf/server.xml配置文件,主要是Tomcat HTTP 端口號(我這裏使用8083端口),完成後能夠直接啓動Tomcat服務器:
cd ~/apache-tomcat-6.0.35/
bin/catalina.sh start
而後訪問地址http://10.10.4.130:8083/便可,根據配置文件指定的root用戶密碼,就能夠登陸Dubbo管理控制檯。
咱們將上面開發的服務提供方服務,部署到2個獨立的節點上(192.168.14.1和10.10.4.125),而後能夠經過Dubbo管理中心查看對應服務的情況,如圖所示:
上圖中能夠看出,該服務有兩個獨立的節點能夠提供,由於配置的集羣模式爲failover,若是某個節點的服務發生故障沒法使用,則會自動透明地重試另外一個節點上的服務,這樣就不至於出現拒絕服務的狀況。若是想要查看提供方某個節點上的服務詳情,能夠點擊對應的IP:Port連接,示例如圖所示:
上圖能夠看到服務地址:
dubbo://10.10.4.125:20880/org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService?actives=100&anyhost=true&application=chatroom-cluster-provider&cluster=failover&dubbo=0.0.1-SNAPSHOT&executes=200&interface=org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService&loadbalance=random&methods=getMaxOnlineUserCount,queryRoomUserCount&pid=30942&queryRoomUserCount.actives=50&queryRoomUserCount.loadbalance=leastactive&queryRoomUserCount.retries=2&queryRoomUserCount.timeout=500&retries=2&revision=0.0.1-SNAPSHOT&side=provider&timeout=1000×tamp=1427793652814&version=1.0.0
若是咱們直接暴露該地址也是能夠的,不過這種直連的方式對服務消費方不是透明的,若是之後IP地址更換,也會影響調用方,因此最好是經過註冊中心來隱蔽服務地址。同一個服務所部署在的多個節點上,也就對應對應着多個服務地址。另外,也能夠對已經發布的服務進行控制,如修改訪問控制、負載均衡相關配置內容等,能夠經過上圖中「消費者」查看服務消費方調用服務的狀況,如圖所示:
也在管理控制檯能夠對消費方進行管理控制。
Dubbo監控中心是以Dubbo服務的形式發佈到註冊中心,和普通的服務時同樣的。例如,我這裏下載了Dubbo自帶的簡易監控中心文件dubbo-monitor-simple-2.5.3-assembly.tar.gz,能夠解壓縮之後,修改配置文件~/dubbo-monitor-simple-2.5.3/conf/dubbo.properties的內容,以下所示:
dubbo.container=log4j,spring,registry,jetty dubbo.application.name=simple-monitor dubbo.application.owner= dubbo.registry.address=zookeeper://zk1:2181?backup=zk2:2181,zk3:2181 dubbo.protocol.port=7070 dubbo.jetty.port=8087 dubbo.jetty.directory=${user.home}/monitor dubbo.charts.directory=${dubbo.jetty.directory}/charts dubbo.statistics.directory=${user.home}/monitor/statistics dubbo.log4j.file=logs/dubbo-monitor-simple.log dubbo.log4j.level=WARN
而後啓動簡易監控中心,執行以下命令:
cd ~/dubbo-monitor-simple-2.5.3
bin/start.sh
這裏使用了Jetty Web容器,訪問地址http://10.10.4.130:8087/就能夠查看監控中心,Applications選項卡頁面包含了服務提供方和消費方的基本信息,如圖所示:
上圖主要列出了全部提供方發佈的服務、消費方調用、服務依賴關係等內容。
接着,查看Services選項卡頁面,包含了服務提供方提供的服務列表,如圖所示:
點擊上圖中Providers連接就能看到服務提供方的基本信息,包括服務地址等,如圖所示:
點擊上圖中Consumers連接就能看到服務消費方的基本信息,包括服務地址等,如圖所示:
因爲上面是Dubbo自帶的一個簡易監控中心,可能所展示的內容並不能知足咱們的須要,因此能夠根據須要開發本身的監控中心。Dubbo也提供了監控中心的擴展接口,若是想要實現本身的監控中心,能夠實現接口com.alibaba.dubbo.monitor.MonitorFactory和com.alibaba.dubbo.monitor.Monitor,其中MonitorFactory接口定義以下所示:
/** * MonitorFactory. (SPI, Singleton, ThreadSafe) * * @author william.liangf */ @SPI("dubbo") public interface MonitorFactory { /** * Create monitor. * @param url * @return monitor */ @Adaptive("protocol") Monitor getMonitor(URL url); }
Monitor接口定義以下所示:
/** * Monitor. (SPI, Prototype, ThreadSafe) * * @see com.alibaba.dubbo.monitor.MonitorFactory#getMonitor(com.alibaba.dubbo.common.URL) * @author william.liangf */ public interface Monitor extends Node, MonitorService { }
具體定義內容能夠查看MonitorService接口,再也不累述。
總結
Dubbo還提供了其餘不少高級特性,如路由規則、參數回調、服務分組、服務降級等等,並且不少特性在給出內置實現的基礎上,還給出了擴展的接口,咱們能夠給出自定義的實現,很是方便並且強大。更多能夠參考Dubbo官網用戶手冊和開發手冊。