1、架構發展過程前端
首先,咱們先來看看上面的架構發展的線路圖:單一應用架構 --> 垂直應用架構 --> 分佈式服務架構 --> 流動計算架構 。web
單一應用架構算法
在一些中小型的傳統軟件公司中,一個 產品/項目 的全部的代碼都在一個工程裏,工程下面有多個不一樣的模塊。在部署的時候,將整個工程打包而後放到服務器 Tomcat 下來運行。而後,爲了所謂的「高可用」,會使用一臺負載均衡服務器(好比Nginx),而後將應用部署到兩到三臺服務器上。至於系統的依賴可能只有一個,就是相似於 MySQL、Oracle 這類的關係型數據庫,會單獨部署在一臺服務器上,讓系統來使用。就以下面這個圖:spring
對於這種單一應用的架構,隨着業務量的增加,雖然也能夠進行擴展,可是擴展的每臺服務器上都部署了全部的功能,假如只須要擴展交易能力而其餘模塊的功能不須要擴展呢?這種單一架構的系統就沒辦法解決,因此後面就出現了垂直應用架構。 數據庫
從研發團隊人數的發展來看,這種架構模式也是愈來愈不靠譜的。若是研發團隊有幾十人甚至上百人一塊兒研發這個系統,業務邏輯複雜,功能模塊多達幾十上百個,你們都在一個工程內寫代碼,大量的衝突以及代碼的合併都會讓人崩潰。並且測試也會很是痛苦,好比某個功能模塊要上線了,就必須得把整個單塊系統全部的功能都回歸測試一遍纔敢上線。由於你們的代碼都在一個工程裏,都是耦合在一塊兒的,你修改了代碼,必須所有測試一遍才能保證系統正常。apache
垂直應用架構編程
隨着業務量的增長,單一應用的架構就愈來愈不適合了,這時候就誕生了垂直應用架構,將整個系統拆成好幾個單獨的應用,提高了效率,擴容的時候也可以對對應的業務進行精準的擴容。緩存
這種垂直應用架構的模式雖然將每一個模塊都拆分開了,可是每一個模塊內部仍是有很是多的功能,好比說用戶中心當中可能會有:註冊、登陸、密碼校驗等等功能,密碼校驗可能會比註冊和登陸使用頻繁得多,這個時候咱們是否要考慮將每個模塊的單體功能再進行拆分,而後就變成了下面這個樣子:tomcat
當拆分得愈來愈多,達到幾十上百甚至上千個的時候,這種垂直應用架構就不能很好的支撐系統的運行,因此就出現了分佈式服務架構。springboot
分佈式服務架構
當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。用於提升業務複用及整合的分佈式調用是關鍵。
2、分佈式&集羣&RPC
分佈式:一個電商系統,用戶模塊部署在 Server1, 訂單模塊部署在 Server2, 促銷模塊部署在 Server3, 商品模塊部署在 Server4,他們之間經過遠程rpc實現服務調用,這就叫分佈式。強調的是不一樣功能模塊,單獨部署在不一樣的 Server 上,全部 Server 加起來是一個完整的系統。
集羣:更多強調的是災備,一個電商系統,完整的部署在Server1上一個,完整的部署在Server2上一個,Server1宕機後,Server2仍然能夠正常提供請求服務,這叫集羣。一樣對於某一功能模塊,好比用戶模塊部署在 Server1上,一樣部署在 Server2上,也叫作集羣。分佈式系統的每一個功能模塊節點,均可以用多機作成集羣。
RPC:Remote Procedure Call,遠程過程調用,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。舉個例子說明:兩臺服務器 A、B,分別部署不一樣的應用 a 和 b。當A服務器上的應用 a 想要調用B服務器上的應用 b 提供的方法的時候,因爲不在一個內存空間,不能直接調用,須要經過網絡來表達調用的語義傳達調用的數據,這個時候就出現了一個遠程服務調用的概念。
常見RPC框架:
3、Dubbo架構
Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。
節點角色說明
節點 | 角色說明 |
---|---|
Provider |
暴露服務的服務提供方 |
Consumer |
調用遠程服務的服務消費方 |
Registry |
服務註冊與發現的註冊中心 |
Monitor |
統計服務的調用次數和調用時間的監控中心 |
Container |
服務運行容器 |
調用關係說明
Dubbo的特色:
連通性
健壯性
伸縮性
升級性
當服務集羣規模進一步擴大,帶動IT治理結構進一步升級,須要實現動態部署,進行流動計算,現有分佈式服務架構不會帶來阻力。下圖是將來可能的一種架構:
節點角色說明
節點 | 角色說明 |
---|---|
Deployer |
自動部署服務的本地代理 |
Repository |
倉庫用於存儲服務應用發佈包 |
Scheduler |
調度中心基於訪問壓力自動增減服務提供者 |
Admin |
統一管理控制檯 |
Registry |
服務註冊與發現的註冊中心 |
Monitor |
統計服務的調用次數和調用時間的監控中心 |
4、Zookeeper
Dubbo 將註冊中心進行抽象,使得它能夠外接不一樣的存儲媒介給註冊中心提供服務,有ZooKeeper,Memcached,Redis等。
Dubbo的註冊、訂閱、通知等功能不是由 Dubbo自己來實現的,而是藉助於這些存儲媒介來實現的。
ZooKeeper的特性
5、Dubbo環境搭建
一、Zookeeper
下載
https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/
安裝
解壓安裝包,而後將 conf 目錄下的 zoo_sample.cfg 改成 zoo.cfg 便可。
啓動
進入 Zookeeper 安裝目錄下的 bin 目錄,執行如下命令
./zkServer.sh start
鏈接
./zkCli.sh -server IP:端口
二、引入依賴
compile('com.alibaba:dubbo:2.6.6') compile('io.netty:netty-all:4.1.34.Final') compile('org.apache.zookeeper:zookeeper:3.4.14') compile('org.apache.curator:curator-framework:2.13.0') compile('org.apache.curator:curator-recipes:2.13.0')
三、建立三個工程
dubbo-order-iface
建立兩個實體類 Order 和 RegMsg,以及一個對外提供的接口 IOrderService
@Getter @Setter @ToString public class Order implements Serializable { private String orderId; private Integer amount; private String orderInfo; }
@Getter @Setter @ToString public class RegMsg implements Serializable { private String errorNo; private String errorMsg; public RegMsg(String errorNo, String errorMsg) { this.errorNo = errorNo; this.errorMsg = errorMsg; } }
這兩個實體類必須實現 Serializable,由於它要在不一樣的進程之間傳輸,須要進行序列化和反序列化
public interface IOrderService { RegMsg creatOrder(Order order); }
注意:該工程需單獨打包,發到中央倉庫,供服務提供方和消費方使用(以 jar 包的方式引入)
dubbo-order-provider(服務提供者)
服務提供者實現 IOrderService 接口
public class OrderServiceImpl implements IOrderService { @Override public RegMsg creatOrder(Order order) { System.out.println("OrderServiceImpl -> create order: " + order); return new RegMsg("200","create order success!!"); } }
用 Spring 配置聲明暴露服務
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方應用信息,用於計算依賴關係 --> <dubbo:application name="dubbo-order-provider" /> <!-- 使用zookeeper註冊中心暴露服務地址 --> <dubbo:registry address="zookeeper://192.168.182.128:2181" /> <!-- 用dubbo協議在20880端口暴露服務 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 和本地bean同樣實現服務 --> <bean id="orderService" class="com.dubbo.order.provider.service.OrderServiceImpl" /> <!-- 聲明須要暴露的服務接口 --> <dubbo:service interface="com.dubbo.order.iface.service.IOrderService" ref="orderService" /> </beans>
加載 Spring 配置
public class ProviderApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml"); context.start(); try { // 按任意鍵退出 System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
dubbo-order-consumer(服務消費者)
經過 Spring 配置引用遠程服務
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方同樣 --> <dubbo:application name="dubbo-order-consumer" /> <!-- 使用zookeeper註冊中心暴露發現服務地址 --> <dubbo:registry address="zookeeper://192.168.182.128:2181" /> <!-- 生成遠程服務代理,能夠和本地bean同樣使用demoService --> <dubbo:reference id="orderService" interface="com.dubbo.order.iface.service.IOrderService" /> </beans>
加載Spring配置,並調用遠程服務
public class ConsumerApp { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml"); context.start(); // 獲取遠程服務代理 IOrderService orderService = context.getBean("orderService", IOrderService.class); Order order = new Order(); order.setOrderId("1"); order.setAmount(1024); order.setOrderInfo("dubbo create order"); // 執行遠程方法 RegMsg regMsg = orderService.creatOrder(order); // 顯示調用結果 System.out.println("regMsg = " + regMsg); } }
6、Dubbo配置
一、啓動時檢查
check="true"
。check="false"
關閉檢查,好比,測試時,有些服務不關心,或者出現了循環依賴,必須有一方先啓動。check="false"
,老是會返回引用,當服務恢復時,能自動連上。示例:經過Spring 配置文件
關閉某個服務的啓動時檢查:
<dubbo:reference id="orderService" check="false" interface="com.dubbo.order.iface.service.IOrderService" />
關閉全部服務的啓動時檢查:
<dubbo:consumer check="false" />
關閉註冊中心啓動時檢查:
<dubbo:registry check="false" />
二、超時重試
<dubbo:reference id="orderService" timeout="3000" retries="3" interface="com.dubbo.order.iface.service.IOrderService" />
上面配置了超時時間爲3秒,重試3次,若是一直超時,會請求四次。
咱們配置超時和重試前,下面這些狀況是要充分考慮的
超時:
對外提供的服務,超時時間設的比較長,實際狀況倒是:服務時間出現抖動,外部鏈接比較多,可能會把該服務給拖垮(瞬間有大量的鏈接進來,可是服務又消化不掉)。因此超時時間的設置應該充分考慮整個鏈路的時間。
重試:
對外提供的服務,是否應該支持重試,是否有必要重試。好比說:訂單業務,重試也不能形成重複下單,要作好內部惟一性校驗,要作到徹底相同的請求在數據庫的落地只有一單。
7、SpringBoot整合Dubbo
一樣是下面建立三個工程
dubbo-order-iface
這個工程和上面的同樣,沒有變化
dubbo-springboot-provider
引入依賴
dependencies { compile project(':dubbo-order-iface') // dubbo須要的starter compile('com.alibaba.spring.boot:dubbo-spring-boot-starter:2.0.0') implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-aop') testImplementation('org.springframework.boot:spring-boot-starter-test') }
服務提供者實現 IOrderService 接口
@org.springframework.stereotype.Service @com.alibaba.dubbo.config.annotation.Service public class OrderServiceImpl implements IOrderService { @Override public RegMsg creatOrder(Order order) { System.out.println("springboot OrderServiceImpl->createOrder, order=" + order); return new RegMsg("3000", "create success!!!"); } }
用 yml文件配置聲明暴露服務
server: port: 8001 servlet: context-path: /provider tomcat: accesslog: enabled: true dubbo: application: name: dubbo-springboot-provider registry: address: 192.168.182.128:2181 protocol: zookeeper protocol: name: dubbo port: 20880
加載 Springboot 配置
@SpringBootApplication @EnableDubbo public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
dubbo-springboot-consumer
引入依賴
dependencies { compile project(':dubbo-order-iface') // dubbo須要的starter compile('com.alibaba.spring.boot:dubbo-spring-boot-starter:2.0.0') implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-aop') testImplementation('org.springframework.boot:spring-boot-starter-test') }
實現一個 Controller 調用方法
@Slf4j @RestController @RequestMapping("/order") public class OrderController { @Reference private IOrderService orderService; @RequestMapping("/createOrder") public RegMsg createOrder(Integer amount) { log.info("createOrder start. amount={}", amount); Order order = new Order(); order.setAmount(amount); order.setOrderInfo("time:" + LocalDateTime.now()); order.setOrderId(System.currentTimeMillis() + ""); return orderService.creatOrder(order); } }
經過 yml文件配置引用遠程服務
server: port: 8002 servlet: context-path: /consumer tomcat: accesslog: enabled: true dubbo: application: name: dubbo-springboot-consumer registry: address: 192.168.182.128:2181 protocol: zookeeper
注意:consumer的端口要和provider不同
加載Springboot配置,並調用遠程服務
@SpringBootApplication @EnableDubbo public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }