分散式服務框架Dubbo使用小結
介紹:
Dubbo是一個被國內很多網際網路公司廣泛使用的開源分散式服務框架,致力於提供高效能和透明化的RPC遠端服務呼叫方案,以及SOA
服務治理方案,每天為2,000+個服務提供3,000,000,000+次訪問量支援,並被廣泛應用於阿里巴巴集團的各成員站點。
其核心部分包含:
- 遠端通訊: 提供對多種基於長連線的NIO框架抽象封裝,包括多種執行緒模型,序列化,以及“請求-響應”模式的資訊交換方式。
- 叢集容錯: 提供基於介面方法的透明遠端過程呼叫,包括多協議支援,以及軟負載均衡,失敗容錯,地址路由,動態配置等叢集支援。
- 自動發現: 基於註冊中心目錄服務(最常用的是基於zookeeper),使服務消費方能動態的查詢服務提供方,使地址透明,使服務
Dubbo能做什麼?
- 透明化的遠端方法呼叫,就像呼叫本地方法一樣呼叫遠端方法,只需簡單配置,沒有任何API侵入。
- 軟負載均衡及容錯機制,可在內網替代F5等硬體負載均衡器,降低成本,減少單點。
- 服務自動註冊與發現,不再需要寫死服務提供方地址,註冊中心基於介面名查詢服務提供者的IP地址,並且能夠平滑新增或刪除服務 提供者。
擴充套件:
dubbox相當於dubbo的擴充套件,最主要Dubbox增加了如RESTful remoting,Kyro/FST 系列化等額外功能,dubbox和dubbo2.x是相容的, 沒有改變dubbo的任何已有的功能和配置方式(除了升級了spring之類的版本)。
配置:
服務端介面實現類:
public classDemoServiceImpl implements DemoService {
public String sayHello(Stringname) {
return "Hello "+ name;
}
}
服務端spring配置:
<?xml version="1.0" encoding="UTF-8"?> <beansxmlns="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:applicationname="hello-world-app" /> <!--使用multicast廣播註冊中心暴露服務地址--> <dubbo:registryprotocal=“zookeeper”address="192.168.152.100:2181,192.168.152.101:2181,192.168.152.102:2181" /> <!--用dubbo協議在20880埠暴露服務 --> <dubbo:protocolname="dubbo"port="20880" /> <!--宣告需要暴露的服務介面 --> <dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoService"ref="demoService" /> <!--和本地bean一樣實現服務可以改為註解式--> <beanid="demoService"class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" /> </beans>
消費端spring配置:
<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="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:applicationname="consumer-of-helloworld-app" />
<!--使用multicast廣播註冊中心暴露發現服務地址-->
<dubbo:registryprotocal=“zookeeper”address="192.168.152.100:2181,192.168.152.101:2181,192.168.152.102:2181" />
<!--生成遠端服務代理,可以和本地bean一樣使用demoService -->
<dubbo:referenceid="demoService"interface="com.alibaba.dubbo.demo.DemoService" />
</beans>
服務呼叫程式碼:
public class Consumer{
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext(new String[] {"consumer.xml"});
context.start();
DemoService demoService=(DemoService)context.getBean("demoService");//獲取遠端服務代理
String hello =demoService.sayHello("world");//執行遠端方法
System.out.println(hello ); //顯示呼叫結果
}
}
優勢:
- Dubbo通過長連線減少握手,通過NIO及執行緒池在單連線上併發拼包處理訊息,通過二進位制流壓縮資料,比常規HTTP等短連線協議更快。在阿里巴巴內部,每天支撐2000多個服務,30多億訪問量,最大單機支撐每天近1億訪問量。
健狀性
- 監控中心宕掉不影響使用,只是丟失部分取樣資料
- 資料庫宕掉後,註冊中心仍能通過快取提供服務列表查詢,但不能註冊新服務
- 註冊中心對等叢集,任意一臺宕掉後,將自動切換到另一臺
- 註冊中心全部宕掉後,服務提供者和服務消費者仍能通過本地快取通訊
- 服務提供者無狀態,任意一臺宕掉後,不影響使用
- 服務提供者全部宕掉後,服務消費者應用將無法使用,並無限次重連等待服務提供者恢復
伸縮性
- 註冊中心為對等叢集,可動態增加機器部署例項,所有客戶端將自動發現新的註冊中心
- 服務提供者無狀態,可動態增加機器部署例項,註冊中心將推送新的服務提供者資訊給消費者
升級性
- 當服務叢集規模進一步擴大,帶動IT治理結構進一步升級,需要實現動態部署,進行流動計算,現有分散式服務架構不會帶來阻力
管理介面:
原理:
節點角色說明:
Provider: 暴露服務的服務提供方。
Consumer: 呼叫遠端服務的服務消費方。
Registry: 服務註冊與發現的註冊中心。
Monitor: 統計服務的呼叫次調和呼叫時間的監控中心。
Container: 服務執行容器。
呼叫關係說明:
0. 服務容器負責啟動,載入,執行服務提供者。
1. 服務提供者在啟動時,向註冊中心註冊自己提供的服務。
2. 服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
3. 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
4. 服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
5. 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。
Dubbo能與Zookeeper做到叢集部署,當提供者出現斷電等異常停機時,Zookeeper註冊中心能自動刪除提供者資訊,當提供者重啟時,能自動恢復註冊資料,以及訂閱請求
經驗:
- zookeeper安裝的版本和pom檔案zookeeper的版本要保持一致,否則會發生找不到服務的錯誤
- 使用maven-shade-plugin外掛打包可以將所有依賴匯入jar包,並且也不會出現找不到spring配置,dubbo配置檔案的問題,唯一要注意的是要將spring配置檔案放到resources/META-INF目錄下
- 服務端main函式要保持執行有兩種方法:
- System.in.read(); //為保證服務一直開著,利用輸入流的阻塞來模擬;
- synchronized(Main.class) {
while (true) {
try{
Main.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
推薦第二種方法,因為第一種方法在使用nohup命令時無法正常啟動
- 消費端呼叫時的pojo一定要實現serializable介面,否則傳不過去,程式卡死,
- 服務端生成的api一定要放到消費端WEB-INF/lib下,否則web專案會提示找不到方法