天天看點

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

    • 本文目的
      • 階段一 基于本地調用的dubbo架構
      • 階段二 基于Zookeeper注冊中心的dubbo架構
    • 相關資料
    • 基于本地調用的dubbo代碼架構
    • 基于注冊中心的dubbo代碼架構

本文目的

一旦提到某某架構,可能很多人的第一感覺就是:這個東西很複雜,很難實際操作。其實不然,隻要獲得對的資料,搭建自己的dubbo架構并不是一件難事,不過由于曆史原因,很多資料過于老舊,引用的文檔也已經被廢棄,是以從零搭建自己的Dubbo架構,可能會遇到不少問題,如果不是老司機,很容易翻車中途放棄。

本文的目的就是一步一步帶您搭建出一個可用于生産環境的Dubbo代碼架構。這個過程,會分三個步驟完成。

階段一 基于本地調用的dubbo架構

改造官方Demo,精簡demo項目,使得工程最後僅包括一個 service-provider,和 service-consumer 。Provider是服務提供者,通過開放Http端口,等待請求到來。Consumer 是服務調用着,通過Http請求調用服務。這個階段,調用僅僅是本地調用,我們隻有一個服務提供者,和一個服務消費者,消費者通過指定本地URL的方式調用提供者。

階段二 基于Zookeeper注冊中心的dubbo架構

但是dubbo架構不僅僅調用本地服務,它更強大的是,利用注冊中心,調用遠端服務,同時提供一系列的機制,實作服務發現,負載均衡等。注冊中心的實作有很多中,本文采用Zookeeper作為注冊中心,注冊中心的工作原理大概可以用下面的時序圖描述:

該圖隻是最簡單的情況,真實場景中,會有多個服務提供者,也會有多個消費者,組成交叉式的調用關系。

然後,我們會安裝服務監控器,dubbo-monitor-simple, 有了它,所有的服務提供者和消費者的狀态,都可以一覽無遺。

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

monitor還有會把調用統計資料,用各種豐富的表格展示出來,真實屌炸天的東西。

好吧,那就開始吧!

相關資料

唯一官網:dubbo.io

源代碼:https://github.com/alibaba/dubbo

基于本地調用的dubbo代碼架構

1. GitHub 上Clone最新代碼:

cd ~
git clone https://github.com/alibaba/dubbo.git dubbo
git checkout master
or: git checkout -b dubbo-
           

2. 導入demo工程

2.1拷貝項目

如果按照官方例子,導入所有的工程,并不是很好的方案,在實際生産環境下,我們也不希望維護那麼多類庫工程。是以這裡我隻拷貝demo工程到另外一個目錄下。

cp -R ./dubbo/dubbo-demo ./  
cd dubbo-demo
           
這裡涉及到的目錄結構如下 dubbo-demo
dubbo-demo-api
dubbo-demo-provider
dubbo-demo-consumer
pom.xml

其中api工程聲明了 Service 提供的接口,provider 實作了 api 接口,并對外開放http端口,consumer依賴 api 工程,但是不會直接依賴provider工程。 這種可以讓消費者僅僅依賴api工程,而不需要對provider工程的依賴,也是松耦合的經典。

2.2修改POM檔案

在這裡我們會修改 dubbo-demo 根pom,去掉它的parent設定,讓它成為獨立的工程,同時配置它所依賴的項目。

簡而言之,就是去掉

<parent>
</parent>
           

中的内容,然後修改後的pom頭部如下:

<groupId>com.alibaba</groupId>
 <version>2.5.4-SNAPSHOT</version>
 <artifactId>dubbo-demo</artifactId>
 <packaging>pom</packaging>
 <name>${project.artifactId}</name>
           

修改相關依賴,核心思想就是把dubbo源代碼中根pom的相關依賴複制過來,并且最重要的,加上

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
</dependency>
           

通過這樣的方式,你已經把dubbo通過maven依賴的方式放在工程裡了,完全不需要用引入官方工程的方式做項目依賴。

在Eclispe中(筆者使用的是,STS),File - Import - Exisiting Maven Projects

的方式導入工程。

3. 修複依賴工程不存在的錯誤

剛剛導入的consumer 和 provider工程可能會有如下錯誤:

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

可以在項目依賴中,删除這些項目,其實他們已經不需要了。

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

4. 導出conf目錄

對于consumer 和 provider工程,有一個很重要的檔案,dubbo.properties, 預設情況下,dubbo架構會加載這個檔案,這個檔案打包在

src/main/assembly/conf
           

需要手動導出這個目錄到Classpath,否則程式運作找不到dubbo配置檔案。

5. 修改 dubbo.properties

該檔案中,定義了注冊中心,是一個不生效的位址,是以要把它禁止掉。這個檔案的配置十分重要,後續出現的相關配置會再次提到這個檔案,可以參考dubbo.io 擷取更多關于配置的較長的描述。

#dubbo.registry.address=multicast://224.5.6.7:1234
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.registry.address=N/A
           

注釋掉那些預設的注冊位址,把它改成N/A. 在測試環境中,也需要修改這個檔案

6. 運作DemoProvider.main

如果工程沒有其他問題,可以啟動服務。如果成功會在Console中列印

[2016-09-13 23:14:37] Dubbo service server started!
           

7. 運作 Consumer.main

在運作支援有一件事,要處理,否則會出現無法找到服務。

打開檔案:

會看到一行引用聲明:

<dubbo:reference id="demoService" interface=
    "com.alibaba.dubbo.demo.DemoService"/>
           

在Consumer工程中,正是用這樣聲明的方式定義所需的微服務的,它通過ProxyFactoryBean的方式,封裝了内部真正的實作。這個細節後面會深入探讨。

這裡的問題是,我們沒有啟動注冊中心,是以會出現服務不能被調用的異常。是以這裡,在聲明中,指定我們要調用的服務URL,修改成如下:

<dubbo:reference id="demoService" 
    url="dubbo://localhost:20880/com.alibaba.dubbo.demo.DemoService"
    interhljs-string">"com.alibaba.dubbo.demo.DemoService" />
           

然後啟動:DemoConsumer.main

如果一切順利,會出現如下輸出。

[-- ::] Dubbo service server started!
[::] Hello world0, request from consumer: /:
[::] Hello world1, request from consumer: /:
[::] Hello world2, request from consumer: /:
           

到這裡,一份完全基于本地調用,禁用了注冊中心的微服務程式架構就建立起來了。其實在開發環境下,我們完全可以僅僅使用基于本地的調用,在測試環節和生産環節,可以通過替換配置檔案的方式采用注冊中心的方式部署。 本地調用方式更友善調試。采用注冊中心的方式開發,如果采用統一注冊中心,程式員A做本地開發,可能會調用其他人的程式,如果每人用不同的注冊中心,這樣會提高開發成本,畢竟開發過程中,我隻希望我的 Consumer 調用我本地的 Provider.

基于注冊中心的dubbo代碼架構

關于官方給出的三種注冊中心安裝方法, 本文将使用Zookeeper作為 registry center.

1. 安裝 Zookeeper

cd ~
wget http://apache.fayea.com/zookeeper/zookeeper-/zookeeper-.tar.gz
tar zxvf zookeeper-.tar.gz
cd zookeeper-/conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
- edit: dataDir=/Users/Vic/data/zookeeper
cd ..

[~/zookeeper-]$ ./bin/zkServer.sh start                                                                                   
ZooKeeper JMX enabled by default
Using config: /Users/Vic/zookeeper-/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
           

2. 配置 Zookeeper 注冊中心

修改所有的 dubbo.properties, 之前我們使用 N/A 禁用了注冊中心,現在我們使用zookeeper的方式。

dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=N/A
           

再次啟動服務,這次Console輸出的log有很多不同,說明已經是通過Zookeeper注冊中心了。

[// ::: CST] main  INFO zookeeper.ZooKeeper: Client environment:os.arch=x86_64
[// ::: CST] main  INFO zookeeper.ZooKeeper: Client environment:os.version=
[// ::: CST] main  INFO zookeeper.ZooKeeper: Client environment:user.name=Vic
[// ::: CST] main  INFO zookeeper.ZooKeeper: Client environment:user.home=/Users/Vic
[// ::: CST] main  INFO zookeeper.ZooKeeper: Client environment:user.dir=/Users/Vic/dubbo/dubbo-demo/dubbo-demo-provider
[// ::: CST] main  INFO zookeeper.ZooKeeper: Initiating client connection, connectString=: sessionTimeout= watcher=org.I0Itec.zkclient.ZkClient@1c32386d
[// ::: CST] main-SendThread()  INFO zookeeper.ClientCnxn: Opening socket connection to server /:
[// ::: CST] main-SendThread(localhost:)  INFO zookeeper.ClientCnxn: Socket connection established to localhost/:, initiating session
[// ::: CST] main-SendThread(localhost:)  INFO zookeeper.ClientCnxn: Session establishment complete on server localhost/:, sessionid = , negotiated timeout = 
[// ::: CST] main-EventThread  INFO zkclient.ZkClient: zookeeper state changed (SyncConnected)
[// ::: CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Register: dubbo://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=, dubbo version: , current host: 
[// ::: CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Subscribe: provider://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=, dubbo version: , current host: 
[// ::: CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Notify urls for subscribe url provider://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=, urls: [empty://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=], dubbo version: , current host: 
[// ::: CST] main  INFO container.Main:  [DUBBO] Dubbo SpringContainer started!, dubbo version: , current host: 
[-- ::] Dubbo service server started!
           

同樣的方式修改consumer工程的 dubbo 配置,然後我們啟動consumer的main.

不過在此之前,我們是調用的本地服務,指明了服務的URL,這裡我們要把這個指定去掉,通過注冊中心找到服務。

是以修改 service 引用如下:

<dubbo:reference id="demoService" 
    interhljs-string">"com.alibaba.dubbo.demo.DemoService" />
           

啟動DemoConsumer.main

[// ::: CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Notify urls for subscribe url provider://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=, urls: [empty://:/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=&interhljs-keyword">com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=&side=provider&timestamp=], dubbo version: , current host: 
[// ::: CST] main  INFO container.Main:  [DUBBO] Dubbo SpringContainer started!, dubbo version: , current host: 
[-- ::] Dubbo service server started!
[::] Hello world0, request from consumer: /:
           

其實,如果對zookeeper的原理少有了解的話,可以進入 zkclient檢視目前節點.

ls /dubbo/*.DemoService/providers
[dubbo%3A%2F%2F10..%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26loadbalance%3Droundrobin%26methods%3DsayHello%26owner%3Dwilliam%26pid%3D11433%26side%3Dprovider%26timestamp%3D1473829023222]
           

其實服務的Provider定義,就是在zookeeper節點的資料上。

3. 配置監控中心

當服務的提供者有很多,而消費者也有很多的時候,管理這些服務會十分棘手,是以官方提供了一個Monitor項目,通過配置,啟動後,可以在浏覽器中,檢視服務提供者和消費者的所有狀态。

可以使用 mvn 在 dubbo 根目錄方式執行 install 的方式生産 dubbo-monitor-simple. 然後解壓。

cd ./dubbo-monitor-simple-/conf
edit dubbo.properties

dubbo.registry.address=zookeeper://:
dubbo.jetty.port= //配置通路端口

../bin/start.sh 
           

啟動後,可以通過 127.0.0.1:8088 直接通路監控中心。

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

裡面也可以查詢所有服務調用的狀态,并且提供圖表的方式

深入了解Java SOA 架構Dubbo系列—— 第二回 搭建dubbo-demo環境

到這裡,dubbo-demo 的代碼架構就搭建完成了。運作程式可以使用官方打包的方式,在部署的時候更為友善。

接下來,在後續的文章裡,筆者會通過閱讀源代碼的方式,分析dubbo核心的實作原理。