圖解Dubbo和ZooKeeper是如何協同工作的?
介紹
GitHub地址:https://github.com/erlieStar/study-dubbo
微服務是最近比較火的概念,而微服務框架目前主流的有Dubbo和Spring Cloud,兩者都是為了解決微服務遇到的各種問題而產生的,即遇到的問題是一樣的,但是解決的策略卻有所不同,所以這2個框架經常拿來比較。沒用過Dubbo的小夥伴也不用擔心,其實Dubbo還是比較簡單的,看完本文你也能掌握一個大概,重要的不是程式碼,而是思想。
Dubbo實現服務呼叫是通過RPC的方式,即客戶端和服務端共用一個介面,客戶端面向介面寫呼叫,服務端面向介面寫實現,中間的網路通訊交給框架去實現,想深入瞭解的看推薦閱讀。
使用入門
服務提供者
定義服務介面
public interface DemoService {
String sayHello(String name);
}
在服務提供方實現介面
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
用 Spring 配置宣告暴露服務
provider.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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd" >
<!-- 當前專案在整個分散式架構裡面的唯一名稱,用於計算依賴關係 -->
<dubbo:application name="helloworld-app" />
<!--dubbo這個服務所要暴露的服務地址所對應的註冊中心,N/A為不使用註冊中心-->
<dubbo:registry address="N/A"/>
<!--當前服務釋出所依賴的協議;webserovice、Thrift、Hessain、http-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--服務釋出的配置,需要暴露的服務介面-->
<dubbo:service interface="com.st.DemoService"
ref="demoService"/>
<!--bean的定義-->
<bean id="demoService" class="com.st.DemoServiceImpl"/>
</beans>
載入 Spring 配置
public class Provider {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
System.in.read(); // 按任意鍵退出
}
}
服務消費者
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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 -->
<dubbo:application name="consumer-of-helloworld-app"/>
<dubbo:registry address="N/A"/>
<!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
<dubbo:reference id="demoService" interface="com.st.DemoService"
url="dubbo://localhost:20880/com.st.DemoService"/>
</beans>
載入Spring配置,並呼叫遠端服務
public class Consumer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
context.start();
// 獲取遠端服務代理
DemoService demoService = (DemoService)context.getBean("demoService");
// 執行遠端方法
String hello = demoService.sayHello("world");
// Hello world
System.out.println( hello );
}
}
這就是典型的點對點的服務呼叫。當然我們為了高可用,可以在consumer.xml中配置多個服務提供者,並配置響應的負載均衡策略
配置多個服務呼叫者在comsumer.xml的<dubbo:reference>
標籤的url屬性中加入多個地址,中間用分號隔開即可
配置負載均衡策略在comsumer.xml的<dubbo:reference>
標籤中增加loadbalance即可,值可以為如下四種類型
- RoundRobin LoadBalance,隨機,按權重設定隨機概率。
- RoundRobin LoadBalance,輪詢,按公約後的權重設定輪詢比率。
- LeastActive LoadBalance,最少活躍呼叫數,相同活躍數的隨機,活躍數指呼叫前後計數差。
- ConsistentHash LoadBalance,一致性 Hash,相同引數的請求總是發到同一提供者。
<dubbo:reference id="demoService" interface="com.st.DemoService"
url="dubbo://192.168.11.1:20880/com.st.DemoService;
dubbo://192.168.11.2:20880/com.st.DemoService;
dubbo://192.168.11.3:20880/com.st.DemoService"
loadbalance="roundrobin"/>
現在整體架構是如下圖(假設服務消費者為訂單服務,服務提供者為使用者服務):
這樣會有什麼問題呢?
- 當服務提供者增加節點時,需要修改配置檔案
- 當其中一個服務提供者宕機時,服務消費者不能及時感知到,還會往宕機的服務傳送請求
這個時候就得引入註冊中心了
註冊中心
Dubbo目前支援4種註冊中心,(multicast zookeeper redis simple) 推薦使用Zookeeper註冊中心,本文就講一下用zookeeper實現服務註冊和發現(敲黑板,又一種zookeeper的用處)
現在我們來看Dubbo官網對Dubbo的介紹圖,有沒有和我們上面畫的很相似
節點角色說明
節點 | 角色說明 |
---|---|
Provider | 暴露服務的服務提供方 |
Consumer | 呼叫遠端服務的服務消費方 |
Registry | 服務註冊與發現的註冊中心 |
Monitor | 統計服務的呼叫次數和呼叫時間的監控中心 |
Container | 服務執行容器 |
呼叫關係說明
- 服務容器負責啟動(上面例子為Spring容器),載入,執行服務提供者。
- 服務提供者在啟動時,向註冊中心註冊自己提供的服務。
- 服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
- 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
- 服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
- 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。
要使用註冊中心,只需要將provider.xml和consumer.xml更改為如下
<!--<dubbo:registry address="N/A"/>-->
<dubbo:registry protocol="zookeeper" address="192.168.11.129:2181"/>
如果zookeeper是一個叢集,則多個地址之間用逗號分隔即可
<dubbo:registry protocol="zookeeper" address="192.168.11.129:2181,192.168.11.137:2181,192.168.11.138:2181"/>
把consumer.xml中配置的直連的方式去掉
<!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
<!--<dubbo:reference id="demoService" interface="com.st.DemoService"-->
<!--url="dubbo://localhost:20880/com.st.DemoService"/>-->
<dubbo:reference id="demoService" interface="com.st.DemoService"/>
註冊資訊在zookeeper中如何儲存?
啟動上面服務後,我們觀察zookeeper的根節點多了一個dubbo節點及其他,圖示如下
最後一個節點中192.168.1.104是小編的內網地址,你可以任務和上面配置的localhost一個效果,並且這個url中引數省略了,完整地址為。
dubbo://192.168.1.104:20880/com.st.DemoService?anyhost=true&application=helloworld-app&dubbo=2.5.3&interface=com.st.DemoService&methods=sayHello&pid=13360&side=provider×tamp=1544257793335
大家可以想一下我為什麼把最後一個節點標成綠色的。沒錯,最後一個節點是臨時節點,而其他節點是持久節點,這樣,當服務宕機時,這個節點就會自動消失,不再提供服務,服務消費者也不會再請求。如果部署多個DemoService,則providers下面就是DemoService的所有服務地址
其實一個zookeeper叢集能被多個應用公用,如小編Storm叢集和Dubbo配置的就是一個zookeeper叢集,為什麼呢?因為不同的框架會在zookeeper上建不同的節點,互不影響。如dubbo會建立一個/dubbo節點,storm會建立一個/storm節點,如圖