"TOC" 系統架構 概述 隨著互聯網的發展,網站應用的規模不斷擴大。需求的激增,帶來的是技術上的壓力。 系統架構也因此也不斷的演進、升級、迭代。 從單一應用,到垂直拆分,到分散式服務,到SOA,以及現在火熱的微服務架構 集中式架構 概述 當網站流量很小時,只需一個應用 將所有功能都部署在一起,以減 ...
目錄
系統架構
概述
隨著互聯網的發展,網站應用的規模不斷擴大。需求的激增,帶來的是技術上的壓力。 系統架構也因此也不斷的演進、升級、迭代。
從單一應用,到垂直拆分,到分散式服務,到SOA,以及現在火熱的微服務架構
集中式架構
概述
當網站流量很小時,只需一個應用 將所有功能都部署在一起,以減少部署節點和成本 從頭到尾就一個工程,部署的時候 , 只需要打成一個war包
特點
- 代碼耦合,開發維護困難
- 無法針對不同模塊進行針對性優化
- 無法水平擴展
- 單點容錯率低,併發能力差
垂直拆分
概述
當訪問量逐漸增大,單一應用無法滿足需求,此時為了應對更高的併發和業務需求,我們根據業務功能對系統進行拆分
特點
- 系統拆分實現了流量分擔,解決了併發問題
- 可以針對不同模塊進行優化
- 方便水平擴展,負載均衡,容錯率提高
- 系統間相互獨立,會有很多重覆開發工作,影響開發效率
系統架構分類
微服務
微服務就是把原本臃腫的一個項目的所有模塊拆分開來並做到互相沒有關聯,甚至可以不使用同一個資料庫
微服務的特點:
- 單一職責:微服務中每一個服務都對應唯一的業務能力,做到單一職責
- 服務拆分粒度很小:例如一個用戶管理就可以作為一個服務
- 面向服務:面向服務是說每個服務都要對外暴露服務介面API,並不關心服務的技術實現,做到與平臺和語言無關,不限定用什麼技術實現,只要提供Rest的介面即可
- 自治:自治是說服務間互相獨立,互不幹擾
分散式服務:
概述:
當垂直應用越來越多,應用之間交互不可避免,將核心業務抽取出來,作為獨立的服務
分散式,就是將偌大的系統劃分為多個模塊(這一點和微服務很像)部署到不同機器上 因為一臺機器可能承受不了這麼大的壓力
各個模塊通過介面進行數據交互,其實 分散式也是一種微服務。
特點:
- 將基礎服務進行了抽取,系統間相互調用,提高了代碼復用和開發效率
- 系統間耦合度變高,調用關係錯綜複雜,難以維護
微服務和分散式的區別:
微服務與分散式都是把模塊拆分開來變為獨立的單元,提供介面來調用
他們本質的區別在於目標的不同:
- 分散式的目標是:一臺機器承受不了的,或者是成本問題 , 不得不使用多台機器來完成服務的部署
- 微服務的目標 :只是讓各個模塊拆分開來,不會被互相影響,比如模塊的升級亦或是出現BUG等等...
微服務要面臨的問題:
- 服務治理(SOA)
概述:
當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現, 此時需增加一個調度中心基於訪問壓力實時管理集群容量,提高集群利用率。
(SOA)用於提高機器利用率的資源調度和治理中心
問題:
服務越來越多,需要管理每個服務的地址 調用關係錯綜複雜,難以理清依賴關係 服務過多,服務狀態難以管理,無法根據服務情況動態管理
服務治理要做什麼:
服務註冊中心,實現服務自動註冊和發現,無需人為記錄服務地址 服務自動訂閱,服務列表自動推送,服務調用透明化,無需關心依賴關係
動態監控服務狀態監控報告,人為控制服務狀態
- 監聽服務有沒有宕機:部署很多服務後 ,如果監聽到服務有沒有宕機
- 負載均衡:一個服務吃不消,要部署多個服務,部署的多個服務均衡調用
- 熔斷:服務出現了問題,不能讓程式卡在那裡
- 限流:限流就是針對超過預期的流量,通過預先設定的限流規則選擇性的對某些請求進行限流“熔斷”
- 降級:當伺服器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放伺服器資源以保證核心交易正常運作或高效運作
- 網關:統一管理API的一個網路關口、通道,是整個微服務平臺所有請求的唯一入口
springClould是什麼
微服務只是一種項目的架構方式,或者說是一種概念
Spring-Cloud便是對這種技術的實現
對微服務面臨的問題進行統一的封裝處理
遠程調用方式:
RPC:
- Remote Produce Call遠程過程調用,類似的還有RMI。自定義數據格式,基於原生TCP通信,速度快,效率高
- 早期的webservice,現在熱門的dubbo,都是RPC的典型
- 限制了平臺,只能是Java平臺
Http:
- http其實是一種網路傳輸協議,基於TCP,規定了數據傳輸的格式
- 現在客戶端瀏覽器與服務端通信基本都是採用Http協議。也可以用來進行遠程服務調用。缺點是消息封裝臃腫
- 不限制平臺
模擬微服務:
- 創建一個普通父工程,刪除src目錄,保留pom文件
- 在父工程當中添加springboot依賴
代碼:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
</parent>
- 創建子模塊user
- 添加springboot-web啟動器依賴
代碼:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 創建user工程啟動類UserApplication
代碼:
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
- 創建util包,把ResponseResult工具類複製到該包中
代碼:
public class ResponseResult extends HashMap {
public static String SUCCESS_CODE = "200";
public static String ERROR_CODE = "500";
public static String DATA_KEY = "data";
public static String MSG_KEY = "msg";
private ResponseResult() {
}
public ResponseResult set(String key, Object object) {
super.put(key, object);
return this;
}
private static ResponseResult newResponseResult() {
return new ResponseResult();
}
public static ResponseResult success() {
return ResponseResult.newResponseResult()
.set("code", ResponseResult.SUCCESS_CODE)
.set(ResponseResult.MSG_KEY, "操作成功");
}
public static ResponseResult success(String msg) {
return ResponseResult.newResponseResult()
.set("code", ResponseResult.SUCCESS_CODE)
.set(ResponseResult.MSG_KEY, msg);
}
public static ResponseResult success(String msg, Object object) {
return ResponseResult.newResponseResult()
.set("code", ResponseResult.SUCCESS_CODE)
.set(ResponseResult.MSG_KEY, msg)
.set(ResponseResult.DATA_KEY, object);
}
public ResponseResult data(Object obj) {
return this.set("data", obj);
}
public static ResponseResult error() {
return ResponseResult.newResponseResult()
.set(ResponseResult.MSG_KEY, "操作失敗")
.set("code", ResponseResult.ERROR_CODE);
}
public static ResponseResult error(String msg) {
return ResponseResult.newResponseResult()
.set(ResponseResult.MSG_KEY, msg)
.set("code", ResponseResult.ERROR_CODE);
}
public static ResponseResult error(String msg, Object object) {
return ResponseResult.newResponseResult()
.set(ResponseResult.MSG_KEY, msg)
.set(ResponseResult.DATA_KEY, object)
.set("code", ResponseResult.ERROR_CODE);
}
}
- 創建子包controller,在controller當中創建UserController
代碼:
@RestController
public class UserController {
@RequestMapping("/getUser.do")
public ResponseResult getUser() {
return ResponseResult.success("返回成功","myUser");
}
}
- 在resources目錄下創建application.yml
- 啟動訪問http://localhost:5000/getUser.do
- 創建子模塊goods
- 配置和user一樣,修改server-port埠為:5001
- 啟動訪問http://localhost:5001/getGoods.do
- user工程調用goods工程當中的介面:
在UserApplication中添加RestTemplate的Bean
代碼:
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
在user工程的UserController當中註入restTemplate
通過restTemplate實現工程之間的介面調用
同時運行兩個工程, 訪問http://localhost:5000/getGoods.do
以上操作就實現了兩個工程之間的調用
使用nginx實現集群搭建
- 下載nginx 網址:nginx下載地址
下載後解壓:註意解壓目錄不要帶有中文 - 創建一個新的goods1工程 和goods一模一樣 只需要改埠號即可,用於搭建集群。
- 修改nginx的配置文件
把之前的server的代碼刪掉,替換成這樣
代碼:
upstream mServer {
server localhost:5001;
server localhost:5002;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
proxy_pass http://mServer;
}
-
配置完成後啟動nginx.exe
啟動會一閃而過 屬於正常情況 -
把user中調用方的埠號改為80
-
啟動user,goods,goods1 訪問user的地址:http://localhost:5000/getGoods.do
會發現每次刷新訪問,都會返回兩個不同的工程的controller,完成集群的搭建。
存在問題, 如果其中的一個服務停止了, 當訪問的時候 , 會出現有時會很慢的情況
解決方案:用到SpringCloud的Eureka註冊中心來管理我們的服務
下次更新 Spring-Cloud-Netflix-Eureka的使用方法