Dubbo+Zookeeper微服務架構
- 1、Apache Dubbo概述
- 1.1、Dubbo簡介
- 1.2、Dubbo的服務架構
- 2、服務注冊中心 Zookeeper
- 2.1、ZooKeeper介紹
- 2.2、ZooKeeper安裝
- 2.3、啟動 ZooKeeper
- 3、ZooKeeper快速入門
- 3.1、服務提供方
- 3.2、服務消費方
- 3.3、問題思考
- 4、 Dubbo管理控制臺
- 4.1、安裝
- 4.2、使用
- 5、 Dubbo相關配置
- 5.1、包掃描
- 5.2、Dubbo 協議
- 5.3、負載均衡
- 5.4、 Dubbo無法發布被事務代理的服務
1、Apache Dubbo概述
1.1、Dubbo簡介
? **Apache Dubbo **是一款高性能的 Java RPC 框架,其前身是阿里巴巴公司開源的、輕量級的開源 Java RPC 框架,可以和 Spring 框架無縫集成,2018年阿里巴巴把這個框架捐獻給了apache基金,此框架的使用比 Spring Cloud 微服務的框架使用較為簡單,只需要表寫相應的服務提供和服務消費的代碼即可,中央服務配置可由 ZooKeeper 進行服務的注冊管理,只需要相應的服務進行配置注冊,服務消費進行介面的抓取即可完成服務的遠程呼叫,
- 什么是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.2、Dubbo的服務架構
?Dubbo的服務架構圖如下所示:
- 各節點角色說明:
| 節點名 | 功能 |
|---|---|
| 提供者 | 暴露介面的提供方 |
| 容器 | 整個服務運行時的容器 |
| 注冊 | 服務注冊與發現的注冊中心 |
| 消費者 | 呼叫遠程服務的消費方 |
| 監控 | 統計服務呼叫次數呼叫時間的監控中心 |
- 服務的執行步驟:
- 服務容器負責啟動,加載,運行服務的介面提供者,
- 服務提供者在啟動時,向注冊中心注冊自己提供的服務,也就是注冊自己的介面地址,
- 服務消費者在啟動時,向注冊中心訂閱自己所需的服務,通過代理的方式直接定位到需要的介面實作物件,但是需要注意的是消費者必須有該介面才能進行代理,
- 注冊中心回傳服務提供者地址串列給消費者,如果有變更,注冊中心將基于長連接推送變更資料給消費者, 4
- 服務消費者,從提供者地址串列中,基于軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫,
- 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘發送一次統計資料到監控中心,
2、服務注冊中心 Zookeeper
? 通過前面的 Dubbo架構圖 可以看到,Registry(服務注冊中心)在整個架構中起著至關重要的作用,Dubbo官方推薦使用 Zookeeper 作為服務注冊中心,下面詳細講一下 Zookeeper 在服務器中的安裝以及相應的服務注冊和拉取配置,
2.1、ZooKeeper介紹
? Zookeeper 是 Apache Hadoop 的子專案,是一個樹型的目錄服務,支持變更推送,適合作為 Dubbo 服務的注冊中心,工業強度較高,可用于生產環境,并推薦使用,

?流程說明:
- 服務提供者(Provider)啟動時: 向 /dubbo/com.test.UserServiceBo/providers 目錄下寫入自己的 URL 地址
- 服務消費者(Consumer)啟動時: 訂閱 /dubbo/com.test.UserServiceBo/providers 目錄下的提供者 URL 地址,并向 /dubbo/com.test.UserServiceBo/consumers 目錄下寫入自己的 URL 地址
- 監控中心(Monitor)啟動時: 訂閱 /dubbo/com.test.UserServiceBo 目錄下的所有提供者和消費者 URL 地址
2.2、ZooKeeper安裝
? 下載地址:http://archive.apache.org/dist/zookeeper/ 下載完成后 zookeeper-3.4.6.tar.gz的壓縮文 件,
? 安裝步驟:
- 第一步:需要有安裝 JDK 的環境,
- 第二步:把
zookeeper的壓縮包上傳到 linux 系統, - 第三步:解壓縮壓縮包 tar -zxvf zookeeper-3.4.6.tar.gz -C /usr 路徑可以隨便定義,
- 第四步:進入
zookeeper-3.4.6目錄,創建data目錄,用于資料的存盤, - 第五步:進入
conf目錄 ,把zoo_sample.cfg改名為zoo.cfg,用于配置相關的資料資訊,也是啟動的組態檔,
2.3、啟動 ZooKeeper
? 進入 Zookeeper 的 bin 目錄,執行相應的檔案即可,
- 啟動服務命令: ./zkServer.sh start
- 停止服務命令: ./zkServer.sh stop
- 查看服務狀態: ./zkServer.sh status
- 客戶端連接: ./zkCli.sh
3、ZooKeeper快速入門
?Dubbo 作為一個RPC框架,其最核心的功能就是要實作跨網路的遠程呼叫,本小節就是要創建兩個應用,一個作為服務的提供方,一個作為服務的消費方,通過Dubbo來實作服務消費方遠程呼叫服務提供方的方法,
3.1、服務提供方
?創建一個簡單的 web 專案作為服務的提供者(由maven進行管理),
-
添加依賴:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.beordie</groupId> <artifactId>dubbo-normal</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>5.0.5.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> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> -
配置 web.xml 檔案
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<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>
- 創建服務介面
package com.beordie.service;
/**
* @Description
* @Date 2021/9/2 16:08
* @Created 30500
*/
public interface ServiceTest {
public String get(String name);
}
- 創建服務實作類
package com.beordie.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.beordie.service.ServiceTest;
/**
* @Description
* @Date 2021/9/2 16:09
* @Created 30500
*/
@Service
public class serviceImpl implements ServiceTest {
@Override
public String get(String name) {
return "你好" + name;
}
}
注意:服務實作類上使用的 Service 注解是 Dubbo 提供的,用于對外發布服務 ,
- 創建web.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
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://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="provider"/>
<!-- 連接服務注冊中心zookeeper ip為zookeeper所在服務器的ip地址-->
<dubbo:registry address="zookeeper://192.168.55.129:2181"/>
<!-- 注冊 協議和port -->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
<!-- 掃描指定包,加入@Service注解的類會被發布為服務 -->
<dubbo:annotation package="com.beordie.service.impl" />
</beans>
-
啟動服務并在 ZooKeeper 中進行服務查看
啟動完服務后通過打開客戶端的命令打開
ZooKeeper的客戶端,然后通過指令ls /可查看到當前目錄下的檔案資訊,會發現存在一個Dubbo的檔案目錄,繼續對此目錄進行查看即可發現相應的服務注冊資訊,
| 
3.2、服務消費方
?同樣需要創建一個專案來進行服務的拉取,引入的依賴和提供方的類似,這里就直接復制即可,
- 配置 web.xml 檔案
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加載的組態檔 ,通過引數contextConfigLocation加載 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-
創建和提供方一致的服務介面
可以直接對介面進行復制,因為之后的服務抓取是通過動態代理的方式進行物件生成的,因此需要對應的介面物件,
-
撰寫Controlle對外暴露訪問介面
package com.beordie.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.beordie.service.ServiceTest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Description
* @Date 2021/9/2 17:05
* @Created 30500
*/
@Controller
@RequestMapping("/demo")
public class TeController {
// Dubbo 的遠程物件注入
@Reference
private ServiceTest serviceTest;
@RequestMapping("/hello")
@ResponseBody
public String getName(String name){
//遠程呼叫
String result = serviceTest.get(name);
System.out.println(result);
return result;
}
}
-
創建對應的啟動組態檔
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 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://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="dubbo-consumer"/> <!-- 連接服務注冊中心zookeeper ip為zookeeper所在服務器的ip地址--> <dubbo:registry address="zookeeper://192.168.55.129:2181"/> <!-- 掃描的方式暴露介面 --> <dubbo:annotation package="com.beordie.controller"/> </beans> -
運行測驗
設定完畢后啟動專案,然后訪問相應地址,即可抓取到正確的服務結果,
3.3、問題思考
- 思考一:上面的Dubbo入門案例中我們是將HelloService介面從服務提供者工程 (dubbo_provider)復制到服務消費者工程(dubbo_consumer)中,這種做法是否合適?還有沒有更好的方式?
答:這種做法顯然是不好的,同一個介面被復制了兩份,不利于后期維護,更好的方式是單獨創建一個 maven工程,將此介面創建在這個maven工程中,需要依賴此介面的工程只需要在自己工程的 pom.xml檔案中引入maven坐標即可,- 思考二:在服務消費者工程(dubbo_consumer)中只是參考了介面,并沒有提供實作類,Dubbo是如何做到遠程呼叫的?
答:Dubbo底層是基于代理技術為介面創建代理物件,遠程呼叫是通過此代理物件完成的,可以通過開發工具的debug功能查看此代理物件的內部結構,另外,Dubbo實作網路傳輸底層是基于Netty框架完成的,- 思考三:上面的Dubbo入門案例中我們使用Zookeeper作為服務注冊中心,服務提供者需要將自己的服務資訊注冊到Zookeeper,服務消費者需要從Zookeeper訂閱自己所需要的服務,此時Zookeeper服務就變得非常重要了,那如何防止Zookeeper單點故障呢?
答:Zookeeper其實是支持集群模式的,可以配置Zookeeper集群來達到Zookeeper服務的高可用,防 止出現單點故障,
4、 Dubbo管理控制臺
?我們在開發時,需要知道 Zookeeper 注冊中心都注冊了哪些服務,有哪些消費者來消費這些服務,我們可以通過部署一個管理中心來實作,其實管理中心就是一個web應用,部署到tomcat即可,
4.1、安裝
?只需要下載對應的 war 到本地的tomcat,然后啟動服務即可,
- 需要修改WEB-INF下的dubbo.properties檔案,注意dubbo.registry.address對應的值需要對應當前使用的Zookeeper的ip地址和埠號 dubbo.registry.address=zookeeper://192.168.55.129:2181
4.2、使用
? 訪問 http://localhost:8080/dubbo-admin-2.6.0/,輸入用戶名(root)和密碼(root) 即可查看網站,相關的服務資訊都可以在這里進行查看,
5、 Dubbo相關配置
5.1、包掃描
<dubbo:annotation package="com.beordie.service" />
服務提供者和服務消費者都需要配置,表示包掃描,作用是掃描指定包(包括子包)下的類,提供者掃描服務所在的包,消費者掃描控制器所在的包,
- 如果不使用包掃描,也可以通過如下配置的方式來發布服務:
<bean id="serviceImpl" class="com.beordie.service.impl.serviceImpl" />
<dubbo:service interface="com.beordie.service.Service" ref="serviceImpl" />
- 作為服務消費者,可以通過如下配置來參考服務:
<!-- 生成遠程服務代理,可以和本地bean一樣使用Service -->
<dubbo:reference id="serviceTest" interface="com.beordie.ServiceTest" />
? 上面這種方式發布和參考服務,一個配置項(dubbo:service、dubbo:reference)只能發布或者參考一個服務,如果有多個服務,這種方式就比較繁瑣了,推薦使用包掃描方式,
5.2、Dubbo 協議
?一般在服務提供者一方配置,可以指定使用的協議名稱和埠號,
<dubbo:protocol name="dubbo" port="20880"/>
-
Dubbo支持的 協議 有:
dubbo、rmi、hessian、http、webservice、rest、redis等, -
推薦使用的是dubbo協議, dubbo 協議采用單一長連接和 NIO 異步通訊,適合于小資料量大并發的服務呼叫,以及服務消費者機器數遠大于服務提供者機器數的情況,不適合傳送大資料量的服務,比如傳檔案,傳視頻等,除非請求量很低,
-
也可以在同一個工程中配置多個協議,不同服務可以使用不同的協議,例如:
<!-- 多協議配置 --> <dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="rmi" port="1099" /> <!-- 使用dubbo協議暴露服務 --> <dubbo:service interface="com.beordie.HelloService" ref="helloService" protocol="dubbo" /> <!-- 使用rmi協議暴露服務 --> <dubbo:service interface="com.beordie.DemoService" ref="demoService" protocol="rmi" />
5.3、負載均衡
?負載均衡(Load Balance):其實就是將請求分攤到多個操作單元上進行執行,從而共同完成作業任 務,
-
在集群負載均衡時,Dubbo 提供了多種均衡策略(包括隨機、輪詢、最少活躍呼叫數、一致性 Hash),預設為random隨機呼叫,
-
配置負載均衡策略,既可以在服務提供者一方配置,也可以在服務消費者一方配置,如下:
// 呼叫方配置 @Reference(check = false,loadbalance = "random")// 服務方配置 @Service(loadbalance = "random")
5.4、 Dubbo無法發布被事務代理的服務
-
問題
因為提供的是服務層的介面,在涉及資料庫的
ACID時就會添加事務管理,但是這樣服務將不會在 ,ZooKeeper中進行注冊,服務的消費端也就不會拿到對應的代理物件,也會報沒有可用的服務提供者的錯誤, -
原因
加入事務注解后,Spring會為此類基于 JDK動態代理技術 創建代理物件,創建的代理物件完整類名為
com.sun.proxy.$Proxy35,導致Dubbo在進行包匹配時沒有成功(因為我們在發布服務時掃描的包為com.beordie.service),所以后面真正發布服務的代碼沒有執行, -
解決
使用
cglib代理方式為Service類創建代理物件,并指定發布的介面 @Service(interfaceClass = HelloService.class)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297103.html
標籤:其他

