天天看點

SpringBoot - 分布式 Dubbo + Zookeeper

一、基礎知識

1)分布式理論

(1)什麼是分布式系統?

分布式系統是若幹獨立計算機的集合,這些計算機對于使用者來說就像單個相關系統。

分布式系統由一組通過網絡進行通信、為了完成共同的任務而協調工作的計算機節點組成的系統。分布式系統的出現是為了用廉價的、普通的機器完成單個計算機無法完成的計算、存儲任務。其目的是 利用更多的機器,處理更多的資料。

分布式系統(distributed system)是建立在網絡之上的軟體系統。

首先需要明确的是,隻有單個節點的處理能力無法滿足日益增長的計算、存儲任務的時候,且硬體的提升(加記憶體、加磁盤、使用更好的CPU)高昂到得不償失的時候,應用程式也不能進一步優化的時候,我們才需要考慮分布式系統。因為,分布式系統要解決的問題本身就和單機系統一樣,而由于分布式系統多節點、通過網絡的拓撲結構,會引入很多單機系統沒有的問題,為了解決這些問題又會引入更多的機制、協定,帶來更多的問題...

(2)Dubbo文檔

随着網際網路的發展。網站應用的規模不斷擴大,正常的垂直應用架構已無法應對,分布式服務架構以及流動計算架構勢在必行。急需一個治理系統確定架構有條不絮的演進。

SpringBoot - 分布式 Dubbo + Zookeeper

● 單一應用架構

當網站流量很小時,隻需一個應用,将所有功能都部署在一起,以減少部署節點和成本。此時,用于簡化增删改查工作量的資料通路架構(ORM)是關鍵。

SpringBoot - 分布式 Dubbo + Zookeeper

适用于小型網站,小型管理系統,将所有功能部署到一個功能裡,簡單易用。

缺點:

① 性能擴充比較難
② 協同開發問題
③ 不利于更新維護      

● 垂直應用架構

當通路量逐漸增大,單一應用增加機器帶來的加速度越來越小,提升效率的方法之一是将應用拆成互不相幹的幾個應用,以提升效率。此時,用于加速前端頁面開發的Web架構(MVC)是關鍵。

SpringBoot - 分布式 Dubbo + Zookeeper

通過切分業務來實作各個子產品獨立部署,降低了維護的部署難度,團隊各司其職更易管理,性能擴充也更友善,更有針對性。

缺點:公用子產品無法重複利用,開發性能的浪費

● 分布式服務架構

當垂直應用越來越多,應用之間互動不可避免,将核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。此時,用于提高業務複用及整合的 分布式服務架構(RPC)是關鍵。

SpringBoot - 分布式 Dubbo + Zookeeper

● 流動計算架構

當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基于通路壓力實時管理叢集容量,提高叢集使用率。此時,用于 提高機器使用率的資源排程和治理中心(SOA)是關鍵 。

SpringBoot - 分布式 Dubbo + Zookeeper

2)RPC

(1)什麼是RPC?

PRC【Remote Procedure Call】是指遠端過程調用,是一種程序間的通信方式,它是一種技術思想,而不是規範。它允許程式調用另一個位址空間(通常是共享網絡的另一台機器上)的過程或函數,而不是程式員顯式編碼這個遠端調用的細節。即程式員無論調用本地的還是遠端的函數,本質上編寫的調用代碼基本相同。

也就是所兩台伺服器A、B,一個應用部署在A伺服器上,想要調用B伺服器上應用提供的函數/方法,由于不在一個記憶體空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的資料。為什麼要RPC呢?就是無法在一個程序内,甚至一個計算機内通過本地調用的方式完成的需求,比如不同的系統間的通訊,甚至不同的組織間的通訊,由于計算能力需要橫向擴充,需要在多台機器自稱的叢集上部署應用。PRC就是要調用本地的函數一樣去調用遠端函數。

(2)RPC基本原理

SpringBoot - 分布式 Dubbo + Zookeeper

步驟解析:

SpringBoot - 分布式 Dubbo + Zookeeper

RPC的兩個核心子產品:通訊、序列化。

二、Dubbo

1)什麼是Dubbo?

Apache Dubbo 是一款高性能、輕量級的開源 Java RPC 架構,它提供了三大核心功能:面向接口的遠端方法調用,智能容錯和負載均衡,以及服務自動注冊和發現。

2)Dubbo架構

SpringBoot - 分布式 Dubbo + Zookeeper

● 節點角色說明:

① 服務提供者(Provider):暴露服務的服務提供方。服務提供者在啟動時,向注冊中心注冊自己提供的服務。

② 服務消費者(Consumer):調用遠端服務的服務消費方。服務消費者在啟動時,向注冊中心訂閱自己所需的服務,服務消費者,從提供者位址清單中,基于軟負載均衡算法。選一台提供者進行調用,如果調用失敗,再選一台調用。

③ 注冊中心(Registry):服務注冊與發現的注冊中心。注冊中心傳回服務提供者位址清單給消費者,如有變更,注冊中心将基于長連接配接推送變更資料給消費者。

④ 監控中心(Monitor):統計服務的調用次數和調用時間的監控中心。服務消費者和提供者,在記憶體中累計調用次數和調用時間,定時每分鐘發送一次統計資料到監控中心。

⑤ 服務運作容器(Container):

● 調用關系說明:

① 服務容器負責啟動,加載,運作服務提供者。

② 服務提供者在啟動時,向注冊中心注冊自己提供的服務。

③ 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。

④ 注冊中心傳回服務提供者位址清單給消費者,如果有變更,注冊中心将基于長連接配接推送變更資料給消費者。

⑤ 服務消費者,從提供者位址清單中,基于軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。

⑥ 服務消費者和提供者,在記憶體中累計調用次數和調用時間,定時每分鐘發送一次統計資料到監控中心。

3)Dubbo環境搭建

Dubbo 官方推薦使用 Zookeeper 注冊中心。

(1)Window 下載下傳安裝 zookeeper

① 下載下傳 zookeeper (這裡下載下傳3.4.14)

② 解壓到指定的安裝目錄

③ 運作 /bin/zkServer.cmd ,初次運作可能會報錯,沒有 zoo.cfg 配置檔案;

可能會遇到問題:閃退!

解決方案:編輯 zkServer.cmd 檔案末尾添加 pause。這樣運作出錯就不會閃退了,會提示錯誤資訊,友善查找原因。

SpringBoot - 分布式 Dubbo + Zookeeper
SpringBoot - 分布式 Dubbo + Zookeeper

④ 修改 zoo.cfg 配置檔案

将 conf 檔案夾下面的 zoo_sample.cdg 複制一份改名為 zoo.cfg 即可。

注意幾個重要位置:

 dataDir = ./ :臨時資料存儲的目錄(可寫相對路徑)

 clientPort = 2181 :zookeeper的預設端口

修改完成後再次啟動zookeeper

SpringBoot - 分布式 Dubbo + Zookeeper

⑤ 使用 zkCli.cmd 測試

ls /:列出zookeeper根下儲存的所有節點

SpringBoot - 分布式 Dubbo + Zookeeper

create -e /hello 777:建立一個hello節點,值為123

SpringBoot - 分布式 Dubbo + Zookeeper

get /hello:擷取/hello節點的值

SpringBoot - 分布式 Dubbo + Zookeeper

再次檢視zookeeper根節點,發現多了hello

SpringBoot - 分布式 Dubbo + Zookeeper

(2)Window 安裝 dubbo-admin

dubbo 本身并不是一個服務軟體。它其實是一個 jar 包,能夠幫你的 java 程式連接配接到 zookeeper ,并利用 zookeeper 消費、提供服務。

但是為了讓使用者更好的管理監控衆多的 Dubbo 服務,官方提供了一個可視化的監控程式 dubbo-admin ,不過這個監控即使 不安裝也不影響使用 。

① 下載下傳 dubbo-admin

② 解壓到指定安裝目錄

修改 dubbo-admin\src\main\resources\application.properties 指定Zookeeper位址

SpringBoot - 分布式 Dubbo + Zookeeper

③ 在項目目錄下打包 dubbo-admin

mvn clean package -Dmaven.test.skip=true      

第一次打包可能比較慢,耐心等待...

SpringBoot - 分布式 Dubbo + Zookeeper

④ 執行 dubbo-admin\target 下的 dubbo-admin-0.0.1-SNAPSHOT.jar

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar      

【注意:Zookeeper的服務一定要打開】

執行完畢,通路 localhost:7001/,這時候我們需要輸入登入賬戶和密碼,預設都為 root

SpringBoot - 分布式 Dubbo + Zookeeper

三、SpringBoot整合Dubbo+Zookeeper

整合測試前確定 Zookeeper 服務已開啟!

1)Provider - 服務提供者

① 引入依賴:dubbo和zkclient相關依賴

<!-- 導入依賴 Dubbo + Zookeeper -->
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>
<!-- 日志沖突 -->
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.14</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>      

② 配置properties檔案:配置 dubbo 掃描包和注冊中心位址

# 服務名稱
dubbo.application.name=provider-service
# 注冊中心位址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 聲明需要暴露的服務的接口 - 該包下的接口若有使用dubbo的@Service注解的接口實作則會暴露為dubbo服務
dubbo.scan.base-packages=com.cyan.service      

③ 服務提供:使用 @Service 注解注冊服務

在服務提供主要包括兩部分,一個是暴露服務,一個是服務實作

- 暴露服務:即我們平常開發中所使用的的接口,這裡我們建立一個 TicketService 的接口

public interface TicketService {
    public String getTicket();
}      

- 服務實作:與我們平常的服務一樣,對接口進行實作,比較特别的是,我們這裡需要使用到 Dubbo 提供的 @Service 注解

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

@Component  //将實作納入IOC
@Service    //将服務釋出出去
public class TicketServiceImpl implements TicketService {

    @Override
    public String getTicket() {
        return "《Java分布式》";
    }
}      

● 檢視提供的服務網:使用 dubbo-admin 檢視是否将服務釋出出去

SpringBoot - 分布式 Dubbo + Zookeeper

2)Consumer - 服務消費者

① 引入依賴:與服務提供者的依賴一緻

SpringBoot - 分布式 Dubbo + Zookeeper
SpringBoot - 分布式 Dubbo + Zookeeper
<!-- 導入依賴 Dubbo+Zookeeper -->
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>
<!-- 日志沖突 -->
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.14</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>      

View Code

② 配置檔案:配置服務名、注冊中心位址

# 暴露消費者名字
dubbo.application.name=consumer-service
# 注冊中心位址 - zookeeper伺服器位址和端口
dubbo.registry.address=zookeeper://127.0.0.1:2181      

③ 服務實作:使用 @Reference 注解,從遠端注入服務

- 建立與服務提供者一樣的接口:注意包名和接口名等要完全一緻,這是因為dubbo識别服務靠的是包名,而不像SpringCloud靠的是應用名和Http接口名

SpringBoot - 分布式 Dubbo + Zookeeper

- 使用 dubbo 提供的 @Reference 注解訂閱遠端服務

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // 在服務消費者中使用dubbo訂閱遠端服務:使用dubbo提供的@Reference注解
    @Reference
    TicketService ticketService;

    public void getTicket() {
        String ticket = ticketService.getTicket();
        System.out.println(ticket);
    }

}      

④ Junit測試:確定Zookeeper服務已開啟,然後啟動服務提供者,再在服務消費者中調用getTikcet()

@SpringBootTest
class ConsumerServiceApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void contextLoads() {
        userService.getTicket();
    }
}      

測試結果:

SpringBoot - 分布式 Dubbo + Zookeeper