一、dubbo是什么?
DUBBO是一個分布式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,是阿里巴巴SOA服務化治理方案的核心框架。
二、dubbo的工作模式

節點角色說明:
- Provider: 暴露服務的服務提供方。
- Consumer: 調用遠程服務的服務消費方。
- Registry: 服務注冊與發現的注冊中心。
- Monitor: 統計服務的調用次數和調用時間的監控中心。
- Container: 服務運行容器。
調用關系說明:
- 0. 服務容器負責啟動,加載,運行服務提供者。
- 1. 服務提供者在啟動時,向注冊中心注冊自己提供的服務。
- 2. 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
- 3. 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基於長連接推送變更數據給消費者。
- 4. 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
- 5. 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鍾發送一次統計數據到監控中心。
三、一個簡單的例子
1、首先我們需要安裝Zookeeper,使用它作為dubbo的注冊中心,Zookeeper可以單擊部署、集群部署和偽集群部署(在一台服務器上配置多個Zookeeper實例);
1)在http://www.apache.org/dyn/closer.cgi/zookeeper/下載安裝包,解壓;
2)把conf目錄下的zoo_sample.cfg文件修改為zoo.cfg,Zookeeper啟動時會查找這個文件,配置信息:
# The number of milliseconds of each tick Zookeeper tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. #dataDir=/tmp/zookeeper dataDir=D:\\dev-env\\zookeeper-3.5.1-alpha\\data dataLogDir=D:\\dev-env\\zookeeper-3.5.1-alpha\\logs # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
參數說明:
tickTime:服務器之間或客戶端與服務器之間維持心跳的時間間隔,每一個tickTime時間會發送一個心跳
dataDir:數據目錄,默認情況,zookeeper將寫數據的日志也保存這個目錄
dataLogDir:zookeeper保存日志文件的目錄
clientPort:客戶端連接zookeeper服務器的端口,zookeeper會監聽這個端口,接受客戶端的訪問請求
Zookeeper的集群模式,需要增加幾個配置項(也支持偽集群,在一台服務器上配置多個Zookeeper實例):
initLimit=5 syncLimit=2 server.1=192.168.2.1:2888:3888 server.2=192.168.2.2:2888:3888
initLimit: 這個是用來配置zookeeper接受客戶端(這里說的客戶端不是用戶連接zookeeper的客戶端,而是zookeeper服務器集群中連接到Leader的
Follower服務器)初始化連接時最長能忍受多少個心跳時間,當已經超過5個心跳時間長度后zookeeper服務器還沒有收到客戶端的返回信息,那么
表明這個客戶端連接失敗。總的時間長度就是5*2000=10秒
syncLimit: 這個配置標示Leader和Follower之間發送消息,請求和應答時間長度,最長不能超過多少個tickTime的時間長度,總的時間長度就是
2*2000=4秒
server.A=B:C:D 其中A是一個數字,表示這個是第幾號服務器;B表示服務器ip地址,C表示這個服務器與集群中的Leader服務器交換信息的端口;
D表示萬一集群中的Leader服務器掛了,需要一個端口來重新進行選舉,選出一個新的Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。
如果是偽集群的配置方式,由於B都是一樣的,所以不同的Zookeeper實例通信端口不能一樣,所以要給他們分配不同的端口。
集群模式下,除了配置zoo.cfg文件,還需要配置一個myid,這個文件在dataDir目錄下,這個文件里就有一個數據就是A的值,Zookeeper啟動時會讀取這個
文件,拿到里面的數據與zoo.cfg里面的配置信息比較從而判斷到底是哪個server
3)然后就可以啟動Zookeeper了,windows下運行bin\zkServer.cmd,linux下運行zkServer.sh。
注意:如果是在windows下安裝Zookeeper,啟動時可能會提示"Error: JAVA_HOME is incorrectly set." ,這時候我們需要修改bin目錄下的zkEnv.cmd,修改如下:
原代碼:
if not defined JAVA_HOME (
echo Error: JAVA_HOME is not set. goto :eof ) if not exist %JAVA_HOME%\bin\java.exe ( echo Error: JAVA_HOME is incorrectly set. goto :eof ) set JAVA=%JAVA_HOME%\bin\java
修改后:
if not defined JAVA_HOME (
echo Error: JAVA_HOME is not set. goto :eof ) if not exist "%JAVA_HOME%\bin\java.exe" ( echo Error: JAVA_HOME is incorrectly set. goto :eof ) set JAVA="%JAVA_HOME%\bin\java"
如果提示java版本問題,這時需要升級jdk。
2、下載dubbo-admin.war,修改一下WEB-INF/dubbo.properties中的配置,然后隨便找個tomcat部署起來就行了;訪問http://127.0.0.1:(你的端口號)/,這里可以對我們的dubbo服務進行管理。
3、編寫一個簡單的例子
項目使用Maven管理依賴。
1) 首先新建一個dubbo-parent項目,用來管理dubbo依賴:

pom中依賴配置如下:
<properties> <dubbo_version>2.1.2</dubbo_version> <spring_version>2.5.6.SEC03</spring_version> <javassist_version>3.15.0-GA</javassist_version> <log4j_version>1.2.16</log4j_version> <jcl_version>1.1</jcl_version> <netty_version>3.2.5.Final</netty_version> <zookeeper_version>3.3.3</zookeeper_version> <zkclient_version>0.1</zkclient_version> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>${dubbo_version}</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>${zookeeper_version}</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>${zkclient_version}</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>${javassist_version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>${spring_version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j_version}</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>${jcl_version}</version> </dependency> <dependency> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> <version>${netty_version}</version> </dependency> </dependencies>
2)新建dubbo-api項目,我們在這個項目中定義服務接口:

建立一個接口DemoService:
package com.test.service; public interface DemoService { String sayHello(String paramString); }
3)新建dubbo-provider項目(生產者,服務提供方),繼承dubbo-parent,同時配置依賴dubbo-api,pom如下:
<modelVersion>4.0.0</modelVersion> <parent> <groupId>com.test.dubbo</groupId> <artifactId>dubbo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>dubbo-provider</artifactId> <dependencies> <dependency> <groupId>com.test.dubbo</groupId> <artifactId>dubbo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
創建DemoService的實現DemoServiceImpl:
package com.test.service.impl; import java.text.SimpleDateFormat; import java.util.Date; import com.alibaba.dubbo.rpc.RpcContext; import com.test.service.DemoService; public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } }
創建dubbo-provider.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-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 提供方應用信息,用於計算依賴關系 --> <dubbo:application name="hello-world-app" /> <!-- 暴露服務地址,注冊中心地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 用dubbo協議在20880端口暴露服務 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 服務實現 --> <bean id="demoService" class="com.test.service.impl.DemoServiceImpl" /> <!-- 聲明需要暴露的服務 --> <dubbo:service interface="com.test.service.DemoService" ref="demoService" /> </beans>
創建程序啟動類:
package com.test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Provider { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "dubbo-provider.xml" }); context.start(); System.in.read(); // 按任意鍵退出 } }
4)新建dubbo-consumer項目(消費者,服務調用方),繼承dubbo-parent,同時配置依賴dubbo-api,pom如下:
<modelVersion>4.0.0</modelVersion> <parent> <groupId>com.test.dubbo</groupId> <artifactId>dubbo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>dubbo-consumer</artifactId> <dependencies> <dependency> <groupId>com.test.dubbo</groupId> <artifactId>dubbo-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
創建dubbo-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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 消費方應用名,用於計算依賴關系,不是匹配條件,不要與提供方一樣 --> <dubbo:application name="consumer-of-helloworld-app" /> <!-- 注冊中心,發現服務的地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 生成遠程服務代理,可以和本地bean一樣使用demoService --> <dubbo:reference id="demoService" interface="com.test.service.DemoService" /> </beans>
創建啟動類:
package com.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.test.service.DemoService; public class Consumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "dubbo-consumer.xml" }); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); // 獲取遠程服務代理 String hello = demoService.sayHello("world"); // 執行遠程方法 System.out.println(hello); } }
5)我們來測試一下!
首先運行dubbo-provider項目中Provider類:
然后我們在dubbo-admin的管理頁面查看我們的服務是否已經在注冊中心完成注冊,如果程序正常執行,我們會看到如下界面:

接着,我們啟動消費者dubbo-consumer項目中的Consumer類,程序執行結果如下圖說明我們的程序正常執行了:

