微服務架構與實踐及雲原生等相關概念
微服務架構與實踐
筆記:《微服務架構與實踐》 王磊 著
一 單塊架構
1 定義:對於這種功能集中、代碼和數據中心化、一個發布包、部署後運行在同一進程的應用程序,我們通常稱之為單塊架構應用,並非物理上的分層。
2 單層架構:數據 邏輯 頁面 混合
3 三層架構:
1)表示層:數據顯示和用戶交互
2)業務邏輯層:業務邏輯處理
3)數據訪問層:數據存儲訪問
4 優勢: 比較適合小項目
易於開發:開發簡單直接,集中式管理,基本不會重復開發,集成工具適合
易於測試:單進程
易於部署:單項目包,功能都在本地,沒有分布式的管理開銷和調用開銷
易於水平伸縮:發布相同的項目包,部署多個運行環境,使用負載均衡器分發,克隆
5 挑戰:
開發效率低:所有的開發在一個項目改代碼,遞交代碼相互等待,代碼沖突不斷
代碼維護難:代碼功能耦合在一起,新人不知道何從下手
部署不靈活:構建時間長,任何小修改必須重新構建整個項目,這個過程往往很長
穩定性不高:一個微不足道的小問題,可以導致整個應用掛掉
維護成本增加:功能多,團隊大,管理復雜,缺陷修復容易導致新的缺陷問題
持續交付周期長:
技術選型成本高:采用統一的技術平臺或方案開發,當嘗試引入新的框架、技術或對技術站升級會面臨不小的風險。技術變化快,平滑完成替代較難。
可擴展性差:無法滿足高並發情況下的業務需求
構建全功能團隊難:單塊架構往往以技能為單位進行分組,如前端、業務層、數據庫團隊等。
二 微服務架構
微服務架構是一種架構模式,它提倡將單一應用程序劃分成一組小的服務,服務之間互相協調、互相配合,為用戶提供最終價值。每個服務運行在其獨立的進程中,服務與服務間采用輕量級的通信機制互相溝通(通常是基於HTTP的RESTful API)。每個服務都圍繞著具體業務進行構建,並且能夠被獨立地部署到生產環境、類生產環境等。另外,應盡量避免統一的、集中式的服務管理機制,對具體的一個服務而言,應根據業務上下文,選擇合適的語言、工具對其進行構建。
——摘自馬丁· 福勒先生的博客
1 特點:
1)微
微服務架構通過對特定業務領域的分析與建模,將復雜的應用分解成小而專、低耦合並且高度自治的一組服務。微的定義最好符合項目的敏捷開發周期。
2)單一職責
業務邏輯單一,高內聚低耦合,不同服務通過管道等方式靈活組合。
註:面向對象設計之SOLID原則
SRP |
The Single Responsibility Principle |
單一責任原則 |
一個對象/類應該只有一個發生變化的原因,如果一個對象/類被多個原因改變,則說明該對象/類承擔了多個職責 |
OCP |
The Open Closed Principle |
開放封閉原則 |
軟件實體應該是可擴展,而不可修改的。也就是說,對擴展是開放的,而對修改是封閉的。 |
LSP |
The Liskov Substitution Principle |
裏氏替換原則 |
當一個子類的實例應該能夠替換任何其超類的實例時,它們之間才具有is-A關系(is-a 指的是類的父子繼承關系) |
DIP |
The Dependency Inversion Principle |
依賴倒置原則 |
1. 高層模塊不應該依賴於低層模塊,二者都應該依賴於抽象 2. 抽象不應該依賴於細節,細節應該依賴於抽象 |
ISP |
The Interface Segregation Principle |
接口分離原則 |
不能強迫用戶去依賴那些他們不使用的接口。換句話說,使用多個專門的接口比使用單一的總接口總要好。 |
3)輕量級通信
輕量級通信機制通常指語言無關、平臺無關的交互方式。通信消息格式,如xml、json等,他們的解析和使用基本與語言、平臺無關。通信協議,通常基於HTTP,能讓服務間的通信標準化、無狀態化。REST是實現服務之間互相協作的輕量級通信機制之一。
4)獨立性
開發測試部署的獨立。每個服務都是一個獨立單元,有獨立的代碼庫。服務與服務隔離。
5)進程隔離
每個服務都運行在不同的進程中,可以部署在不同節點。組件一般指獨立升級 獨立替換掉的部分。
2 背景技術
1)互聯網時代的產品通常有兩類特點:需求變化快和用戶群體龐大。在這種情況下,如何從系統架構的角度出發,構建靈活、易擴展的系統,快速應對需求 的變化;同時,隨著用戶量的增加,如何保證系統的可伸縮性、高可用性,成為系統架構面臨的挑戰。
2)敏捷、精益方法論、DevOps的深入人心
精益創業(Lean Startup)幫助組織分析並建立最小可實行產品(Minimum Viable Product),通過叠代持續改進;敏捷方法幫助組織消除浪費,通過反 饋不斷找到正確的方向;持續交付幫助組織構建更快、更可靠、可頻繁發布的交付機制。DevOps文化的推行打破了傳統開發與運維之間的壁壘,幫助組織形成 更高效的、開發與運維高度協作的交付團隊。
3)虛擬化技術和容器化技術
虛擬化技術和基礎設施自動化(Infrastructure As Code)的快速發展極大的簡化了基礎設施的創建、配置以及系統的安裝和部署。譬如雲平臺的成熟以及像 Chef、Puppet、Ansible等工具的使用,讓更多的基礎設施能夠通過自動化的方式動態創建。
容器化技術的發展以及Docker的出現,更是將虛擬化技術推向了一個史無前例的高潮。
3 SOA面向服務架構
SOA闡述了“對於復雜的企業IT系統,應按照不同的、可重用的粒度劃分,將功能相關的一組功能提供者組織在一起為消費者提供服務”,其目的是為了解決企業內部不同IT資源之間無法互聯而導致的信息孤島問題。直到2000年左右,ESB(Enterprise Service Bus)、WebService、SOAP等這類技術的出現,才使得SOA漸漸落地。
實際上, SOA的概念和微服務思想幾乎一致。主要區別如下表所示:
SOA實現 |
微服務架構實現 |
企業級,自頂向下開展實施 |
團隊級,自底向上開展實施 |
服務由多個子系統組成,粒度大 |
一個系統被拆分成多個服務,粒度細 |
企業服務總線,集中式的服務架構 |
無集中式總線,松散的服務架構 |
集成方式復雜(ESB/WS/SOAP) |
集成方式簡單(HTTP/REST/JSON) |
單塊架構系統,相互依賴,部署復雜 |
服務都能獨立部署 |
相比傳統SOA的服務實現方式,微服務更具有靈活性、可實施性以及可擴展性,其強調的是一種獨立測試、獨立部署、獨立運行的軟件架構模式。
4 微服務本質
服務作為組件
傳統實現組件方式是隔離獨立的部分或抽出公用的部分,構建共享庫,從而達到解耦和復用的效果。服務之間定義清晰、語言無關、平臺無關的接口。
圍繞業務組織團隊
關註產品而非項目
技術多樣性
業務數據獨立
提供業務數據接口,而非公用數據庫
基礎設施自動化
每個服務需分別部署,則部署 運維的成本增加,對持續交付和部署流水線要求高。實現基礎設施的自動化促進微服務構建。
演進式架構
敏捷開發 版本更新
5 微服務實施因素
分布式系統的復雜度
微服務架構師一種基於分布式的系統。
性能:多服務之間響應延遲及協作
可靠性:單點故障率增大
異步:
數據一致性:分布式事務管理 或保證數據的瞬時一致性
工具:IDE對微服務的支持不太好
運維成本
配置信息:
部署
監控與告警
日誌收集
部署自動化
構建有效的自動化部署流水線
DevOps與組織架構
微服務不僅是一種架構模型,也表現出一種組織模型(開發者將承擔部署運維監控)
服務間依賴測試
服務間依賴管理
三 微服務實踐/項目開發流程
敏捷開發 自動化工具
1 API實現(REST)
選擇合適的開發語言及開發框架
選擇合適的代碼倉庫,svn、git
2 代碼檢查
1)代碼自動化測試工具
2)單元測試覆蓋率統計
3)代碼靜態檢查,如代碼的可讀性、命名風格及統一的格式等
4)代碼復雜度檢查
可集成,如自動化測試的同時進行代碼的靜態檢查
3 代碼構建
代碼構建工具及構建所生成文件類型,如war、jar、鏡像等
4 項目部署
基礎設施自動化(Puppet Ambari等)
自動化部署,如部署腳本deploy.sh,可包括基礎設施環境準備
5 持續交付流水線
持續集成環境,如jenkins
持續交付:小批量價值流動 頻繁可發布 快速反饋
1 提交階段
代碼編譯 靜態檢查 單元測試等等
持續集成工具可通過WebHook的方式檢測到代碼倉庫的提交並觸發相應的處理機制,可以輪詢的方式定期檢測代碼庫(提交版本時間)的變化。
2 構建階段
構建部署包,提交階段完成後觸發構建,註意部署包的版本定義
3 部署階段
測試環境
生產環境
基礎環境搭建,如tomcat等,執行部署腳本deploy.sh等
6 日誌聚合
日誌聚合工具 splunk kafka flume
數據采集 數據存儲 高效索引 數據搜索 數據分析
7 監控與告警
主機監控 基礎設施 Nagios zabbix
應用監控 項目相關的狀態
告警 服務出現異常通知相關人員修復
8 功能叠代
服務描述文件:服務介紹 (名稱 功能) 服務維護者 服務級信息 運行環境(地址) 開發(搭建 運行) 測試 構建 部署 運維(日誌URL 監控URL)
四 微服務進階
1 輕量級通信機制
定義:平臺無關、語言無關的消息通信協議
同步通信:請求->等待->響應->處理
1)遠程過程調用RPC:
典型的分布式節點間同步通信
語言依賴
傳輸格式為二進制 一端變化另一端也許對應修改
2)表述性狀態傳遞REST
以資源為核心、以HTTP為操作方式 HTTP通信是同步的
核心:資源:信息實體的抽象
表述:對資源某一特定時刻的狀態描述,如json格式等,URI僅代表資源的實體,HTTP請求頭Accept、Content-Type字段才是表述
狀態轉移:客戶端同服務器端交互的過程中,客戶端能通過資源的表述來實現操作資源的目的。
統一接口:GET獲取資源 POST新建資源 PUT更新資源 DELETE銷毀資源
3)超文本應用語言HAL
輕量級超文本應用描述協議,基於REST,並解決REST中資源結構標準化和定義資源鏈接的問題。可使用HAL瀏覽器可視化資源信息。
HAL又將資源分為:狀態 鏈接 子資源
狀態:資源本身固有的屬性
鏈接Links:與當前資源相關的一組資源的鏈接的集合
子資源:描述 在當前資源內部 其嵌套資源的定義
異步通信:
1)消息隊列
核心:持久性(消息保持在內存、磁盤、或數據庫中) 排隊標準(消息隊列的標準及算法)安全策略 清理策略 處理通知
訪問方式:
拉模式pull:消費者定期檢查隊列上的消息,一般存在一個發布者和一個消費者
推模式push:每當發布者將消息添加到隊列中時,會通過某種機制通知消費者,一般存在多個消費者,也叫訂閱者。
2)後臺任務處理系統
相對簡單的異步場景中使用消息隊列略微復雜。常見的後臺任務處理系統有Resque、Sidekiq、Delayed_job等
核心:任務 隊列 執行器 定時器
服務回調:保持任務的輕量級 不在任務中定義過多邏輯 盡量做到由任務回調具體的服務來完成交互。
2 微服務與測試
微服務的組成部分及測試內容
在微服務場景下,這個層次可以被擴展為5層(如果將UI測試單獨抽取出來,可以分為六層):
單元測試:
針對程序單元的正確性進行的檢驗。被測單元依賴於模擬部分和被測單元依賴於真實部分。工具如java中的JUnit
接口/契約 測試
針對服務接口進行的測試,驗證提供者提供的契約/接口是否滿足消費者的期望。對於微服務,建議使用基於消費者驅動的契約測試。
工具如Pact、Pacto、Janus
集成測試
將不同的單元按照期望組合起來,對其接口進行正確性檢驗的測試工作,如數據庫訪問模塊與數據庫的集成、對外部service依賴的測試。
自頂向下集成(從應用的入口開始,把不同部分組合起來,進行驗證,並向底層移動)自底向上集成(傳統瀑布模型常用)。
工具如WireMock、mountebank
組件測試
對組件提供的功能進行正確性檢驗。進程內測試和進程外測試。
工具如WireMock、mountebank、moco
端到端測試
從用戶使用系統的角度出發,對系統的行為進行正確性檢驗。在端到端測試中,最重要的反而不是測試本身,而是環境的自動化能力。
采用BDD方式描述測試用例,工具如Jbehave,Cucumber
參考:微服務場景下的自動化測試
微服務實踐
摘自:微服務(Microservice)那點事
一 客戶端如何訪問這些服務?
後臺有N個服務,前臺就需要記住管理N個服務,一個服務下線/更新/升級,前臺就要重新部署,這明顯不服務我們 拆分的理念,特別當前臺是移動應用的時候,通常業務變化的節奏更快。另外,N個小服務的調用也是一個不小的網絡開銷。還有一般微服務在系統內部,通常是無狀態的,用戶登錄信息和權限管理最好有一個統一的地方維護管理(OAuth)。所以,一般在後臺N個服務和UI之間一般會一個代理或者叫API Gateway:
1)提供統一服務入口,讓微服務對前臺透明
2)聚合後臺的服務,節省流量,提升性能
3)提供安全,過濾,流控等API管理功能
API Gateway可以是一個軟硬一體的盒子,也可以是一個簡單的MVC框架,甚至是一個Node.js的服務端。他們最重要的作 用是為前臺(通常是移動應用)提供後臺服務的聚合,提供一個統一的服務出口,解除他們之間的耦合,不過API Gateway也有可能成為單點故障點或者性能的瓶頸。
二 服務之間如何通信?
因為所有的微服務都是獨立的Java進程跑在獨立的虛擬機上,所以服務間的通行就是IPC(inter process communication),現在基本最通用的有兩種方式。
1)同步調用:
REST(JAX-RS,Spring Boot)
RPC(Thrift, Dubbo)
2)異步消息調用:(Kafka, Notify, MetaQ)
一般同步調用比較簡單,一致性強,但是容易出調用問題,性能體驗上也會差些,特別是調用層次多的時候。RESTful和RPC的比較也是一個很有意思的話題。一般REST基於HTTP,更容易實現,更容易被接受,服務端實現技術也更靈活些,各個語言都能支持,同時能跨客戶端,對客戶端沒有特殊的要 求,只要封裝了HTTP的SDK就能調用,所以相對使用的廣一些。RPC也有自己的優點,傳輸協議更高效,安全更可控,特別在一個公司內部,如果有統一個 的開發規範和統一的服務框架時,他的開發效率優勢更明顯些。
異步消息的方式在分布式系統中有特別廣泛的應用,他既能減低調用服務之間的耦合,又能成為調用之間的緩沖,確保消息積壓不會沖垮被調用方,同時能保證調用方的服務體驗,繼續幹自己該幹的活,不至於被後臺性能拖慢。不過需要付出的代價是一致性的減弱,需要接受數據最終一致性;還有就是後臺服務一般要實現冪等性,因為消息發送出於性能的考慮一般會有重復(保證消息的被收到且僅收到一次對性能是很大的考驗);最後就是必須引入一個獨立的broker,如果公司內部沒有技術積累,對分布式管理之broker模式也是一個很大的挑戰。broker模式:引入一個Broker組件,解耦客戶端和服務端。服務端註冊自己到Broker,通過暴露接口的方式允許客戶端接入服務。客戶端是通過Broker發送請求的,Broker轉發請求道服務端,並將請求的結果或異常回發給客戶端。通過使用Broker模式,應用可以通過發送消息訪問遠程的服務。
三 這麽多服務,怎麽找?
在微服務架構中,一般每一個服務都是有多個拷貝,來做負載均衡。一個服務隨時可能下線,也可能應對臨時訪問壓力增加新的服務節點。服務之間如何相互感知?服務如何管理?這就是服務發現的問題了。一般有兩類做法,也各有優缺點。基本都是通過zookeeper等類似技術做服務註冊信息的分布式管理。
客戶端做:優點是架構簡單,擴展靈活,只對服務註冊器依賴。缺點是客戶端要維護所有調用服務的地址,有技術難度,一般大公司都有成熟的內部框架支 持,比如Dubbo。
服務端做:優點是簡單,所有服務對於前臺調用方透明,一般在小公司在雲服務上部署的應用采用的比較多。
四 服務掛了怎麽辦?
當我們的系統是由一系列的服務調用鏈組成的時候,我們 必須確保任一環節出問題都不至於影響整體鏈路。相應的手段有很多:
重試機制
限流
熔斷機制
負載均衡
降級(本地緩存)
雲原生
參考:雲原生應用程序架構的五大特性(上)- 12要素應用
參考: 雲原生機制的三個核心思想及其未來之路
在雲的時代,應用會更多的遷移到雲端,基於雲的架構設計和開發模式需要一套全新的理念去承載,於是雲原生思想應運而生,而針對雲原生應用開發的最佳實踐原則,12-Factor脫穎而出。
雲計算平臺的三個層次:
IaaS 基礎雲設施:提供各種基礎資源(Infrastructure)
PaaS 開發平臺:提供各種平臺服務(Platform)
SaaS 交付應用或服務:直面用戶,提供應用價值(Application)
12要素
1、基準代碼
一份基準代碼,多份部署。每個可部署的應用程序均被視為在版本控制中的代碼庫來進行追蹤,相同的基準代碼可能在多個環境下部署有許多的應用程序實例。
2、依賴
顯式聲明依賴關系。應用程序通過適當的工具(如:Maven、Bundler、NPM)隔離依賴性,目的就是不依賴於部署環境。
3、配置
在環境中存儲配置。通過操作系統級的環境變量將配置信息或其他可能存在的不同信息(如:開發環境、預生產環境、生產環境)應用到各個部署環境中。
4、 後端服務
把後端服務當作附加資源。數據庫、消息隊列、郵件發送服務或緩存系統等均被作為是附加資源在不同環境中被同等地調用,每個不同的後端服務都是一份資源 。舉個例子,一個MySQL 數據庫是一個資源,兩個MySQL 數據庫(用來給數據分區)就是兩個不同的資源。12要素應用將這些數據庫都視作附加資源 ,將它們和部署環境保持松耦合。
5、構建、發布、運行
嚴格分離構建和運行。基準代碼轉化為部署(非開發環境)需要以下三個階段:
構建階段,是指將代碼倉庫轉化為可執行包的過程。構建時會使用指定版本的代碼,獲取和打包依賴項,編譯成二進制文件和資源文件。
發布階段,會將構建的結果和當前部署所需的配置相結合,並能夠立刻在運行環境中投入使用。
運行階段,是指針對選定的發布版本在執行環境中啟動一系列應用程序的進程。
以上所有階段都是嚴格分離的。
6、進程
以一個或多個無狀態進程運行應用。在運行環境中,應用程序作為一個或多個無共享的無狀態進程(如:master/workers)來執行,任何需要持久化的數據都要存儲在後端服務內(例如:緩存、對象存儲等)。
7、端口綁定
通過端口綁定(Port Binding)來提供服務。具有12要素的應用能夠實現完全自我加載,不依賴於任何網絡服務器就可以創建基於網絡的服務。互聯網應用可以通過端口綁定來提供服務並隨時監聽所有發送至該端口的請求。
8、並發
通過進程模型進行擴展。一般而言,並行由水平向外擴展應用程序進程(盡管必要時進程也可通過內部管理線程多路傳輸工作)來實現。
9、易處理
通過快速啟動和終止來實現應用程序韌性的最大化。這包括了快速而有彈性的擴展、對變更的部署以及宕機恢復能力。
10、開發環境與生產環境等價
通過盡可能地保持開發環境、預生產環境和生產環境三者的相似性來實現持續交付與部署。
11、日誌
將日誌作為事件流,允許執行環境通過集中式服務來收集、聚合、檢索和分析日誌,而非僅僅管理日誌文件。
12、管理進程
將後臺管理任務當作一次性進程運行。當環境就等同於應用程序長時間運行的進程時,管理任務(如:數據庫遷移)會被作為一次性進程而執行。
微服務架構與實踐及雲原生等相關概念