Dubbo框架結合Zookeeper註冊中心使用初探
【參考文章】http://www.cnblogs.com/Javame/p/3632473.html (灰常感謝這篇啟蒙文章!!)
【文章有錯,修改見刪除線處。。】
一、基本概念
【Dubbo】
Dubbo是一個來源於阿里巴巴的分散式服務框架,本質上是一個服務呼叫的東西,主要在分散式場景中使用。它是以服務者/訊息者的模式在dubbo上註冊的。
核心:1)RPC:遠端通訊——對長連線的NIO框架進行封裝(多執行緒模型、序列化、“請求-響應”模式的資訊交換);
2)叢集容錯:基於介面方法的遠端過程呼叫,各種叢集支援
3)基於註冊中心目錄的服務(這裡用到的即是zookeeper),讓服務的消費者可以動態地查詢到服務提供者,地址透明化,以便服務者可以平滑的增加或者減少節點。
【Zookeeper】
ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要元件。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、名字服務、分散式同步、組服務等。
ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。
理解Zookeeper的演算法可代入現實生活的“投票選舉”。
Zookeeper字面意思是“動物園管理員”,它是一個分散式的服務框架,基於Fast Paxos演算法。Zookeeper分散式叢集裡,主要分為三個角色:
Leader接收所有Follower的提案請求並統一協調發起提案的投票,負責與所有的Follower進行內部的資料交換(同步);
Follower直接為客戶端服務並參與提案的投票,同時與Leader進行資料交換(同步);
Observer直接為客戶端服務但並不參與提案的投票,同時也與Leader進行資料交換(同步)。
ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。
【Dubbo使用背景】
大規模分散式服務的背景需求。之前在大規模分散式服務以前,都是簡單使用原生的RMI,簡單暴露和引用遠端服務,通過配置遠端服務的URL地址進行呼叫,而通過硬體進行負載均衡(負載均衡:負載均衡,英文名稱為Load Balance,其意思就是分攤到多個操作單元上進行執行,例如Web伺服器、FTP伺服器、企業關鍵應用伺服器和其它關鍵任務伺服器等,從而共同完成工作任務。)
大規模分散式需求下,出現問題:
(1)當服務越來越多時,服務URL配置管理變得非常困難,F5硬體負載均衡器的單點壓力也越來越大。——因此此時非常需要一個服務註冊中心,動態註冊和發現服務,管理服務地址
(2)服務間依賴關係變得錯蹤複雜,甚至分不清哪個應用要在哪個應用之前啟動——需自己整理應用服務之間的依賴關係圖
(3)服務呼叫量加大時,服務的容量限制問題
——Dubbo解決了以上面對的的問題。
二、Dubbo框架架構
【說明】Provider——給外界提供服務的服務方
Container——服務方執行服務的容器,負責啟動、載入執行服務
Registry——服務註冊與服務發現的中心(這裡我們用的是zookeeper)
Monitor——監控中心,用於統計服務的呼叫次數和呼叫時間
服務呼叫過程:
Step1 首先服務方啟動時,向註冊中心註冊自己可提供的服務;
Step2 服務消費者啟動時,向註冊中心訂閱自己所需的相關服務
Step3 註冊中心在接收到訂閱請求後,返回服務提供方的地址列表給服務消費方,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
Step4 服務消費方從提供的地址列表中基於負載均衡演算法選擇一臺服務提供方進行呼叫,若呼叫失敗,選擇另一臺
Step5 同時在呼叫的過程中,服務方和消費者都會在記憶體中累計呼叫次數和呼叫時間,定時將統計資料傳送給監控中心。
——那麼問題來了,如何使用Dubbo?
三、Dubbo簡單使用
Dubbo是一個開源優秀的分散式服務呼叫框架,幸運地是可以跟Spring MVC無縫整合,而沒有任何API侵入。Dubbo基於Spring的Schema擴充套件進行載入。所以常常在web平臺的專案中使用到。
而zookeeper作為Dubbo的服務註冊中心,我們首先要安裝zookeeper啟動註冊中心服務。
簡單來說,就是在A應用中定義一個介面及其實現類,然後配置對應的配置檔案,把實現類打成一個jar包。B應用引用該jar包,並且需定義相同的介面,介面名稱和路徑必須和A應用對外的介面路徑一致。
步驟:建立2個web應用,必須先引入相關jar包(jar包的獲取可以先下載一個dubbo-admin-2.5.4.war包,再解壓,裡面會有相關jar包):
dubbo-2.5.4-SNAPSHOT.jar
netty-3.2.5.Final.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.6.2.jar
slf4j-simple-1.7.2.jar
zkclient-0.1.jar
zookeeper-3.3.3.jar
下面開始使用Dubbo的示例:
【服務提供方】
1、先定義A應用(作為服務對外的提供方),定義多個介面(考慮到今後真正投入到專案中使用的時候,肯定不止一個介面,所以我用2個介面來模擬):
介面一:
Java程式碼- public interface ServiceDemo {
- String sayHello(String name);
- }
介面二:
Java程式碼- public interface ServiceDemo2 {
- String print(String name);
- }
還有他們的實現類:
Java程式碼- public class ServiceDemoImpl implements ServiceDemo {
- @Override
- public String sayHello(String name) {
- return "hello " + name;
- }
- }
以及介面二的實現類:
Java程式碼- public class ServiceDemoImpl2 implements ServiceDemo2 {
- @Override
- public String print(String name) {
- return "My name is " + name;
- }
- }
服務提供方的配置:
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 ">
- <bean id="demoService" class="com.xxx.demo.dubbo.ServiceDemoImpl" />
- <bean id="demoService2" class="com.xxx.demo.dubbo.ServiceDemoImpl2" />
- <!-- 提供方應用資訊 -->
- <dubbo:application name="service_provider" />
- <!-- 用zookeeper註冊中心暴露服務地址 -->
- <dubbo:registry address="zookeeper://127.0.0.1:2181" subscribe="false"/>
- <!-- 用dubbo協議在指定埠暴露服務 -->
- <dubbo:protocol name="dubbo" port="20880" />
- <!-- 宣告需要暴露的(多個)服務介面 -->
- <dubbo:service interface="com.xxx.demo.dubbo.ServiceDemo" ref="demoService" />
- <dubbo:service interface="com.xxx.demo.dubbo.ServiceDemo2" ref="demoService2" />
- </beans>
再將這多個實現類(注意是實現類,【應為介面並非實現類!!!!】這裡為2個)單獨打成1個(注意是1個)jar包(選中這多個實現類,【是介面】右鍵->Export->JAR
file->Next(只勾選Export Java source files and resources)->命名->Next匯出),這裡命名為dubbo-test.jar。
【服務消費方】
2、定義B應用(服務消費方),分別並且定義與A應用路徑相同的介面(這裡就不再把程式碼顯示出來了因為跟上面介面的定義一模一樣),這裡的介面也與服務提供方一致。【有錯!正確的是把服務提供端的介面打成jar包(並非實現類打成jar包),把這個jar包給服務的消費端即可。服務的實現類應該對消費端隱藏!】這裡即為ServiceDemo和ServiceDemo2,並且他們的包名路徑應該與A應用的對外提供的介面包名路徑一致。
【注意】除了上述所說的jar包外,在B應用中另外加入剛才由A應用提供的jar包dubbo-test.jar
服務消費方的配置(這裡IP為127.0.0.1是因為服務方就在我本機)
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="service_consumer" />
- <!-- 用zookeeper註冊中心暴露服務地址 -->
- <dubbo:registry address="zookeeper://127.0.0.1:2181" />
- <!-- 生成遠端服務代理,以便在本地可以使用遠端曝露的(多個)介面服務-->
- <dubbo:reference interface="com.xxx.demo.dubbo.ServiceDemo" id="caller"/>
- <dubbo:reference interface="com.xxx.demo.dubbo.ServiceDemo2" id="caller2"/>
- </beans>
然後我又嘗試了在另外一臺機器建立服務消費方(Jar包匯入、介面定義什麼的跟上述操作一樣),其配置為(這裡的IP就必須寫服務提供方所在機器的ip地址了,即為我電腦的ip):
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="service_consumer" />
- <!-- 用zookeeper註冊中心暴露服務地址 -->
- <dubbo:registry address="zookeeper://192.168.0.105:2181" />
- <!-- 生成遠端服務代理,以便在本地可以使用遠端曝露的多個介面服務-->
- <dubbo:reference interface="com.xxx.demo.dubbo.ServiceDemo" id="caller"/>
- <dubbo:reference interface="com.xxx.demo.dubbo.ServiceDemo2" id="caller2"/>
- </beans>
【Zookeeper註冊中心啟動】
3、啟動zookeeper服務註冊中心,進入zookeeper安裝路徑/bin,雙擊zkServer.cmd命令即可開啟。
【服務測試部分】
在A應用(工程)中啟動服務提供方(向Zookeepr註冊服務):
Java程式碼- public class Provider {
- public static void main(String[] args) throws Exception {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- new String[] {"context-dubbo-provider.xml"});
- context.start();
- System.in.read();//用於模擬服務一直開著
- }
- }
接著,分別在本機和另外一臺機器啟動服務消費方(從Zookeepr訂閱服務):
Java程式碼- public class Consumer {
- public static void main(String[] args) throws Exception {
- FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
- new String[] {
- "webRoot/WEB-INF/conf/spring/sys/context-dubbo-consumer.xml"});
- context.start();
- ServiceDemo demo = (ServiceDemo) context.getBean("caller");
- String hello = demo.sayHello("Lily");
- System.out.println("After call the remote (sayHello): " + hello);
- System.out.println("================");
- ServiceDemo2 demo2 = (ServiceDemo2) context.getBean("caller2");
- System.out.println(demo2.print("Tom"));
- System.in.read();
- }
- }
之後在本機和另外一臺機器(2個服務消費方)分別可以得到如下的列印結果:
After call the remote (sayHello): hello Lily
======================
My name is Tom
說明了A應用對外提供的多個介面服務都被遠端呼叫成功了!
======================
遇到的異常:
No provider available for the service xxxxx出現該異常原因之一很可能是因為服務的消費方沒有匯入服務提供方提供的jar包(jar包封裝的是實現類而不是介面!),當然也有可能是其他原因造成。。
四、Dubbo管理控制
好吧。。因為之前參考網上的文章都有這部分,所以自己也做了一下。。。
將下載好的war包,我下的是dubbo-admin-2.5.4-SNAPSHOT.war(dubbo服務管理的war包)
將tomcat安裝檔案下的webapps/ROOT的東西刪除(建議先備份),再把上述war包解壓後的全部檔案拷貝至ROOT下,而且tomcat使用的jdk的版本不要太高,控制在jdk1.7或以下最佳。啟動tomcat成功後,在瀏覽器位址列輸入http://loclahost:8080,此時會彈出一個要求你輸入使用者名稱密碼的會話框,都填入root,即可得到dubbo管理介面:
進入管理介面即可看到服務者、消費者、服務被呼叫的統計情況等等,這裡為節省篇幅,只看看消費者的截圖(因為有2臺機器都訪問了A應用提供的對外的介面,所以有2列資料):
綜上:簡單理解來說,Dubbo和Zookeeper的結合使用達到了遠端呼叫的效果。Dubbo是一個分散式服務框架(尤其在RPC效能方面體現較好),而Zookeeper是作為Dubbo的服務註冊中心而使用的。