1.1 Dubbo簡介
Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司開源的一個高性能、輕量級的開源Java RPC框架,可以和Spring框架無縫集成。
什么是RPC?
RPC全稱為remote procedure call,即遠程過程調用。比如兩台服務器A和B,A服務器上部署一個應用,B服務器上部署一個應用,A服務器上的應用想調用B服務器上的應用提供的方法,由於兩個應用不在一個內存空間,不能直接調用,所以需要通過網絡來表達調用的語義和傳達調用的數據。
需要注意的是RPC並不是一個具體的技術,而是指整個網絡遠程調用過程。
RPC是一個泛化的概念,嚴格來說一切遠程過程調用手段都屬於RPC范疇。各種開發語言都有自己的RPC框架。Java中的RPC框架比較多,廣泛使用的有RMI、Hessian、Dubbo等。
Dubbo官網地址:http://dubbo.apache.org
Dubbo提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動注冊和發現。
1.1 Dubbo架構
架構

節點角色說明
| 節點 | 角色說明 |
|---|---|
Provider |
暴露服務的服務提供方 |
Consumer |
調用遠程服務的服務消費方 |
Registry |
服務注冊與發現的注冊中心 |
Monitor |
統計服務的調用次數和調用時間的監控中心 |
Container |
服務運行容器 |
調用關系說明
- 服務容器負責啟動,加載,運行服務提供者。
- 服務提供者在啟動時,向注冊中心注冊自己提供的服務。
- 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
- 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基於長連接推送變更數據給消費者。
- 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
- 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鍾發送一次統計數據到監控中心。
Dubbo 架構具有以下幾個特點,分別是連通性、健壯性、伸縮性、以及向未來架構的升級性。
連通性
- 注冊中心負責服務地址的注冊與查找,相當於目錄服務,服務提供者和消費者只在啟動時與注冊中心交互,注冊中心不轉發請求,壓力較小
- 監控中心負責統計各服務調用次數,調用時間等,統計先在內存匯總后每分鍾一次發送到監控中心服務器,並以報表展示
- 服務提供者向注冊中心注冊其提供的服務,並匯報調用時間到監控中心,此時間不包含網絡開銷
- 服務消費者向注冊中心獲取服務提供者地址列表,並根據負載算法直接調用提供者,同時匯報調用時間到監控中心,此時間包含網絡開銷
- 注冊中心,服務提供者,服務消費者三者之間均為長連接,監控中心除外
- 注冊中心通過長連接感知服務提供者的存在,服務提供者宕機,注冊中心將立即推送事件通知消費者
- 注冊中心和監控中心全部宕機,不影響已運行的提供者和消費者,消費者在本地緩存了提供者列表
- 注冊中心和監控中心都是可選的,服務消費者可以直連服務提供者
健壯性
- 監控中心宕掉不影響使用,只是丟失部分采樣數據
- 數據庫宕掉后,注冊中心仍能通過緩存提供服務列表查詢,但不能注冊新服務
- 注冊中心對等集群,任意一台宕掉后,將自動切換到另一台
- 注冊中心全部宕掉后,服務提供者和服務消費者仍能通過本地緩存通訊
- 服務提供者無狀態,任意一台宕掉后,不影響使用
- 服務提供者全部宕掉后,服務消費者應用將無法使用,並無限次重連等待服務提供者恢復
伸縮性
- 注冊中心為對等集群,可動態增加機器部署實例,所有客戶端將自動發現新的注冊中心
- 服務提供者無狀態,可動態增加機器部署實例,注冊中心將推送新的服務提供者信息給消費者
升級性
當服務集群規模進一步擴大,帶動IT治理結構進一步升級,需要實現動態部署,進行流動計算,現有分布式服務架構不會帶來阻力。下圖是未來可能的一種架構:

節點角色說明
| 節點 | 角色說明 |
|---|---|
Deployer |
自動部署服務的本地代理 |
Repository |
倉庫用於存儲服務應用發布包 |
Scheduler |
調度中心基於訪問壓力自動增減服務提供者 |
Admin |
統一管理控制台 |
Registry |
服務注冊與發現的注冊中心 |
Monitor |
統計服務的調用次數和調用時間的監控中心 |
服務注冊中心Zookeeper
2.1 Zookeeper簡介
2.1.1 Zookeeper簡介
Zookeeper 是 Apache Hadoop 的子項目,是一個樹型的目錄服務,支持變更推送,適合作為 Dubbo 服務的注冊中心,工業強度較高,可用於生產環境,並推薦使用 。
為了便於理解Zookeeper的樹型目錄服務,我們先來看一下我們電腦的文件系統(也是一個樹型目錄結構):

Zookeeper樹型目錄服務:

流程說明:
服務提供者(Provider)啟動時: 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
服務消費者(Consumer)啟動時: 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址。並向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
監控中心(Monitor)啟動時: 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費者 URL 地址
2.1.2 Zookeeper安裝與啟動
使用資料中提供的windows版本zookeeper服務器進行安裝即可

進入安裝路徑的bin目錄,雙擊zkServer.cmd即可啟動zookeeper服務
簡單案例
Dubbo作為一個RPC框架,其最核心的功能就是要實現跨網絡的遠程調用。現在要創建兩個應用,一個作為服務的提供者,一個作為服務的消費者。通過Dubbo來實現服務消費者遠程調用服務提供者的方法。
項目目錄結構如圖

服務提供者
創建一個空工程,並創建maven工程(打包方式為war)dubbodemo_provider模塊,在pom.xml文件中導入如下坐標
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> </dependencies>
第二步、編寫spring與dubbo整合的服務提供者spring配置文件applicationContext-dubboprovider.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:aop="http://www.springframework.org/schema/aop" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--給當前服務提供者命名--> <dubbo:application name="dubbodemo_provider"/> <!--指定zookeeper注冊中心的address和port,如果使用的是redis則address使用redis的address--> <dubbo:registry address="zookeeper://127.0.0.1:2181" ></dubbo:registry> <!--協議必須使用dubbo,端口號是提供一個可供消費者使用的端口--> <dubbo:protocol name="dubbo" port="20881"/> <!--開啟注解掃描,使dubbo的注解生效--> <dubbo:annotation package="com.alibaba.provider"/> </beans>
第三步、在web.xml中配置項目加載監聽器,並指定spring配置文件的路徑
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 監聽器監聽其他的spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
第四步、編寫service的接口和實現類
Service接口代碼
public interface HelloService { public String sayHello(String name); }
Service實現類代碼
import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.service.provider.HelloService; //此注解使用的阿里巴巴的dubbo注解 @Service public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "hello@@"+name; } }
服務消費者
第一步、導入坐標
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> </dependencies>
第二步、配置服務消費者的Spring配置文件applicationContext-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:aop="http://www.springframework.org/schema/aop" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--開啟包掃描,用來掃描所有的Spring注解--> <context:component-scan base-package="com.alibaba.web.controller.consumer"/> <!--開啟MVC注解,使所有的MVC注解生效--> <mvc:annotation-driven/> <!--為服務消費者在向注冊中心訂閱服務時起個名字--> <dubbo:application name="dubbodemo_consumer"/> <!--連接到zookeeper注冊中心--> <dubbo:registry address="zookeeper://127.0.0.1" port="2181"/> <!--開啟包掃描,使dubbo的注解生效,讓當前的被注解的類交給dubbo管理--> <dubbo:annotation package="com.alibaba.web.controller.consumer"/> </beans>
第三步、在web.xml配置前端控制器,加載spring的配置信息
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-*.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
第四步、編寫控制器
import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.provider.HelloService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { //此處使用阿里巴巴的注解進行注入 @Reference HelloService helloService; @RequestMapping("/hello") public void hello(String name) { String result = helloService.sayHello(name); System.out.println(result); } }
注意:服務提供者的接口必須存在於服務消費者的目錄中,並且該接口的路徑與服務提供者的路徑必須保持一致,一模一樣。
Dubbo相關配置說明
包掃描
服務提供者和服務消費者都需要配置,表示包掃描,作用是掃描指定包(包括子包)下的類
<dubbo:annotation package="cn.itcast.service" />
如果不使用包掃描,也可以通過如下配置的方式來發布服務
<bean id="helloService" class="cn.itcast.service.impl.HelloServiceImpl" /> <dubbo:service interface="cn.itcast.HelloService" ref="helloService" />
作為服務消費者,可以通過如下配置來引用服務:
<!-- 生成遠程服務代理,可以和本地bean一樣使用helloService --> <dubbo:reference id="helloService" interface="cn.itcast.HelloService" />
上面這種方式發布和引用服務,一個配置項(dubbo:service、dubbo:reference)只能發布或者引用一個服務,如果有多個服務,這種方式就比較繁瑣了。推薦使用包掃描方式。
協議
<dubbo:protocol name="dubbo" port="20880"/>
一般在服務提供者一方配置,可以指定使用的協議名稱和端口號。
其中Dubbo支持的協議有:dubbo、rmi、hessian、http、webservice、rest、redis等。
推薦使用的是dubbo協議。
dubbo 協議采用單一長連接和 NIO 異步通訊,適合於小數據量大並發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況。不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低。
也可以在同一個工程中配置多個協議,不同服務可以使用不同的協議
啟動時檢查
<dubbo:consumer check="false"/>
上面這個配置需要配置在服務消費者一方,如果不配置默認check值為true。Dubbo 缺省會在啟動時檢查依賴的服務是否可用,不可用時會拋出異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題。可以通過將check值改為false來關閉檢查。
建議在開發階段將check值設置為false,在生產環境下改為true。
Dubbo管理控制台
我們在開發時,需要知道Zookeeper注冊中心都注冊了哪些服務,有哪些消費者來消費這些服務。我們可以通過部署一個管理中心來實現。其實管理中心就是一個web應用,部署到tomcat即可
安裝
安裝步驟:
(1)將資料中的dubbo-admin-2.6.0.war文件復制到tomcat的webapps目錄下
(2)啟動tomcat,此war文件會自動解壓
(3)修改WEB-INF下的dubbo.properties文件,注意dubbo.registry.address對應的值需要對應當前使用的Zookeeper的ip地址和端口號
dubbo.registry.address=zookeeper://Ip:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
(4)重啟tomcat
使用
操作步驟:
訪問http://localhost:8080/dubbo-admin-2.6.0/,輸入用戶名(root)和密碼(root)

