分散式架構與Dubbo基礎入門與實踐
【1】分散式系統
① 什麼是分散式系統
《分散式系統原理與範型》定義:“分散式系統是若干獨立計算機的集合,這些計算機對於使用者來說就像單個相關係統”。
分散式系統(distributed system)是建立在網路之上的軟體系統。
隨著網際網路的發展,網站應用的規模不斷擴大,常規的垂直應用架構已無法應對,分散式服務架構以及流動計算架構勢在必行,亟需一個治理系統確保架構有條不紊的演進。
② 架構發展演變
如下圖所示:
- 單一應用架構
當網站流量很小時,只需一個應用,將所有功能都部署在一起,以減少部署節點和成本。此時,用於簡化增刪改查工作量的資料訪問框架(ORM)是關鍵。
適用於小型網站,小型管理系統,將所有功能都部署到一個功能裡,簡單易用。
缺點: 1、效能擴充套件比較難 ;2、協同開發問題; 3、不利於升級維護。
- 垂直應用架構
當訪問量逐漸增大,單一應用增加機器帶來的加速度越來越小,將應用拆成互不相干的幾個應用,以提升效率。此時,用於加速前端頁面開發的Web框架(MVC)是關鍵。
通過切分業務來實現各個模組獨立部署,降低了維護和部署的難度,團隊各司其職更易管理,效能擴充套件也更方便,更有針對性。
缺點: 公用模組無法重複利用,開發性的浪費。
- 分散式服務架構
當垂直應用越來越多,應用之間互動不可避免,將核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。此時,用於提高業務複用及整合的分散式服務框架(RPC)是關鍵。
- 流動計算架構
當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基於訪問壓力實時管理叢集容量,提高叢集利用率。此時,用於提高機器利用率的資源排程和治理中心(SOA)[ Service Oriented Architecture]是關鍵。
即,通常分散式應用就是面向服務的分散式架構。
③ RPC
- 什麼叫RPC
RPC(Remote Procedure Call)是指遠端過程呼叫,是一種程序間通訊方式,他是一種技術的思想,而不是規範。它允許程式呼叫另一個地址空間(通常是共享網路的另一臺機器上)的過程或函式,而不用程式設計師顯式編碼這個遠端呼叫的細節。即程式設計師無論是呼叫本地的還是遠端的函式,本質上編寫的呼叫程式碼基本相同。
- RPC基本原理
時序圖如下:
可以發現RPC兩個核心模組:通訊和序列化。
常見的RPC框架有:Dubbo、GRPC(谷歌)、Thrift(Facebook)、HSF(High Speed Service Framework 阿里)、JSF(京東)及Motan(新浪)。
【2】Dubbo
Apache Dubbo (incubating) 是一款高效能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向介面的遠端方法呼叫,智慧容錯和負載均衡,以及服務自動註冊和發現。
官網地址:http://dubbo.apache.org/
官網開發文件:http://dubbo.apache.org/zh-cn/docs/user/preface/
Dubbo的官方使用者文件提供了很詳細的使用說明與例項,遇到問題請一定參考官網文件!
① 結構示意圖
如下所示(012345表示執行順序,實現表示同步,虛線表示非同步):
特性如下:
- 面向介面代理的高效能RPC呼叫:提供高效能的基於代理的遠端呼叫能力,服務以介面為粒度,為開發者遮蔽遠端呼叫底層細節。
- 智慧負載均衡:內建多種負載均衡策略,智慧感知下游節點健康狀況,顯著減少呼叫延遲,提高系統吞吐量。
- 服務自動註冊與發現:支援多種註冊中心服務,服務例項上下線實時感知。
- 高度可擴充套件能力:遵循微核心+外掛的設計原則,所有核心能力如Protocol、Transport、Serialization被設計為擴充套件點,平等對待內建實現和第三方實現。
- 執行期流量排程:內建條件、指令碼等路由策略,通過配置不同的路由規則,輕鬆實現灰度釋出,同機房優先等功能。
- 視覺化的服務治理與運維:提供豐富服務治理、運維工具–隨時查詢服務元資料、服務健康狀態及呼叫統計,實時下發路由策略、調整配置引數。
② 幾個概念
服務提供者(Provider):暴露服務的服務提供方,服務提供者在啟動時,向註冊中心註冊自己提供的服務。
服務消費者(Consumer): 呼叫遠端服務的服務消費方,服務消費者在啟動時,向註冊中心訂閱自己所需的服務。服務消費者從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
註冊中心(Registry):註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
監控中心(Monitor):服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。
③ 呼叫關係說明
- 服務容器負責啟動,載入,執行服務提供者。
- 服務提供者在啟動時,向註冊中心註冊自己提供的服務。
- 服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
- 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
- 服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
- 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心(monitor)。
【3】Zookeeper註冊中心
Dubbo推薦使用Zookeeper作為註冊中心,當然Dubbo還支援其他作為註冊中心如Multicast 註冊中心,Redis註冊中心和Simple 註冊中心(本身就是一個普通的 Dubbo 服務)。
① 核心概念
Zookeeper 是 Apacahe Hadoop 的子專案,是一個樹型的目錄服務,支援變更推送,適合作為 Dubbo 服務的註冊中心,工業強度較高,可用於生產環境,並推薦使用。
官網地址:http://zookeeper.apache.org/
下載地址:https://archive.apache.org/dist/zookeeper/
② 流程說明:
- 服務提供者啟動時: 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
- 服務消費者啟動時: 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址。並向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
- 監控中心啟動時: 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費者 URL 地址。
③ 支援以下功能:
- 當提供者出現斷電等異常停機時,註冊中心能自動刪除提供者資訊;
- 當註冊中心重啟時,能自動恢復註冊資料,以及訂閱請求;
- 當會話過期時,能自動恢復註冊資料,以及訂閱請求;
- 當設定
<dubbo:registry check="false" />
時,記錄失敗註冊和訂閱請求,後臺定時重試; - 可通過
<dubbo:registry username="admin" password="1234" />
設定 zookeeper 登入資訊 - 可通過
<dubbo:registry group="dubbo" />
設定 zookeeper 的根節點,不設定將使用無根樹 - 支援
*
號萬用字元<dubbo:reference group="*" version="*" />
,可訂閱服務的所有分組和所有版本的提供者
更多詳情參考:Dubbo官網文件。
④ Windows下簡單搭建Zookeeper
將下載好的Zookeeper解壓到本地目錄下,並修改zoo.cfg配置檔案。
步驟如下:
-
解壓執行bin/zkServer.cmd ,初次執行會報錯,沒有zoo.cfg配置檔案;
-
將conf下的zoo_sample.cfg複製一份改名為zoo.cfg即可。
注意幾個重要位置:dataDir=./ 臨時資料儲存的目錄(可寫相對路徑) clientPort=2181 zookeeper的預設埠號
修改完成後再次啟動zookeeper
-
使用zkCli.cmd測試
ls /:列出zookeeper根下儲存的所有節點 create –e /myzookeeper 123:建立一個myzookeeper 節點,值為123 get /myzookeeper :獲取/myzookeeper 節點的值
服務端啟動示意圖如下:
客戶端測試如下:
【4】Windows下安裝Dubbo管理控制檯
dubbo本身並不是一個服務軟體。它其實就是一個jar(2.6之後為jar,之前為war需要在Tomcat下執行)包能夠幫你的java程式連線到zookeeper,並利用zookeeper消費、提供服務。所以你不用在Linux上啟動什麼dubbo服務。
但是為了讓使用者更好的管理監控眾多的dubbo服務,官方提供了一個視覺化的監控程式,不過這個監控即使不裝也不影響使用。
安裝步驟如下:
-
進入Dubbo的GitHub專案專案地址;
-
在最下方Dubbo eco system中點選進入Dubbo-OPS;
-
Download ZIP並解壓到本地
-
進入目錄,修改dubbo-admin配置
修改 src\main\resources\application.properties 指定zookeeper地址:dubbo.registry.address=zookeeper://127.0.0.1:2181
-
打包dubbo-admin
mvn clean package -Dmaven.test.skip=true
D:\Java_Tomcat_MySQL_jdk_zip\incubator-dubbo-ops-master\dubbo-admin>mvn clean package -Dmaven.test.skip=true //D:\Java_Tomcat_MySQL_jdk_zip\incubator-dubbo-ops-master 為專案路徑
打包成功如下圖所示:
- 使用命令執行jar
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
- 瀏覽器訪問(http://localhost:7001/)預設使用者名稱密碼root/root
Dubbo OPS專案與管理後臺jar包下載:點選下載。
【5】伺服器提供者/消費者專案簡單實踐
① 簡單需求
某個電商系統,訂單服務需要呼叫使用者服務獲取某個使用者的所有地址。
我們現在 需要建立兩個服務模組進行測試 :
模組 | 功能 |
---|---|
訂單服務模組 | 建立訂單等 |
使用者服務模組 | 查詢使用者地址等 |
測試預期結果:訂單服務模組在A伺服器,使用者服務模組在B伺服器,A可以遠端呼叫B的功能。
② 建立服務提供者和消費者
如下所示,建立兩個maven工程,分別表示provider和consumer:
那消費者如何呼叫provider的方法呢?這裡如果將provider依賴進consumer,則就成了單體應用。
或者可以這樣,將provider的bean和service拷貝到consumer中,如下所示:
該種方式專案例項參考SpringBoot整合Dubbo和Zookeeper。
這種方式是有問題:第一,暫且不說現在OrderServiceImpl呼叫UserService肯定失敗(實現類在另外一個專案);第二,UserService可能會被多個模組呼叫,原則上不應該每個呼叫UserService的模組都新增bean和UserService介面,添麻煩。而且也不符合Dubbo的服務化最佳實踐。
這裡將bean和介面抽離出來放在一個公共API專案中,provider和consumer依賴該專案。如下所示:
現在需要解決的問題就是遠端呼叫,OrderServiceImpl如何呼叫userService.getUserAddressList(userId);
。
③ Dubbo改造服務提供者
第一步:引入依賴:
<!-- 引入dubbo -->
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 註冊中心使用的是zookeeper,引入操作zookeeper的客戶端端 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
dubbo 2.6以前的版本引入zkclient操作zookeeper ,dubbo 2.6及以後的版本引入curator操作zookeeper。
下面兩個zk客戶端根據dubbo版本2選1即可:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
第二步,配置服務
在provider類路徑下新增配置檔案provider.xml:
<!-- 1、指定當前服務/應用的名字(同樣的服務名字相同,不要和別的服務同名) -->
<dubbo:application name="user-service-provider"></dubbo:application>
<!-- 2、指定註冊中心的位置 -->
<!-- <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry> -->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!-- 3、指定通訊規則(通訊協議?通訊埠) -->
<dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>
<!-- 4、暴露服務 ref:指向服務的真正的實現物件 -->
<dubbo:service interface="com.web.gmall.service.UserService"
ref="userServiceImpl" >
<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
</dubbo:service>
<!--統一設定服務提供方的規則 -->
<dubbo:provider timeout="1000"></dubbo:provider>
<!-- 服務的實現 -->
<bean id="userServiceImpl" class="com.web.gmall.service.impl.UserServiceImpl"></bean>
第三步,編寫主類進行測試
public class MainApplication {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
ioc.start();
System.in.read();
}
}
使用Dubbo Admin管理後臺檢視,可以發現已經新增了一個服務提供者:
④ Dubbo改造服務消費者
第一步:引入依賴:
<!-- 引入dubbo -->
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 註冊中心使用的是zookeeper,引入操作zookeeper的客戶端端 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
第二步,配置服務
在消費者class資源路徑下配置consumer.xml:
<context:component-scan base-package="com.web.gmall.service.impl"></context:component-scan>
<dubbo:application name="order-service-consumer"></dubbo:application>
<dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>
<!--宣告需要呼叫的遠端服務的介面;生成遠端服務代理 -->
<dubbo:reference interface="com.web.gmall.service.UserService"
id="userService" >
</dubbo:reference>
第三步,編寫主類進行測試
public class MainApplication {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = applicationContext.getBean(OrderService.class);
orderService.initOrder("1");
System.out.println("呼叫完成....");
System.in.read();
}
}
在保證Zookeeper服務端,Dubbo Admin和伺服器提供者啟動並正常執行前提下,執行該消費者主類,將會從服務提供者那裡獲取資料!
使用Dubbo Admin後臺檢視:
截止現在,Dubbo+Zookeeper簡單整合實踐,原始碼下載地址。
【6】安裝Monitor監控中心
Simple Monitor 掛掉不會影響到 Consumer 和 Provider 之間的呼叫,所以用於生產環境不會有風險。
Simple Monitor 採用磁碟儲存統計資訊,請注意安裝機器的磁碟限制,如果要叢集,建議用mount共享磁碟。
① 安全並執行Monitor
和安裝Dubbo Admin時步驟類似,進入incubator-dubbo-ops-master\dubbo-monitor-simple
目錄下,使用maven命令進行打包:
mvn clean package -Dmaven.test.skip=true
這裡執行jar前,需要檢視一下配置檔案。將dubbo-monitor-simple-2.0.0-assembly.tar.gz複製並解壓到指定資料夾下,檢視其conf目錄下的配置檔案:
// Zookeeper註冊中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
//監控中心於其他服務通訊埠
dubbo.protocol.port=7070
//監控中心web頁面訪問埠
dubbo.jetty.port=8080
之後,進入dubbo-monitor-simple-2.0.0\assembly.bin
目錄,執行start.bat。
進入瀏覽器檢視監控中心:
此時監控中心還沒有消費者。
② 修改服務提供者/消費者配置
在consumer.xml中新增如下配置:
<dubbo:monitor protocol="registry"></dubbo:monitor>
在provider.xml中如下配置:
<dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>
這兩種有什麼區別?參考官方文件:
重新啟動provider和consumer,提供者向消費者索取服務再次檢視Monitor,將會發現com.alibaba.dubbo.monitor.MonitorService對應的consumer有兩個:provider和consumer都是MonitorService的消費者!