分佈式簡要說明
Dubbo是用於分佈式系統的框架所以我們要先了解什麼是分佈式
分佈式系統是若干獨立 計算機的集合,這些計算機對於用戶來說就像單個相關係統。
老式系統(單一應用架構)就是把一個系統,統一放到一個服務器當中然後每一個服務器上放一個系統,如果說要更新代碼的話,每一個服務器上的系統都要重新去部署十分的麻煩。
而分佈式系統就是將一個完整的系統拆分成多個不同的服務,然後在將每一個服務單獨的放到一個服務器當中。(三個臭皮匠賽過諸葛亮)
應用架構及發展演變
Dubbo和SpringCloud對比
發展演變
ORM
單一應用架構:一個項目裝到一個服務器當中,也可以運行多個服務器每一個服務器當中都裝一個項目。
缺點:1.如果要添加某一個功能的話就要把一個項目重新打包,在分別部署到每一個服務器當中去。2.如果後期項目越來越大的話單臺服務器跑一個項目壓力會很大的。會不利於維護,開發和程序的性能。
MVC
垂直應用架構:將應用切割成幾個互不相干的小應用,在將每個小應用獨立放到一個服務器上,如果哪一個應用的訪問數量多就多加幾臺服務器。
分佈式服務架構
RPC簡介
分佈式應用架構(遠程過程調用):當垂直應用越來越多,應用之間交互不可避免,將核心業務抽取出來,作爲獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。
什麼叫RPC
- RPC [ Remote Procedure Call]是指遠程過程調用,是一種進程問通信方式,他是一種技術的思想,而不是規範。它允許程序調用另一個地址空間(通常是共享網絡的另一臺機器上)的過程或函數,而不用程序員顯式編碼這個遠程調用的細節。即程序員無論是調用本地的還是遠程的函數,本質上編寫的調用代碼基本相同。
- RPC(Remote Procedure Call)—遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。也就是說兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的方法,由於不在一個內存空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的數據。
RPC工作原理
- Client像調用本地服務似的調用遠程服務;
- Client stub接收到調用後,將方法、參數序列化
- 客戶端通過sockets將消息發送到服務端
- Server stub 收到消息後進行解碼(將消息對象反序列化)
- Server stub 根據解碼結果調用本地的服務
- 本地服務執行(對於服務端來說是本地執行)並將結果返回給Server stub
- Server stub將返回結果打包成消息(將結果消息對象序列化)
- 服務端通過sockets將消息發送到客戶端
- Client stub接收到結果消息,並進行解碼(將結果消息發序列化)
- 客戶端得到最終結果。
RPC 調用分以下兩種:
同步調用:客戶方等待調用執行完成並返回結果。
異步調用:客戶方調用後不用等待執行結果返回,但依然可以通過回調通知等方式獲取返回結果。若客戶方不關心調用返回結果,則變成單向異步調用,單向調用不用返回結果。
RPC步驟解析
RPC相關資料可訪問博客:
http://blog.csdn.net/smartbetter/article/details/100360835
SOA
流動計算架構:在分佈式應用架構的基礎上增加了一個調度、治理中心基於訪問壓力實時管理集羣容量、提高集羣的利用率,用於提高機器利用率的 資源調度和治理中心(SOA) 是關鍵 (不浪費計算機資源)
Dubbo核心概念
Dubbo官網: http://dubbo.apache.org/en-us/index.html
Dubbo 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,服務自動註冊和發現。分佈式系統是將一個系統拆分爲多個不同的服務
Dubbo特性一覽
dubbo設計架構
該圖來自Dubbo官網,描述了服務註冊中心、服務提供方、服務消費方、服務監控中心之間的調用關係。
服務提供者(Provider):暴露服務的服務提供方,服務提供者在啓動時,向註冊中心註冊自己提供的服務。
服務消費者(Consumer): 調用遠程服務的服務消費方,服務消費者在啓動時,向註冊中心訂閱自己所需的服務,服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,如果調用失敗,再選另一臺調用。
註冊中心(Registry):註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連接推送變更數據給消費者。
監控中心(Monitor):服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心。
Dubbo的特性
(1)服務註冊中心
- 相比Hessian類RPC框架,Dubbo有自己的服務中心, 寫好的服務可以註冊到服務中心, 客戶端從服務中心尋找服務,然後再到相應的服務提供者機器獲取服務。通過服務中心可以實現集羣、負載均衡、高可用(容錯) 等重要功能。
- 服務中心一般使用zookeeper實現,也有redis和其他一些方式。以使用zookeeper作爲服務中心爲例,服務提供者啓動後會在zookeeper的/dubbo節點下創建提供的服務節點,包含服務提供者ip、port等信息。服務提供者關閉時會從zookeeper中移除對應的服務。
- 服務使用者會從註冊中心zookeeper中尋找服務,同一個服務可能會有多個提供者,Dubbo會幫我們找到合適的服務提供者,也就是針對服務提供者的負載均衡。
(2)負載均衡
- 當同一個服務有多個提供者在提供服務時,客戶端如何正確的選擇提供者實 現負載均衡呢?dubbo也給我們提供了幾種方案:
- random
隨機
選提供者,並可以給提供者設置權重 - roundrobin
輪詢
選擇提供者 - leastactive 最少活躍調用數,相同活躍數的隨機,活躍數:指調用前後計數差。使慢的提供者收到更少請求,因爲越慢的提供者的調用前後計數差會越大。
- consistenthash 一致性hash,相同參數的請求發到同一臺機器上。
- random
(3)簡化測試,允許直連提供者
在開發階段爲了方便測試,通常系統客戶端能指定調用某個服務提供者,那麼可以在引用服務時加一個url參數去指定服務提供者。 配置如下:
<dubbo:reference id="xxxService"interface="com.alibaba.xxx.XxxService"url="dubbo://localhost:20890"/>
(4)服務版本,服務分組
在Dubbo配置文件中可以通過制定版本實現連接制定提供者,也就是通過服務版本可以控制服務的不兼容升級;當同一個服務有多種實現時,可以使用服務分組進行區分。
dubbo環境搭建 ZooKeeper註冊中心
搭建zookeeper註冊中心環境
Dubbo官方文檔: http://dubbo.apache.org/en-us/docs/user/quick-start.html
在zookeeper官網下載zookeeper
http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/
在bin文件下,啓動zkServer.cmd會有報錯,處理需要在condif文件中將zoo_sample.cfg文件複製一份,將名字改爲zoo.cfg。在zookeeper的文件夾下創建data文件夾,打開zoo.cfg,修改datadir,將dataDir數據保存爲我們自定義的文件中
(此步驟可省略)
配置完畢後,我們再次在conf下啓動zkServer.cmd,這次可以成功啓動
繼續運行zkCli.cmd,可以連接到zookeeper的服務器。
此時,我們zookeeper的註冊中心及環境以及搭建完畢。
zookeeper監控中心的配置
1、下載dubbo-admin
dubbo-admin下載地址 :https://github.com/apache/dubbo-admin/tree/master
2、解壓後進入目錄修改指定zookeeper地址
進入如下地址:dubbo-admin-master\dubbo-admin\src\main\resources\application.properties"
將zookeeper的監控中心的地址配置爲本地端口
#註冊中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
配置完畢後,我們在dubo-zookeeper\dubbo-admin-master\dubbo-admin文件夾下cmd打包測試下。
mvn clean package
在target文件中打包完成的jar包
cmd命令 java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
運行打包好的jar包
啓動成功後,可以看到一個7001的端口
此時我們的zookeeper的服務都爲啓動狀態,在瀏覽器中訪問 localhost:7001,訪問到註冊中心,輸入賬號密碼root。
此時,我們zookeeper監控中心的配置完成。注意,要訪問到監控中心,一定要啓動zookeeper註冊中心的啓動類
Dubbo環境搭建,創建提供者、消費者項目
基於以下圖實現服務 提供者、消費者
Dubbo服務提供消費者接口搭建
創建Maven項目=> user-service-provider
服務提供者
UserAddress
public class UserAddress implements Serializable{
private Integer id;
private String userAddress; //用戶地址
private String userId; //用戶id
private String consignee; //收貨人
private String phoneNum; //電話號碼
private String isDefault; //是否爲默認地址 Y-是 N-否
//get set
//有參構造 無參構造
}
UserService
//用戶服務
public interface UserService {
/**
* 按照用戶id返回所有的收貨地址
* @param userId
* @return
*/
public List<UserAddress> getUserAddressList(String userId);
}
UserServiceImpl
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
UserAddress address1 = new UserAddress(1, "河南省鄭州鞏義市宋陵大廈2F", "1", "安然", "150360313x", "Y");
UserAddress address2 = new UserAddress(2, "北京市昌平區沙河鎮沙陽路", "1", "情話", "1766666395x", "N");
return Arrays.asList(address1,address2);
}
}
創建Maven項目=> order-service-consumer
服務消費者(訂單服務)
OrderService
public interface OrderService {
/**
* 初始化訂單
* @param userID
*/
public void initOrder(String userID);
}
OrderServiceImpl
public class OrderServiceImpl implements OrderService {
public void initOrder(String userID) {
//查詢用戶的收貨地址
}
}
因服務消費者要拿到提供者的方法
將 服務提供者 中的 實體類 及 UserService 複製到當前消費者同級文件中。
OrderServiceImpl
public class OrderServiceImpl implements OrderService {
public UserService userService;
public void initOrder(String userID) {
//查詢用戶的收貨地址
List<UserAddress> userAddressList = userService.getUserAddressList(userID);
System.out.println(userAddressList);
}
}
此時我們調用userservice肯定是要報錯的。這種面向接口的方式,我們這裏只是調到了接口,而接口實際是在另外一個項目中,如果我們兩個項目工程都創建共同的實體類,太過於麻煩了,我們可以將服務接口,服務模型等單獨放在一個項目中,更爲方便調用。
創建Maven項目=> gmail-interface 用於存放共同的服務接口
將 提供者 和 消費者 項目中的所有實體類複製到當前相關的文件包下,刪除原有的實體類包及service包,也就是將實體類及service放在了當前公共的項目中。
把服務提供者和消費者項目中引入以下依賴,引入後項目不在報錯.
<dependency>
<groupId>com.lemon.gmail</groupId>
<artifactId>gmail-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
服務提供者配置及測試
在 user-service-provider
服務提供者項目中引入依賴
<!--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>
在resource
文件中創建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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--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="20880"></dubbo:protocol>
<!--4、暴露服務 讓別人調用 ref指向服務的真正實現對象-->
<dubbo:service interface="com.lemon.gmail.service.UserService" ref="userServiceImpl"></dubbo:service>
<!--服務的實現-->
<bean id="userServiceImpl" class="com.lemon.gmail.service.impl.UserServiceImpl"></bean>
</beans>
編寫一個ProviderApplication
啓動類程序,運行測試配置
public class MailApplication {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("provider.xml");
applicationContext.start();
System.in.read();
}
}
啓動zookeeper註冊中心的的zkServer.cmd、和zkCli.cmd服務
在dubbo-admin target中cmd運行 java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
再次啓動項目,我們可以看到在zookeeper中已經發現服務提供者。
服務提供者的配置和測試完成
服務消費者配置及測試
在 order-service-consumer
服務消費者項目中引入依賴
<!--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>
創建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://dubbo.apache.org/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--包掃描-->
<context:component-scan base-package="com.lemon.gmail.service.impl"/>
<!--指定當前服務/應用的名字(同樣的服務名字相同,不要和別的服務同名)-->
<dubbo:application name="order-service-consumer"></dubbo:application>
<!--指定註冊中心的位置-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>
<!--調用遠程暴露的服務,生成遠程服務代理-->
<dubbo:reference interface="com.lemon.gmail.service.UserService" id="userService"></dubbo:reference>
</beans>
把當前OrderServiceImpl實現類中加上註解
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
public UserService userService;
public void initOrder(String userID) {
//查詢用戶的收貨地址
List<UserAddress> userAddressList = userService.getUserAddressList(userID);
//爲了直觀的看到得到的數據,以下內容也可不寫
System.out.println("當前接收到的userId=> "+userID);
System.out.println("**********");
System.out.println("查詢到的所有地址爲:");
for (UserAddress userAddress : userAddressList) {
//打印遠程服務地址的信息
System.out.println(userAddress.getUserAddress());
}
}
}
編寫一個ConsumerApplication
啓動類程序,運行測試配置
public class ConsumerApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = applicationContext.getBean(OrderService.class);
//調用方法查詢出數據
orderService.initOrder("1");
System.out.println("調用完成...");
System.in.read();
}
}
注意:消費者的運行測試需要先啓動提供者。
啓動服務提供者、消費者。及zookeeper的和dubbo-admin,查看監控信息。
localhost:7001
此時可以看到一個提供者,一個消費者的信息監控信息。
dubbo-monitor-simple簡易監控中心
進入dubbo-monitor-simple文件,執行cmd命令,mvn package打包成jar包
將 dubbo-monitor-simple-2.0.0-assembly.tar.gz
壓縮包解壓至當前文件夾,解壓後config文件查看properties的配置是否是本地的zookeeper。
打開解壓後的 assembly.bin
文件,start.bat
啓動dubbo-monitor-simple監控中心
在瀏覽器 localhost:8080
,可以看到一個監控中心。
在服務提供者和消費者的xml中配置以下內容,再次啓動服務提供和消費者啓動類。
<!--dubbo-monitor-simple監控中心發現的配置-->
<dubbo:monitor protocol="registry"></dubbo:monitor>
<!--<dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>-->
可以看到,這個監控中心也捕獲到了服務提供和消費者信息
Dubbo與SpringBoot整合
boot-user-service-provider 服務提供者
創建Maven項目 boot-user-service-provider
服務提供者
導入以下依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>com.lemon.gmail</groupId>
<artifactId>gmail-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
把 user-service-provider
中的service拿到此項目中。
注意,以此方法爲返回的需要更改 interface包中的void爲 List
@Service//dubbo的服務暴露
@Component
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
UserAddress address1 = new UserAddress(1, "河南省鄭州鞏義市宋陵大廈2F", "1", "安然", "150360313x", "Y");
UserAddress address2 = new UserAddress(2, "北京市昌平區沙河鎮沙陽路", "1", "情話", "1766666395x", "N");
return Arrays.asList(address1,address2);
}
}
配置 application.properties
dubbo.application.name=boot-user-service-provider
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#連接監控中心
dubbo.monitor.protocol=registry
BootProviderApplication 啓動類配置
@EnableDubbo //開啓基於註解的dubbo功能
@SpringBootApplication
public class BootProviderApplication {
public static void main(String[] args) {
SpringApplication.run(BootProviderApplication.class, args);
}
}
啓動註冊中心,啓動當前服務提供者,可以在瀏覽器看到一個服務提供者。
boot-order-service-consumer 服務消費者
創建Maven項目 boot-order-service-consumer
服務消費者
導入以下依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.lemon.gmail</groupId>
<artifactId>gmail-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
把order-service-consumer項目中的service複製到當前項目。
@Service
public class OrderServiceImpl implements OrderService {
@Reference//引用遠程提供者服務
UserService userService;
public List<UserAddress> initOrder(String userID) {
//查詢用戶的收貨地址
List<UserAddress> userAddressList = userService.getUserAddressList(userID);
System.out.println("當前接收到的userId=> "+userID);
System.out.println("**********");
System.out.println("查詢到的所有地址爲:");
for (UserAddress userAddress : userAddressList) {
//打印遠程服務地址的信息
System.out.println(userAddress.getUserAddress());
}
return userAddressList;
}
}
創建 OrderController 控制器
@Controller
public class OrderController {
@Autowired
OrderService orderService;
@RequestMapping("/initOrder")
@ResponseBody
public List<UserAddress> initOrder(@RequestParam("uid")String userId) {
return orderService.initOrder(userId);
}
}
創建application.properties 配置
server.port=8081
dubbo.application.name=boot-order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
#連接監控中心 註冊中心協議
dubbo.monitor.protocol=registry
BootConsumerApplication 啓動類創建
@EnableDubbo //開啓基於註解的dubbo功能
@SpringBootApplication
public class BootConsumerApplication {
public static void main(String[] args){
SpringApplication.run(BootConsumerApplication.class,args);
}
}
配置完畢,此時啓動zookeeper註冊中心及監控。
啓動springboot配置的服務提供者和消費者
在瀏覽器輸入 localhost:7001 查看結果
http://localhost:8081/initOrder?uid=1 查詢到地址信息
duboo的springboot整合配置完成。
Dubbo配置
dubbo配置官網參考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-service.html
1、配置原則
JVM 啓動 -D 參數優先,這樣可以使用戶在部署和啓動時進行參數重寫,比如在啓動時需改變協議的端口。
XML 次之,如果在 XML 中有配置,則 dubbo.properties 中的相應配置項無效。
Properties 最後,相當於缺省值,只有 XML 沒有配置時,dubbo.properties 的相應配置項纔會生效,通常用於共享公共配置,比如應用名。
2、啓動時檢查
Dubbo 缺省會在啓動時檢查依賴的服務是否可用,不可用時會拋出異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題,默認 check=“true”。
可以通過 check=“false” 關閉檢查,比如,測試時,有些服務不關心,或者出現了循環依賴,必須有一方先啓動。
另外,如果你的 Spring 容器是懶加載的,或者通過 API 編程延遲引用服務,請關閉 check,否則服務臨時不可用時,會拋出異常,拿到 null 引用,如果 check=“false”,總是會返回引用,當服務恢復時,能自動連上。
以order-service-consumer
消費者爲例,在consumer.xml中添加配置
<!--配置當前消費者的統一規則,當前所有的服務都不啓動時檢查-->
<dubbo:consumer check="false"></dubbo:consumer>
添加後,即使服務提供者不啓動,啓動當前的消費者,也不會出現錯誤。
3、全局超時配置
全局超時配置
<dubbo:provider timeout="5000" />
指定接口以及特定方法超時配置
<dubbo:provider interface="com.foo.BarService" timeout="2000">
<dubbo:method name="sayHello" timeout="3000" />
</dubbo:provider>
配置原則
dubbo推薦在Provider上儘量多配置Consumer端屬性
1、作服務的提供者,比服務使用方更清楚服務性能參數,如調用的超時時間,合理的重試次數,等等
2、在Provider配置後,Consumer不配置則會使用Provider的配置值,即Provider配置可以作爲Consumer的缺省值。否則,Consumer會使用Consumer端的全局設置,這對於Provider不可控的,並且往往是不合理的
配置的覆蓋規則:
- 方法級配置別優於接口級別,即小Scope優先
- Consumer端配置 優於 Provider配置 優於 全局配置,
- 最後是Dubbo Hard Code的配置值(見配置文檔)
多版本控制
http://dubbo.apache.org/zh-cn/docs/user/demos/multi-versions.html
在服務提供者中複製多個impl。起不同的名字
配置多個文件的路徑及信息。
服務消費者調用時,可自由配置版本
dubbo與springboot整合的三種方式
1、將服務提供者註冊到註冊中心(如何暴露服務)
1.1導入Dubbo的依賴 和 zookeeper 客戶端
2、讓服務消費者去註冊中心訂閱服務提供者的服務地址
Springboot與Dubbo整合的三種方式
2.1導入dubbo-starter。在application.properties配置屬性,使用@Service【暴露服務】,使用@Reference【引用服務】
2.2保留Dubbo 相關的xml配置文件
導入dubbo-starter,使用@ImportResource導入Dubbo的xml配置文件
3、使用 註解API的方式
將每一個組件手動配置到容器中,讓dubbo來掃描其他的組件
高可用
zookeeper宕機與dubbo直連
現象:zookeeper註冊中心宕機,還可以消費dubbo暴露的服務。
原因:
健壯性↓
- 監控中心宕掉不影響使用,只是丟失部分採樣數據
- 數據庫宕掉後,註冊中心仍能通過緩存提供服務列表查詢,但不能註冊新服務
- 註冊中心對等集羣,任意一臺宕掉後,將自動切換到另一臺
- 註冊中心全部宕掉後,服務提供者和服務消費者仍能通過本地緩存通訊
- 服務提供者無狀態,任意一臺宕掉後,不影響使用
- 服務提供者全部宕掉後,服務消費者應用將無法使用,並無限次重連等待服務提供者恢復
高可用:通過設計,減少系統不能提供服務的時間;
集羣下dubbo負載均衡配置
在集羣負載均衡時,Dubbo 提供了多種均衡策略,缺省爲 random 隨機調用。
負載均衡策略如下
Random LoadBalance 基於權重的隨機負載均衡機制隨機,按權重設置隨機概率。 在一個截面上碰撞的概率高,但調用量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。
RoundRobin LoadBalance 基於權重的輪詢負載均衡機制輪循,按公約後的權重設置輪循比率。 存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。
LeastActive LoadBalance最少活躍數負載均衡機制最少活躍調用數,相同活躍數的隨機,活躍數指調用前後計數差。 使慢的提供者收到更少請求,因爲越慢的提供者的調用前後計數差會越大。
ConsistentHash LoadBalance一致性hash 負載均衡機制一致性 Hash,相同參數的請求總是發到同一提供者。 當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。算法參見:http://en.wikipedia.org/wiki/Consistent_hashing 缺省只對第一個參數 Hash,如果要修改,請配置 <dubbo:parameter key="hash.arguments" value="0,1" /> 缺省用 160 份虛擬節點,如果要修改,請配置 <dubbo:parameter key="hash.nodes" value="320" />
整合hystrix,服務熔斷與降級處理
服務降級
當服務器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運作或高效運作。
可以通過服務降級功能臨時屏蔽某個出錯的非關鍵服務,並定義降級後的返回策略。
向註冊中心寫入動態配置覆蓋規則:
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
- 1
- 2
- 3
其中:
mock=force:return+null 表示消費方對該服務的方法調用都直接返回 null 值,不發起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。
還可以改爲 mock=fail:return+null 表示消費方對該服務的方法調用在失敗後,再返回 null 值,不拋異常。用來容忍不重要服務不穩定時對調用方的影響。
集羣容錯
在集羣調用失敗時,Dubbo 提供了多種容錯方案,缺省爲 failover 重試。
集羣容錯模式
Failover Cluster
失敗自動切換,當出現失敗,重試其它服務器。通常用於讀操作,但重試會帶來更長延遲。可通過 retries=“2” 來設置重試次數(不含第一次)。
重試次數配置如下:
<dubbo:service retries=“2” />
或
<dubbo:reference retries=“2” />
或
dubbo:reference
<dubbo:method name=“findFoo” retries=“2” />
</dubbo:reference>
Failfast Cluster
快速失敗,只發起一次調用,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
Failsafe Cluster
失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於消息通知操作。
Forking Cluster
並行調用多個服務器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks=“2” 來設置最大並行數。
Broadcast Cluster
廣播調用所有提供者,逐個調用,任意一臺報錯則報錯 [2]。通常用於通知所有提供者更新緩存或日誌等本地資源信息。
集羣模式配置
按照以下示例在服務提供方和消費方配置集羣模式
<dubbo:service cluster=“failsafe” />
或
<dubbo:reference cluster=“failsafe” />
整合hystrix
服務熔斷錯處理配置參考=> https://www.cnblogs.com/xc-xinxue/p/12459861.html
Hystrix 旨在通過控制那些訪問遠程系統、服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備擁有回退機制和斷路器功能的線程和信號隔離,請求緩存和請求打包,以及監控和配置等功能
配置spring-cloud-starter-netflix-hystrix
spring boot官方提供了對hystrix的集成,直接在pom.xml里加入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
然後在Application類上增加@EnableHystrix來啓用hystrix starter:
@SpringBootApplication
@EnableHystrix //開啓服務容錯功能
public class ProviderApplication {
...啓動方法
}
配置Provider端
在Dubbo的Provider上增加@HystrixCommand配置,這樣子調用就會經過Hystrix代理。
@Service(version = "1.0.0")
public class HelloServiceImpl implements HelloService {
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
@Override
public String sayHello(String name) {
// System.out.println("async provider received: " + name);
// return "annotation: hello, " + name;
throw new RuntimeException("Exception to show hystrix enabled.");
}
}
配置Consumer端
對於Consumer端,則可以增加一層method調用,並在method上配置@HystrixCommand。當調用出錯時,會走到fallbackMethod = "reliable"的調用裏。
@Reference(version = "1.0.0")
private HelloService demoService;
@HystrixCommand(fallbackMethod = "reliable")
public String doSayHello(String name) {
return demoService.sayHello(name);
}
public String reliable(String name) {
return "hystrix fallback value";
}
dubbo原理
RPC原理
一次完整的RPC調用流程(同步調用,異步另說)如下:
- 服務消費方(client)調用以本地調用方式調用服務;
- client stub接收到調用後負責將方法、參數等組裝成能夠進行網絡傳輸的消息體;
- client stub找到服務地址,並將消息發送到服務端;
- server stub收到消息後進行解碼;
- server stub根據解碼結果調用本地的服務;
- 本地服務執行並將結果返回給server stub;
- server stub將返回結果打包成消息併發送至消費方;
- client stub接收到消息,並進行解碼;
- 服務消費方得到最終結果。
dubbo只用了兩步1和8,中間的過程是透明的看不到的。RPC框架的目標就是要2~8這些步驟都封裝起來,這些細節對用戶來說是透明的,不可見的。
netty通信原理
Netty是一個異步事件驅動的網絡應用程序框架, 用於快速開發可維護的高性能協議服務器和客戶端。它極大地簡化並簡化了TCP和UDP套接字服務器等網絡編程。
BIO:(Blocking IO)
NIO (Non-Blocking IO)
Selector 一般稱 爲選擇器 ,也可以翻譯爲 多路複用器,
Connect(連接就緒)、Accept(接受就緒)、Read(讀就緒)、Write(寫就緒)
Netty基本原理:
netty基本原理,可參考https://www.sohu.com/a/272879207_463994
dubbo原理
1.dubbo原理 -框架設計
- config 配置層:對外配置接口,以 ServiceConfig, ReferenceConfig 爲中心,可以直接初始化配置類,也可以通過 spring 解析配置生成配置類
- proxy 服務代理層:服務接口透明代理,生成服務的客戶端 Stub 和服務器端 Skeleton, 以 ServiceProxy 爲中心,擴展接口爲 ProxyFactory
- registry 註冊中心層:封裝服務地址的註冊與發現,以服務 URL 爲中心,擴展接口爲 RegistryFactory, Registry, RegistryService
- cluster 路由層:封裝多個提供者的路由及負載均衡,並橋接註冊中心,以 Invoker 爲中心,擴展接口爲 Cluster, Directory, Router, LoadBalance
- monitor 監控層:RPC 調用次數和調用時間監控,以 Statistics 爲中心,擴展接口爲 MonitorFactory, Monitor, MonitorService
- protocol 遠程調用層:封裝 RPC 調用,以 Invocation, Result 爲中心,擴展接口爲 Protocol, Invoker, Exporter
- exchange 信息交換層:封裝請求響應模式,同步轉異步,以 Request, Response 爲中心,擴展接口爲 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
- transport 網絡傳輸層:抽象 mina 和 netty 爲統一接口,以 Message 爲中心,擴展接口爲 Channel, Transporter, Client, Server, Codec
- serialize 數據序列化層:可複用的一些工具,擴展接口爲 Serialization, ObjectInput, ObjectOutput, ThreadPool
2.dubbo原理 -啓動解析、加載配置信息
3.dubbo原理 -服務暴露
4.dubbo原理 -服務引用
5.dubbo原理 -服務調用