一、Web應用架構的演變
隨着互聯網的發展,網站應用的規模不斷擴大,Web應用架構也在不斷的演變
四個階段:單一應用、垂直應用、分佈式服務、流動計算
1.單一應用架構
當網站訪問量很小時,只需要一個應用程序,將所有的功能都部署在一起,以減少部署節點和成本
此時關鍵問題:簡化數據庫操作,數據訪問框架ORM是核心
適用場景:小型網站、管理系統、簡易辦公系統
侷限:
- 擴展性差
- 不便於協同開發
- 不利於升級維護
2. 垂直應用架構
當訪問量逐漸增大,單一應用(單機)負載太大,此時可以增加服務器來進行負載均衡,提高響應速度,即集羣
但是,當增加的服務器到達一定數據時所帶來的加速度會越來越小,此時單純的增加服務器已無法明顯提升響應速度
此時,需要將系統業務拆分成多個 互不相關的 系統,分別部署在獨立的服務器上,以提升效率,稱爲垂直應用
此時關鍵問題:加速前端頁面開發MVC框架(MVVM)
優點:通過拆分項目的業務,實現業務上的獨立,降低了開發和維護的難度,便於協同開發,提高了擴展性
侷限:每個垂直模塊中都有相同的內容(entity、dao、service、web),公共資源無法複用,且業務邏輯與界面無法分離
3. 分佈式服務架構
當垂直應用越來越多,應用之間的交互無法避免,有些業務系統無法完全拆分爲獨立系統。
此時,可以將核心業務抽取出現,作爲獨立的服務Service,逐漸的形成穩定的服務中心,使前端應用能夠更好的適應市場需要的變化。
此時關鍵問題:提高業務的利用以及整合分佈式服務框架RPC(Remote Procedure Call 遠程過程調用)
4. 流動計算架構
當服務越來越多,服務之間的調用和依賴關係也越來越複雜,誕生了面向服務聽架構體系(SOA: Service-Oriented Architecture )
容量的評估,小服務資源的浪費等問題開始出現,此時需要增加一個調度中心,基於訪問壓力實時的管理集羣容量,提高集羣利用率
此時關鍵問題:資源調度和治理中心,使用dubbo+zookeeper
二、RPC簡介
1. RPC是什麼
RPC:Remote Procedure Call 遠程過程調用
- 是一種進程間的通信方式
- 它允許應用程序調用網絡上的另一個應用程序中的方法
- 對於服務的消費者而言,無需瞭解遠程調用的底層細節,透明的
2. 執行流程
執行流程:
- 客戶端發起調用請求
- 客戶端存根 對請求參數(接口、方法、參數等)進行序列化(封裝)
- 客戶端存根向 服務器存根 發送消息
- 服務端存根 對接收到的消息 進行反序列化
- 服務端存根發送請求調用本地方法
- 服務器執行業務處理
- 服務器返回處理結果
- 服務端存根 對處理結果進行序列化
- 服務端存根 將結果返回給 客戶端存根
- 客戶端存根 對接收到的結果進行反序列化
- 客戶端存根 將結果返回給 客戶端
三、Dubbo簡介
1. Dubbo是什麼
Apache Dubbo是一款高性能的Java RPC框架(由阿里巴巴開發,開源貢獻給Apache)
提供了三個核心功能:
- 面向接口的遠程方法調用
- 智能容錯和負載均衡
- 服務自動註冊和發現
參考:官網 http://dubbo.apache.org
2. Dubbo體系結構
執行流程:
- Provider:服務的提供者,負責對外提供服務,提供者在啓動的時候,需要向Registry註冊自己能夠提供的服務
- Consumer:服務的消費者,消費者在啓動的時候,需要向Registry訂閱自己需要的服務
- Registry:註冊中心,授受註冊和訂閱,會異步的通知訂閱者,向消費者提供服務列表
- 當消費者需要執行遠程過程調用時,會從Registry獲取到服務地址列表(基於負載均衡算法)進行調用,如果調用失敗會重新選擇新的提供者再次調用
- Monitor:監控中心,統計服務的調用次數和調用時間,服務消費者和提供者會在內存中累計調用次數和調用時間,定時每分鐘向監控中心發送一次統計數據
具體業務流程:
四、使用Dubbo
1. Spring版
1.1 創建common工程
創建entity和service接口
1.2 創建provider工程
步驟:
-
添加依賴
<!--依賴於dubbon-common--> <dependency> <groupId>com.itany</groupId> <artifactId>dubbo-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springversion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${springversion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springversion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${springversion}</version> </dependency> <!--dubbo核心包--> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.2</version> </dependency> <!--使用zookeeper作爲註冊中心,在dubbo中會訪問zookeeper--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.13</version> </dependency> <!--zookeeper的客戶端實現--> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.1</version> </dependency>
-
編寫實現類
public class UserServiceImpl implements UserService { @Override public User findById(int id) { System.out.println("UserServiceImpl.findById"); User user = new User(); user.setId(id); user.setUsername("tom"); user.setPassword("123"); return user; } }
-
配置dubbo
<!--配置當前dubbo應用程序的名稱,可自定義,但必須唯一,一般使用項目名--> <dubbo:application name="dubbo-provider"/> <!--指定註冊中心地址--> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <!--配置dubbo協議和端口(通過該端口來提供服務)--> <dubbo:protocol name="dubbo" port="8888"/> <!--指定要暴露的服務接口--> <dubbo:service interface="com.itany.service.UserService" ref="userService"/> <bean id="userService" class="com.itany.service.impl.UserServiceImpl"/>
1.3 創建consumer工程
步驟:
-
添加依賴
同1.2
-
編寫使用類
@Controller public class UserController { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public void findUser(){ User user = userService.findById(1001); System.out.println(user); } } }
-
配置Dubbo
<dubbo:application name="dubbo-consumer"/> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <!--指定要引用的服務--> <dubbo:reference id="userService" interface="com.itany.service.UserService"/> <bean class="com.itany.controller.UserController"> <property name="userService" ref="userService" /> </bean>
1.4 測試
-
啓動zookeeper
-
編寫並運行provider
public static void main(String[] args) { ApplicationContext ac=new ClassPathXmlApplicationContext("classpath:provider.xml"); //阻塞線程 new Scanner(System.in).next(); }
-
編寫並運行consumer
public static void main(String[] args) { ApplicationContext ac=new ClassPathXmlApplicationContext("classpath:consumer.xml"); UserController userController = ac.getBean(UserController.class); userController.findUser(); //阻塞線程 new Scanner(System.in).next(); }
2. Spring註解版
2.1 改寫provider
<!--dubbo組件的掃包-->
<dubbo:annotation package="com.itany.service.impl"/>
<!--spring組件的掃包-->
<context:component-scan base-package="com.itany.service.impl"/>
// 方式1
// @Service
// @com.alibaba.dubbo.config.annotation.Service
// 方式2
@Component
@Service
public class UserServiceImpl implements UserService {
2.2 改寫consumer
<dubbo:annotation package="com.itany.controller"/>
<context:component-scan base-package="com.itany.controller"/>
@Controller
public class UserController {
// 使用dubbo的@Reference注入遠程服務對象
@Reference
private UserService userService;
3. SpringBoot版
3.1 創建provider工程
步驟:
-
添加依賴
<!--依賴於dubbo-common--> <dependency> <groupId>com.itany</groupId> <artifactId>dubbo-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--dubbo的starter--> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency>
-
編寫實現類
@Component @Service public class UserServiceImpl implements UserService { @Override public User findById(int id) { User user = new User(); user.setId(id); user.setUsername("alice"); user.setPassword("123"); return user; } }
-
配置dubbo
server: port: 8881 dubbo: application: name: boot-provider registry: address: zookeeper://127.0.0.1:2181 protocol: name: dubbo port: 8888
-
啓用dubbo
@SpringBootApplication @EnableDubbo //啓用dubbo public class BootProviderApplication { public static void main(String[] args) { SpringApplication.run(BootProviderApplication.class, args); } }
3.2 創建consumer
步驟:
-
添加依賴,同3.1
-
編寫使用類
@Controller @RequestMapping("/user") public class UserController { @Reference private UserService userService; @RequestMapping("/findUser") public String findUser(int id, Model model) { User user = userService.findById(id); model.addAttribute("user", user); return "success"; } }
-
配置dubbo
server: port: 8882 dubbo: application: name: boot-consumer registry: address: zookeeper://127.0.0.1:2181 spring: thymeleaf: cache: false
五、配置dubbo
1. 配置的覆蓋關係
dubbo屬性可以配置在如下六個位置:
- 消費者引用方法處
- 提供者暴露方法處
- 消費者引用接口處
- 提供者暴露接口處
- 消費者全局配置處
- 提供者全局配置處
它們的優先順序如下:
- 方法級優先,接口級次之,全局配置再次之。
- 如果級別一樣,則消費方優先,提供方次之
注:建議由服務提供者設置超時時間
2. 常用配置
配置項 | 作用 |
---|---|
timeout | 超時時間,單位爲毫秒, 默認1000ms |
retries | 重試次數,不包括第一次調用,默認爲2,0表示不重試 |
check | 啓動時檢查提供者是否存在,true表示不存在時報錯,false表示啓動時不檢查,默認爲true |
url | 點對點直連服務提供者,繞過註冊中心,以服務接口爲單位 |
六、監控中心
1. dubbo-admin
Dubbo的管理控制檯,可以對提供者和消費者進行管理,便於調試,發現問題,解決問題
下載:GitHub——>搜索dubbo-admin——>選擇master分支——>Download
配置:修改dubbo-admin目錄下的application.properties文件(指定註冊中心地址)
打包:mvn package
運行:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
訪問 :http://localhost:7001 默認用戶名和密碼都爲root
2. dubbo-monitor-simple
簡單的監控中心
配置:修改dubbo-monitor-simple目錄下的dubbo.properties文件(指定註冊中心地址)
打包:mvn package
運行:將生成的dubbo-monitor-simple-2.0.0-assembly.tar.gz解壓縮,運行解壓後assembly.bin/start.bat 或 start.sh
在提供者和消費者中配置,指定監控中心,可以定時每分鐘向監控中心發送一次統計數據
dubbo:
monitor:
protocol: registry # 配置監控中心,從註冊中心查找監控中心的地址
七、高可用性
通過對系統進行專門設計,從而減少停機時間,提高系統的高可用性
1. 負載均衡
1.1 簡介
將接收到的請求按照一定的規則(負載均衡算法)分發到不同的服務器進行處理,從而提高系統響應和處理速度,稱爲負載均衡 Load Balance
Dubbo提供了四種負載均衡策略:
-
Random LoadBalance 基於權重的隨機負載均衡(默認)
按照權重的比例,隨機選擇集羣中的服務器
-
RoundRobin LoadBalance 基於權重的輪循負載均衡
根據權重,按照一定的順序將請求分發給每個服務器(輪流提供服務)
-
LeastActive LoadBalance 最少活躍數的負載均衡
最少活躍調用數,活躍時間(請求的響應時間)較小的服務器會處理更多的請求
-
ConsistentHash LoadBalance 一致性hash的負載均衡
相同參數的請求總是發給同一臺服務器
1.2 操作
@Controller
@RequestMapping("/user")
public class UserController {
// 修改負載均衡策略
@Reference(loadbalance = "roundrobin")
private UserService userService;
修改權重的兩種方式:
- 修改暴露服務時的權重
- 動態調整權重
2. 服務降級
當服務器壓力劇增時根據實際業務情況及流量,對一些服務有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運行或高效運行。
簡單來說,就是將非核心服務進行降級,暫時性的關閉或延遲使用,保證核心服務的正常運行
Dubbo支持兩種服務降級:
-
mock=force:return+null
表示消費方對該服務的方法調用都直接返回null,不發起遠程調用
用來屏蔽不重要服務不可用時對調用方的影響
-
mock=fail:return+null
表示消費方對該服務的方法調用在失敗後,再返回null,不拋出異常
用來容忍不重要服務不穩定時對調用方的影響
八、補充:面試題
1. 高併發的處理
高併發如何優化?
- 負載均衡:集羣,通過多臺服務器進行負載均衡,提高響應和處理速度
- 動靜分離:使用Nginx實現,CDN 內容分發網絡
- 緩存:以空間換時間,提高系統效率
- 限流:即流量控制,將過量的請求先放到隊列中,等待一定時間後再從隊列中取出處理,類似於地鐵限流
- 降級:即服務降級
2. 集羣環境下session的處理
幾種解決方式:
-
Session保持:負載均衡進行請求分發時保證每個客戶端固定的訪問後端的同一臺服務器,如Nginx的ip_hash策略
優點:簡單,不需要對session做任何處理
缺點:無法保證負載絕對均衡
缺乏容錯性,如果當前訪問的服務器發生故障,用戶被轉移到第二個服務器上,此時他的session信息將失效
-
Session複製:將每個服務器的Session信息複製到其他服務器節點,保證Session的同步
缺點:如果Session量很大的話可能會造成網絡堵塞,拖慢服務器性能
- Session共享:將Session放到一個統一的地方,如可以放到數據庫中,實際中更推薦使用Redis或Memcached。
視頻課程鏈接:Dubbo快速入門視頻課程(通俗易懂)http://edu.51cto.com/course/16189.html