《分佈式系統原理與範型》定義:
「分佈式系統是若干獨立計算機的集合,這些計算機對於用戶來講就像單個相關係統」
分佈式系統(distributed system)是創建在網絡之上的軟件系統。java
架構的發展是由最初的單一應用架構構建的,通常就是ORM框架方便數據庫操做。linux
不過隨着系統愈來愈複雜,單一應用架構會變得難以維護,因此架構逐漸演變出了垂直應用架構,所謂垂直應用架構其實就是安裝業務模板進行拆分,好比能夠安裝業務將一個電商系統分爲訂單模塊,用戶信息管理模塊,商品管理模塊等等,這時候MVC框架就派上用場,MVC框架能夠協助系統更好的按業務拆分,不過業務拆分後雖然是比單一應用架構更好維護了。git
不過隨着系統越來約複雜,發現不少共用的模塊很難複用起來,這時候分佈式服務架構登場了,分佈式架構是將一些核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心,當應用須要時,就去服務中心調服務就能夠,而實現這種服務註冊的確定是RPC框架了。程序員
當服務愈來愈多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增長一個調度中心基於訪問壓力實時管理集羣容量,提升集羣利用率,這時候就須要流動計算架構(SOA)[ Service Oriented Architecture],用於提升機器利用率的資源調度,SOA是一個治理中心,綜上所述,到目前,軟件系統架構演變經歷了:單一應用架構->垂直應用架構->分佈式應用架構->流動計算架構,下面Dubbo官網的圖片能夠很好的描述
github
RPC概念
RPC【Remote Procedure Call】是指遠程過程調用,是一種進程間通訊方式,他是一種技術的思想,而不是規範。它容許程序調用另外一個地址空間(一般是共享網絡的另外一臺機器上)的過程或函數,而不用程序員顯式編碼這個遠程調用的細節。web
RPC核心模塊
RPC有兩個核心模塊:通訊和序列化算法
Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。spring
官網:
http://dubbo.apache.org/數據庫
Dubbo的服務治理:
apache
Dubbo原理圖片,圖片來自Dubbo官網:
Dubbo角色:
Provider:暴露服務的服務提供者
Container:服務運行的容器
Consumer:調用遠程服務的消費者
Registry:服務註冊和發現的註冊中心
Minitor:統計服務調用次數和時間的監控中心
調用過程:
下面根據個人理解說明一下
0:服務器容器負責啓動、加載、運行服務提供者
1:服務提供者在啓動後就能夠向註冊中心暴露服務
2:服務消費者在啓動後就能夠向註冊中心訂閱想要的服務
3:註冊中心向服務消費者返回服務調用列表
4:服務消費者基於軟負載均衡算法調用服務提供者的服務,這個服務提供者有多是一個服務提供者列表,調用那個服務提供者就是根據負載均衡來調用了
5:服務提供者和服務消費者定時將保存在內存中的服務調用次數和服務調用時間推送給監控中心
搭建Zookeeper,首先是搭建分佈式架構的註冊中心Zookeeper,固然也能夠用Redis等等來作服務註冊中心,不過本博客只介紹Zookeeper的,由於沒有linux服務器,因此只介紹window版的搭建
一、下載Zookeeper:
網址 https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/
三、配置Zookeeper
由於Zookeeper的conf文件夾下面只提供zoo_sample.cfg文件,須要本身修改命名爲zoo.cfg
對於配置文件須要注意:
dataDir=./ 臨時數據存儲的目錄(可寫相對路徑)
clientPort=2181 zookeeper的端口號
ok,簡單在zkCli.cmd敲幾個命令測試一下:
ls /:列出zookeeper根下保存的全部節點
create –e /testNode 12345678:建立一個testNode節點,值爲12345678
get /testNode:獲取/testNode節點的值
搭建了服務註冊中心後,就須要搭建Dubbo-admin了,最近看了一下,dubbo的Github項目已經進行了更新,管理平臺已經作了比較大的改動,而我學習的時候,平臺是比較簡單的,因此本dubbo-admin搭建是以舊版master的爲準,不過以學習爲目的的,只須要知道具體原理和操做技巧就能夠
由於我搭建時候(ps:不是博客寫做時間),dubbo還沒作比較大改動,因此我以比較舊的版本爲例子,如今新的具體參考dubbo官方的教程,本博客只是作記錄
修改 src\main\resources\application.properties 指定zookeeper地址
mvn clean package -Dmaven.test.skip=true
maven打包以後,就去target裏找到jar,而後cmd運行
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
運行成功以後,訪問: http://127.0.0.1:7001,輸入默認的帳號密碼root/root,登陸成功
經典例子(引用尚硅谷教程例子進行改寫):
某個電商系統,訂單服務須要調用用戶服務獲取某個用戶的全部地址;
咱們如今 須要建立兩個服務模塊進行測試
模塊 | 功能 |
---|---|
訂單服務模塊 | 建立訂單等 |
用戶服務模塊 | 查詢用戶地址等 |
建立工程:
建議將服務接口,服務模型,服務異常等均放在 API 包中,由於服務模型及異常也是 API 的一部分,同時,這樣作也符合分包原則:重用發佈等價原則(REP),共同重用原則(CRP)。
建立一個API工程,將實體類和接口都放在api工程
maven新建一個shop-api-common工程:
用戶地址DTO類:
package com.test.dubbo.bean; import java.io.Serializable; 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-否 public UserAddress() { super(); } public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum, String isDefault) { super(); this.id = id; this.userAddress = userAddress; this.userId = userId; this.consignee = consignee; this.phoneNum = phoneNum; this.isDefault = isDefault; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) { this.userAddress = userAddress; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getConsignee() { return consignee; } public void setConsignee(String consignee) { this.consignee = consignee; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } public String getIsDefault() { return isDefault; } public void setIsDefault(String isDefault) { this.isDefault = isDefault; } }
用戶信息服務接口:
package com.test.dubbo.service; import java.util.List; import com.test.dubbo.bean.UserAddress; /** * 用戶服務 */ public interface UserService { /** * 按照用戶id返回全部的收貨地址 * @param userId * @return */ public List<UserAddress> getUserAddressList(String userId); }
訂單信息服務接口:
package com.test.dubbo.service; import java.util.List; import com.test.dubbo.bean.UserAddress; public interface OrderService { /** * 初始化訂單 * @param userId */ public List<UserAddress> initOrder(String userId); }
ok,建立好api工程
要實現服務提供,配置文件主要須要配置以下:
Dubbo提供者加載過程(Dubbo容器的啓動):
Spring加載xml配置以後暴露服務的過程:
Exporter方法主要是打開socket的監聽,接收客戶的請求
ok,理解了上面的理論知識後,繼續建立一個user-service-provider工程:
參考Dubbo官方例子
<properties> <spring-boot.version>2.2.1.RELEASE</spring-boot.version> <dubbo.version>2.7.5</dubbo.version> <curator.version>2.12.0</curator.version> </properties> <dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
我用的Springboot版本是2.2.1,dubbo starter版本是2.7.5,啓動以後,發現報錯
Caused by: java.lang.: org.apache.curClassNotFoundExceptionator.framework.CuratorFrame
找不到對應的類,看起來是缺乏jar了?經過網上資料搜索再加上以下配置便可:
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>${curator.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>${curator.version}</version> </dependency>
curator是Zookeeper配置須要的
maven配置好以後,就能夠進行dubbo配置:
#server.port=7010 dubbo.application.name=user-service-provider dubbo.registry.address=127.0.0.1:2181 dubbo.registry.protocol=zookeeper dubbo.protocol.name=dubbo dubbo.protocol.port=20882 dubbo.monitor.protocol=registry #dubbo.scan.base-packages=com.example.springboot.dubbo
用戶服務類:
package com.example.springboot.dubbo.service.impl; import com.example.spring.dubbo.bean.UserAddress; import com.example.spring.dubbo.service.UserService; import org.apache.dubbo.config.annotation.Service; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; @Service//暴露服務 @Component public class UserServiceImpl implements UserService { @Override public List<UserAddress> getUserAddressList(String userId) { UserAddress address1 = new UserAddress(1, "北京市昌平區", "1", "李老師", "010-56253825", "Y"); UserAddress address2 = new UserAddress(2, "深圳市寶安區", "1", "王老師", "010-56253825", "N"); return Arrays.asList(address1,address2); } }
Springboot的啓動類要加上@EnableDubbo註解:
package com.example.springboot.dubbo; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * <pre> * Springboot啓動類 * </pre> * * @author nicky * <pre> * 修改記錄 * 修改後版本: 修改人: 修改日期: 2020年01月05日 修改內容: * </pre> */ @EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl") @SpringBootApplication public class UserServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(UserServiceProviderApplication.class, args); } }
啓動Springboot類,而後在監控平臺是能夠看到服務註冊成功的
查看服務接口的詳細信息:
而後服務已經註冊了,如今建立一個消費者工程order-service-comsumer
<properties> <spring-boot.version>2.2.1.RELEASE</spring-boot.version> <dubbo.version>2.7.5</dubbo.version> <curator.version>2.12.0</curator.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>${curator.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>${curator.version}</version> </dependency> <dependency> <groupId>com.example.springboot</groupId> <artifactId>shop-api-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
server.port=8081 dubbo.application.name=order-service-consumer dubbo.registry.address=zookeeper://127.0.0.1:2181 dubbo.monitor.protocol=registry
package com.example.springboot.dubbo.service.impl; import com.example.spring.dubbo.bean.UserAddress; import com.example.spring.dubbo.service.OrderService; import com.example.spring.dubbo.service.UserService; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Service; import java.util.List; /** * <pre> * 訂單服務 * </pre> * * @author nicky * <pre> * 修改記錄 * 修改後版本: 修改人: 修改日期: 2020年01月05日 修改內容: * </pre> */ @Service public class OrderServiceImpl implements OrderService{ @Reference(loadbalance="random",timeout=1000) //dubbo直連 UserService userService; @Override public List<UserAddress> initOrder(String userId) { //一、查詢用戶的收貨地址 List<UserAddress> addressList = userService.getUserAddressList(userId); return addressList; } }
package com.example.springboot.dubbo; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * <pre> * Springboot啓動類 * </pre> * * @author nicky * <pre> * 修改記錄 * 修改後版本: 修改人: 修改日期: 2020年01月05日 修改內容: * </pre> */ @EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl") @SpringBootApplication public class OrderServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceProviderApplication.class, args); } }
寫一個Controller類進行測試:
package com.example.springboot.dubbo.controller; import com.example.spring.dubbo.bean.UserAddress; import com.example.spring.dubbo.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; @Controller public class OrderController { @Autowired OrderService orderService; @ResponseBody @RequestMapping("/initOrder") public List<UserAddress> initOrder(@RequestParam("uid")String userId) { return orderService.initOrder(userId); } }
在監控平臺看,消費者啓動也是能夠的
代碼例子下載:github下載連接