微服務架構的規劃
人只有獻身於社會,才能找出那短暫而有風險的生命的意義。
——愛因斯坦
1、前言
本節主要跟大家聊聊如何去規劃一個項目的架構,平時工作當中,很多同學接觸到的項目都是現成的,由專門人員搭建好之後,自己在其基礎上進行開發,自己也從來沒想過爲什麼是這樣的架構,這樣的架構有什麼缺點,有沒有更好的方案等等,就只管編寫自己的代碼。時間長了,感覺寫代碼真的很簡單,一旦你真感覺寫代碼很簡單的時候,其實是在提醒你要學習了,否則很容易就會進入舒適區。有時候,你看似很簡單的問題,但是真要自己動手去搭建一遍,發現遇到的問題很多。
首先,我們梳理一個項目的完整開發流程大概是什麼樣的?
階段 1: 需求的規劃、原型圖的設計;這部分工作一般是產品和美工完成的,主要目的是把虛擬的東西變成一個感觀可見的東西。
階段 2: 需求分析設計階段,主要是把需求文檔的文字梳理成各個模型,包括架構圖設計、流程圖設計等。這個環節非常的重要,如果跳過該環節直接進入代碼實戰,則往往事倍功半。
階段 3: 代碼實戰,就是擼代碼階段
階段 4: 功能測試,大家都是熟悉的。包括:接口聯調、測試環境測試、灰度測試
階段 5: 項目上線
上面的流程大家應該都不陌生,作爲開發人員,我們比較熟悉的應該是階段2
和階段3
;我們的本節的重點就是階段2
需求的分析和設計。其實在這個階段,開發人員通過畫項目的架構圖、各個業務的詳細流程圖,很多難點都會在流程圖上體現出來,再針對難點做技術方案的選型等;這個步驟做好之後,那麼代碼階段就會非常的簡單,只需要按照標準去實現即可。
思考:規劃系統架構需要考慮哪些問題呢?
①架構模式
- 一般根據項目的預估併發量、項目的規模來選擇合適的架構,通常分爲單體架構、垂直架構、SOA 架構、微服務架構。
②技術選型
- 技術選型通常分爲基礎的開發框架(比如:ssm、SpringBoot+MyBatis 等)、分佈式架構本身所引起的技術難點(比如:服務治理、網關、配置中心等等)、具體業務場景選擇什麼樣的解決方案(這個實戰部分會深入分析)。
- 同種類型的框架如何選擇,比如:消息隊列的主流框架有 ActiveMQ、RabbitMQ、RocketMQ、Kafka 等,我們應該選擇哪款框架。
- 必須熟悉分佈式架構常見的問題及解決方案,比如:服務治理問題、自動化部署、系統的穩定性(容錯、限流)、分佈式事務、分佈式鎖等等。
③部署架構
- 根據預估流量、接口壓測,來選擇具體的部署架構方案,是選擇做單節點部署還是集羣部署,是傳統的部署還是容器化部署。
2、項目架構的規劃
2.1、架構模式
瞭解一下單體模式:
無論開發的時候,分多少個子項目,上線的時候,只打成一個包進行部署的項目就是單體項目。
單體項目模式 1:
platform (項目名稱)
|-- src/main/java
| |-- com.micro.utils (工具包)
| |-- com.micro.modules
| |-- com.micro.modules.user (用戶模塊)
| | |-- UserController.java
| | |-- UserService.java
| | |-- UserServiceImpl.java
| | |-- UserDao.java
| |-- com.micro.modules.order (訂單模塊)
| | |-- OrderController.java
| | |-- OrderService.java
| | |-- OrderServiceImpl.java
| | |-- OrderDao.java
| |-- com.micro.modeules.goods (商品模塊)
| | |-- GoodsController.java
| | |-- GoodsService.java
| | |-- GoodsServiceImpl.java
| | |-- GoodsDao.java
- 描述:通過包名來區分不同的模塊
- 優點:項目架構簡單
- 缺點:①所有的模塊代碼嚴重耦合一起,代碼非常的臃腫;②技術受限,不可以靈活的選擇合適的開發語言;③整體運行性能較低
單體項目模式 2:
platform
|-- platform-user (用戶工程)
|-- platform-order (訂單工程)
|-- platform-goods (商品工程)
- 描述:開發過程中把一個大的項目拆分多個子項目;但是最後是打包成一個項目來進行部署
- 優點:相比上面的模式,項目做了拆分,可以實現代碼的重複性利用
- 缺點:①還是技術受限,所有工程必須遵守統一技術規範,否則無法整合;②整體運行性能較低
瞭解一下分佈式(微服務)模式:
- 描述:把一張完整項目拆分多個獨立運行的服務,可以是每個服務獨立自己的數據庫、也可以共用一個數據庫。
- 優點:①每個服務的功能單一;②運行速度快;③開發和迭代週期短;④技術選型比較靈活
- 缺點:①服務數量較多;②部署複雜度提高;③會引起很多的其他問題(下面詳細分析)
大型項目都會選擇微服務的架構模式,架構模式是,前後端分離 + 後端微服務架構,具體如下:
- 相信很多老程序員都接觸過 jsp 這玩意,它是一種模板引擎技術,前後端分離之前,基本上都是使用它來開發的頁面。jsp 雖然內置了好多的標籤,開發起來也比較方便。但是分工責任問題,讓前端和後端開發人員合作起來相對比較麻煩。前端開發好 html 頁面丟給後端整合成 jsp,這中間出現各種樣式問題、兼容性問題等等。因此前後端分離讓項目開發起來效率更加高,畢竟專業的人做專業的事。
思考:微服務架構會存在哪些問題呢?
1)穩定性問題
服務網穩定性問題,主要來自於以下幾個方面。
①高併發訪問、或者突發流量、惡意攻擊等;
- 可以採用限流、容錯、防惡意攻擊的方式保護服務,比如:前端加驗證碼、IP 控制、網關限流、消息隊列限流、服務限流。
②由於服務的數量很多、關係複雜,其中一個服務出問題,就可能導致雪崩效應。
- 爲了防止服務之間的雪崩效應,最常見解決方案就是,服務容錯及降低,主要是當調用的服務出問題時,返回默認值。
③分佈式事務問題,這個是服務拆分必然引起的問題。
- 原來單體項目模式,則所有操作屬於同一個事務,數據一致性得到了保證,但是微服務模式下,則不在同一個事務下了,需要解決分佈式事務的問題。
④爲了更好的保護我們的服務,我們需要在所有服務前面加上一層網關,它的核心功能是請求轉發、認證、鑑權、限流。
⑤接口調用冪等性問題,比如:接口消費方超時時間是 2s,但是此時接口提供方出現卡頓了,處理花了 5s,此時消費方會發起接口重試,就會導致重複執行。
⑥網絡延遲、連接假死等引起遠程通訊問題
2)通訊問題
服務之間通訊,如果使用傳統的 HttpClient、WebService 肯定是滿足不了的,因爲服務之間互相通訊,複雜度更加的高,比如:集羣模式需要動態新增節點、負載均衡、服務容錯等,一般得集成服務治理框架(Dubbo 等)。
3)部署問題
服務數量很多,並且服務器數量也很多的情況下,手工部署效率會非常的低,一般都是自動化部署和自動化擴容;然而項目部署肯定需要修改項目的配置信息,因此需要依賴一個叫配置中心的中間件。
4)錯誤定位問題
日誌文件散落在各個服務器,如何快速定位異常信息呢?如果依靠手工去每臺服務中查看日誌信息,則效率非常的慢。因此需要集成日誌採集、存儲、分析框架,比如:ELK 技術棧。除此之外,爲了提高效率,建議做以下兩個小操作。
-
最好自定義異常類,這樣可以更加快速的定位異常地方。
-
很難篩出指定請求的全部相關日誌,以及下游服務調用對應的日誌,因此建議使用一個 traceId 跟蹤請求的全部路徑。
5)鏈路追蹤問題
服務之間互相依賴,方法之間調用,可能是層層調用,複雜度很高,導致系統上線之後,爲如何定位異常、性能監控等帶來難題,因此我們需要使用這方面的開源中間件來監控,比如:Zipkin 等。
通過上面分析微服務存在的問題和解決方案,我來大致描繪一下微服務的架構圖,具體如下:
架構圖分析說明
- ①綠色部分需要做限流,可以使用 RateLimiter 框架,也可以使用阿里 Sentinel 框架
- ②紅色部分
容錯
,表示的是服務之間的接口調用(rpc 遠程調用),需要容錯機制,否則其中一個服務出問題了,可能引起一片服務產生問題,也就是常說的雪崩效應 - ③紅色部分
日誌採集
,一般採用埋點的方式進行日誌採集,也就是說提供一個 jar 給服務集成,底層採用 Aop 的模式進行收集信息,這個後面實戰部分會詳細講解 - ④配置中心,目的是把經常變動的配置信息由項目抽離到配置中心,方便後期在線修改,常見框架有 Nacos、Apollo
- ⑤註冊中心,目的是做服務地址管理,一般是跟 rpc 框架結合使用,例如:Dubbo
2.2、技術選型
上面我們瞭解完整個微服務的架構圖了,這裏我們主要講解微服務涉及的技術棧及相應的解決方案是什麼。
目前主流的微服務技術方案,主要是 SpringCloudNetflix 和 SpringCloudAlibaba 兩個派系,SpringCloudNetflix 的話,它會有針對每個場景都有具體的解決方案。這裏主要講解以阿里係爲主的解決方案說明。
序號 | 解決方案 | 落地技術 |
---|---|---|
1 | 服務網關 | Nginx,注意的是 Zuul 和 Gateway 不適合 Dubbo,它依賴 Eureka |
2 | 限流框架 | Sentinel |
3 | 容錯框架 | Sentinel |
4 | 配置中心 | Nacos |
5 | 分佈式事務 | seata |
6 | 服務治理 | Dubbo+Zookeeper |
7 | 鏈路追蹤 | Zipkin |
8 | 接口冪等性 | 可以全局 ID 手工實現 |
9 | 日誌管理 | 一般使用 ELK 技術棧,進行日誌的採集、存儲、分析、展示 |
以上只是最基本的微服務技術棧,還有一些常見業務場景的解決方案,具體如下:
序號 | 業務點 | 技術 |
---|---|---|
2 | 分佈式文件系統 | FastDFS、HDFS |
2 | 分佈式鎖 | Zookeeper、Redis |
3 | 消息隊列 | ActiveMQ、RabbitMQ、RocketMQ、Kafka |
4 | 全文檢索引擎 | Solr、ElasticSearch |
5 | 分佈式緩存 | Redis |
9 | 過期監聽 | Redis 過期監聽、延遲隊列 |
10 | 消息推送 | WebSocket、Netty |
2.3、部署架構
一般情況下,高併發的系統部署架構都會採用分佈式集羣部署,主要核心是解決以下方面的問題
- ①提高系統性能,一般需要使用多層負載均衡的方式解決流量分散,負載均衡的含義,其實就是把用戶的請求,根據某種算法均攤到不同的服務器身上,減輕單臺服務器的壓力,是提高系統性能的常見手段。
- ②節點容災,也稱爲服務高可用,例如:只有一個 Nginx 對外提供服務,如果該 Nginx 掛掉之後,則整個項目無法對外提供正常服務,因此需要做節點高可用。特殊說明,負載均衡其實也是解決高可用其中一種方式;可以使用 Keepalived 來實現節點高可用,可以參考部署篇,裏面有這部分的詳細講解。
- ③服務器災備,服務器是會宕機的,服務器宕機之後,裏面的所有服務都失效了,一般使用 docker-swarm、k8s 去做災備。
- ④數據備份,數據安全是非常重要的,很多小公司做備份,使用人工備份或者定時備份,其實這是不夠安全的,比如說:機房發生火災,那麼數據將全部丟失,因此需要做一個異地備份(雙機房備份),參考後面 MySQL 主從章節。
負載均衡部署架構圖:
-
①OSPF (開放式最短鏈路優先) 是一個內部網關協議 (Interior Gateway Protocol, 簡稱 IGP)。OSPF 通過路由器之間通告網絡接口的狀態來建立鏈路狀態數據庫,生成最短路徑樹,OSPF 會自動計算路由接口上的 Cost 值,但也可以通過手工指定該接口的 Cost 值,手工指定的優先於自動計算的值。
OSPF 計算的 Cost,同樣是和接口帶寬成反比,帶寬越高,Cost 值越小。到達目標相同 Cost 值的路
徑,可以執行負載均衡,最多 6 條鏈路同時執行負載均衡。
-
②LVS 負載,Lvs 是第四層負載(tcp/ip 協議)
-
③Nginx 負載,Nginx 主要是用於搭建 Tomcat 負載均衡集羣,它是第七層負載(http 協議)
-
如果有條件,也可以使用 F5 負載,成本比較高
3、案例分析
通過上面的分析,相信大家對微服務也有了一個瞭解了,這裏主要是以網盤系統爲案例講解如何規劃它的架構。
首先大概瞭解網盤系統的核心功能(可以登錄系統查看)。網盤主要分爲三個核心部分:網盤後臺、個人文件的管理、以及對接應用系統;它的客戶端類型分爲好多種(比如:網頁版、h5 版本、app 版本等)。那麼我們如何架構網盤的項目架構呢?
方案 1:垂直架構
- 描述:網盤系統和後臺管理系統都是獨立的工程,操作同一份數據庫;
- 缺點:如果有相同的接口,則重複在兩個工程裏面實現;所有功能都在單體項目裏面實現了。
方案 2:微服務架構 1
- 描述:把 controller 工程和 service 工程獨立,遠程調用接口
- 優點:共用同一個接口工程,controller 工程變的很薄
- 缺點:Controller 工程拆分粒度比較粗
方案 3:微服務架構 2
- 描述:把 controller 工程和 service 工程獨立,並且 controller 根據客戶端類型再細分,遠程調用接口
- 優點:拆分粒度更細,controller 工程變的更薄
- 缺點:工程數量比較多
方案 4:微服務架構 3
- 描述:controller 根據客戶端類型拆分,Service 也拆分成主要業務和非主要業務並通過 MQ 解耦,總體拆分粒度比較細
- 優點:拆分粒度更細,整體性能更高
- 缺點:工程數量比較多
總結:關於工程拆分粒度的總結
①controller 拆分,一般根據根據業務來拆分(比如:訂單、商品);或者客戶端類型來拆分
②service 拆分,一般根據業務來拆分(比如:訂單服務、商品服務);或者根據主要業務和輔助業務拆分(主要目的是提高主要業務的處理速度,快速響應用戶)
總結,其實項目的架構不一定是一步就到位的,我們按照項目的規模、按照項目的併發量來進行選擇。以上四種模式就是架構的一個逐步升級的過程,根據實際情況來選擇合適的架構。
思考:比如,一個網站的首頁應該怎麼規劃呢?網站首頁的功能非常的多,涉及的服務非常的多。
方案 1:
- 描述:整個網站只對應一個 Controller 工程,由 controller 工程再具體調用不同的服務;
- 優點:只有一個 Controller,相對簡單
- 缺點:如果 Controller 掛了則整個網站就訪問不了了(當然可以做集羣);無法很好解耦,比如說:秒殺壓力很大,則所有模塊都會受秒殺模塊的影響;如果系統升級的時候,所有模塊都受影響。
方案 2:
- 描述:網站的不同模塊對應不同的 Controller 工程,
- 優點:這樣壓力也均攤到不同 Controller 上,每個 Controller 工程的後期迭代升級、項目部署都互不干擾。適合更加大型的項目
- 缺點:架構變的更加龐大了和複雜了。
4、小結
本節主要介紹微服務架構的模式,微服務面臨的問題及它的技術解決方案,微服務總體架構圖,以及通過案例來分析微服務架構圖。