筆記:《微服務架構與實踐》 王磊 著html
1 定義:對於這種功能集中、代碼和數據中心化、一個發佈包、部署後運行在同一進程的應用程序,咱們一般稱之爲單塊架構應用,並不是物理上的分層。前端
2 單層架構:數據 邏輯 頁面 混合java
3 三層架構:ios
1)表示層:數據顯示和用戶交互git
2)業務邏輯層:業務邏輯處理算法
3)數據訪問層:數據存儲訪問數據庫
4 優點: 比較適合小項目json
易於開發:開發簡單直接,集中式管理,基本不會重複開發,集成工具適合後端
易於測試:單進程瀏覽器
易於部署:單項目包,功能都在本地,沒有分佈式的管理開銷和調用開銷
易於水平伸縮:發佈相同的項目包,部署多個運行環境,使用負載均衡器分發,克隆
5 挑戰:
開發效率低:全部的開發在一個項目改代碼,遞交代碼相互等待,代碼衝突不斷
代碼維護難:代碼功能耦合在一塊兒,新人不知道何從下手
部署不靈活:構建時間長,任何小修改必須從新構建整個項目,這個過程每每很長
穩定性不高:一個微不足道的小問題,能夠致使整個應用掛掉
維護成本增長:功能多,團隊大,管理複雜,缺陷修復容易致使新的缺陷問題
持續交付週期長:
技術選型成本高:採用統一的技術平臺或方案開發,當嘗試引入新的框架、技術或對技術站升級會面臨不小的風險。技術變化快,平滑完成替代較難。
可擴展性差:沒法知足高併發狀況下的業務需求
構建全功能團隊難:單塊架構每每以技能爲單位進行分組,如前端、業務層、數據庫團隊等。
微服務架構是一種架構模式,它提倡將單一應用程序劃分紅一組小的服務,服務之間互相協調、互相配合,爲用戶提供最終價值。每一個服務運行在其獨立的進程中,服務與服務間採用輕量級的通訊機制互相溝通(一般是基於HTTP的RESTful API)。每一個服務都圍繞着具體業務進行構建,而且可以被獨立地部署到生產環境、類生產環境等。另外,應儘可能避免統一的、集中式的服務管理機制,對具體的一個服務而言,應根據業務上下文,選擇合適的語言、工具對其進行構建。
——摘自馬丁· 福勒先生的博客
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)進程隔離
每一個服務都運行在不一樣的進程中,能夠部署在不一樣節點。組件通常指獨立升級 獨立替換掉的部分。
1)互聯網時代的產品一般有兩類特色:需求變化快和用戶羣體龐大。在這種狀況下,如何從系統架構的角度出發,構建靈活、易擴展的系統,快速應對需求 的變化;同時,隨着用戶量的增長,如何保證系統的可伸縮性、高可用性,成爲系統架構面臨的挑戰。
2)敏捷、精益方法論、DevOps的深刻人心
精益創業(Lean Startup)幫助組織分析並創建最小可實行產品(Minimum Viable Product),經過迭代持續改進;敏捷方法幫助組織消除浪費,經過反 饋不斷找到正確的方向;持續交付幫助組織構建更快、更可靠、可頻繁發佈的交付機制。DevOps文化的推行打破了傳統開發與運維之間的壁壘,幫助組織造成 更高效的、開發與運維高度協做的交付團隊。
3)虛擬化技術和容器化技術
虛擬化技術和基礎設施自動化(Infrastructure As Code)的快速發展極大的簡化了基礎設施的建立、配置以及系統的安裝和部署。譬如雲平臺的成熟以及像 Chef、Puppet、Ansible等工具的使用,讓更多的基礎設施可以經過自動化的方式動態建立。
容器化技術的發展以及Docker的出現,更是將虛擬化技術推向了一個前所未有的高潮。
SOA闡述了「對於複雜的企業IT系統,應按照不一樣的、可重用的粒度劃分,將功能相關的一組功能提供者組織在一塊兒爲消費者提供服務」,其目的是爲了解決企業內部不一樣IT資源之間沒法互聯而致使的信息孤島問題。直到2000年左右,ESB(Enterprise Service Bus)、WebService、SOAP等這類技術的出現,才使得SOA漸漸落地。
實際上, SOA的概念和微服務思想幾乎一致。主要區別以下表所示:
SOA實現 |
微服務架構實現 |
企業級,自頂向下開展實施 |
團隊級,自底向上開展實施 |
服務由多個子系統組成,粒度大 |
一個系統被拆分紅多個服務,粒度細 |
企業服務總線,集中式的服務架構 |
無集中式總線,鬆散的服務架構 |
集成方式複雜(ESB/WS/SOAP) |
集成方式簡單(HTTP/REST/JSON) |
單塊架構系統,相互依賴,部署複雜 |
服務都能獨立部署 |
相比傳統SOA的服務實現方式,微服務更具備靈活性、可實施性以及可擴展性,其強調的是一種獨立測試、獨立部署、獨立運行的軟件架構模式。
服務做爲組件
傳統實現組件方式是隔離獨立的部分或抽出公用的部分,構建共享庫,從而達到解耦和複用的效果。服務之間定義清晰、語言無關、平臺無關的接口。
圍繞業務組織團隊
關注產品而非項目
技術多樣性
業務數據獨立
提供業務數據接口,而非公用數據庫
基礎設施自動化
每一個服務需分別部署,則部署 運維的成本增長,對持續交付和部署流水線要求高。實現基礎設施的自動化促進微服務構建。
演進式架構
敏捷開發 版本更新
分佈式系統的複雜度
微服務架構師一種基於分佈式的系統。
性能:多服務之間響應延遲及協做
可靠性:單點故障率增大
異步:
數據一致性:分佈式事務管理 或保證數據的瞬時一致性
工具:IDE對微服務的支持不太好
運維成本
配置信息:
部署
監控與告警
日誌收集
部署自動化
構建有效的自動化部署流水線
DevOps與組織架構
微服務不只是一種架構模型,也表現出一種組織模型(開發者將承擔部署運維監控)
服務間依賴測試
服務間依賴管理
敏捷開發 自動化工具
選擇合適的開發語言及開發框架
選擇合適的代碼倉庫,svn、git
1)代碼自動化測試工具
2)單元測試覆蓋率統計
3)代碼靜態檢查,如代碼的可讀性、命名風格及統一的格式等
4)代碼複雜度檢查
可集成,如自動化測試的同時進行代碼的靜態檢查
代碼構建工具及構建所生成文件類型,如war、jar、鏡像等
基礎設施自動化(Puppet Ambari等)
自動化部署,如部署腳本deploy.sh,可包括基礎設施環境準備
持續集成環境,如jenkins
持續交付:小批量價值流動 頻繁可發佈 快速反饋
1 提交階段
代碼編譯 靜態檢查 單元測試等等
持續集成工具可經過WebHook的方式檢測到代碼倉庫的提交併觸發相應的處理機制,能夠輪詢的方式按期檢測代碼庫(提交版本時間)的變化。
2 構建階段
構建部署包,提交階段完成後觸發構建,注意部署包的版本定義
3 部署階段
測試環境
生產環境
基礎環境搭建,如tomcat等,執行部署腳本deploy.sh等
日誌聚合工具 splunk kafka flume
數據採集 數據存儲 高效索引 數據搜索 數據分析
主機監控 基礎設施 Nagios zabbix
應用監控 項目相關的狀態
告警 服務出現異常通知相關人員修復
服務描述文件:服務介紹 (名稱 功能) 服務維護者 服務級信息 運行環境(地址) 開發(搭建 運行) 測試 構建 部署 運維(日誌URL 監控URL)
定義:平臺無關、語言無關的消息通訊協議
同步通訊:請求->等待->響應->處理
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等
核心:任務 隊列 執行器 定時器
服務回調:保持任務的輕量級 不在任務中定義過多邏輯 儘可能作到由任務回調具體的服務來完成交互。
微服務的組成部分及測試內容
在微服務場景下,這個層次能夠被擴展爲5層(若是將UI測試單獨抽取出來,能夠分爲六層):
單元測試:
針對程序單元的正確性進行的檢驗。被測單元依賴於模擬部分和被測單元依賴於真實部分。工具如java中的JUnit
接口/契約 測試
針對服務接口進行的測試,驗證提供者提供的契約/接口是否知足消費者的指望。對於微服務,建議使用基於消費者驅動的契約測試。
工具如Pact、Pacto、Janus
集成測試
將不一樣的單元按照指望組合起來,對其接口進行正確性檢驗的測試工做,如數據庫訪問模塊與數據庫的集成、對外部service依賴的測試。
自頂向下集成(從應用的入口開始,把不一樣部分組合起來,進行驗證,並向底層移動)自底向上集成(傳統瀑布模型經常使用)。
工具如WireMock、mountebank
組件測試
對組件提供的功能進行正確性檢驗。進程內測試和進程外測試。
工具如WireMock、mountebank、moco
端到端測試
從用戶使用系統的角度出發,對系統的行爲進行正確性檢驗。在端到端測試中,最重要的反而不是測試自己,而是環境的自動化能力。
採用BDD方式描述測試用例,工具如Jbehave,Cucumber
參考:微服務場景下的自動化測試
一 客戶端如何訪問這些服務?
後臺有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-Factor脫穎而出。
雲計算平臺的三個層次:
IaaS 基礎雲設施:提供各類基礎資源(Infrastructure)
PaaS 開發平臺:提供各類平臺服務(Platform)
SaaS 交付應用或服務:直面用戶,提供應用價值(Application)
一、基準代碼
一份基準代碼,多份部署。每一個可部署的應用程序均被視爲在版本控制中的代碼庫來進行追蹤,相同的基準代碼可能在多個環境下部署有許多的應用程序實例。
二、依賴
顯式聲明依賴關係。應用程序經過適當的工具(如:Maven、Bundler、NPM)隔離依賴性,目的就是不依賴於部署環境。
三、配置
在環境中存儲配置。經過操做系統級的環境變量將配置信息或其餘可能存在的不一樣信息(如:開發環境、預生產環境、生產環境)應用到各個部署環境中。
四、 後端服務
把後端服務看成附加資源。數據庫、消息隊列、郵件發送服務或緩存系統等均被做爲是附加資源在不一樣環境中被同等地調用,每一個不一樣的後端服務都是一份資源 。舉個例子,一個MySQL 數據庫是一個資源,兩個MySQL 數據庫(用來給數據分區)就是兩個不一樣的資源。12要素應用將這些數據庫都視做附加資源 ,將它們和部署環境保持鬆耦合。
五、構建、發佈、運行
嚴格分離構建和運行。基準代碼轉化爲部署(非開發環境)須要如下三個階段:
構建階段,是指將代碼倉庫轉化爲可執行包的過程。構建時會使用指定版本的代碼,獲取和打包依賴項,編譯成二進制文件和資源文件。
發佈階段,會將構建的結果和當前部署所需的配置相結合,並可以馬上在運行環境中投入使用。
運行階段,是指針對選定的發佈版本在執行環境中啓動一系列應用程序的進程。
以上全部階段都是嚴格分離的。
六、進程
以一個或多個無狀態進程運行應用。在運行環境中,應用程序做爲一個或多個無共享的無狀態進程(如:master/workers)來執行,任何須要持久化的數據都要存儲在後端服務內(例如:緩存、對象存儲等)。
七、端口綁定
經過端口綁定(Port Binding)來提供服務。具備12要素的應用可以實現徹底自我加載,不依賴於任何網絡服務器就能夠建立基於網絡的服務。互聯網應用能夠經過端口綁定來提供服務並隨時監聽全部發送至該端口的請求。
八、併發
經過進程模型進行擴展。通常而言,並行由水平向外擴展應用程序進程(儘管必要時進程也可經過內部管理線程多路傳輸工做)來實現。
九、易處理
經過快速啓動和終止來實現應用程序韌性的最大化。這包括了快速而有彈性的擴展、對變動的部署以及宕機恢復能力。
十、開發環境與生產環境等價
經過儘量地保持開發環境、預生產環境和生產環境三者的類似性來實現持續交付與部署。
十一、日誌
將日誌做爲事件流,容許執行環境經過集中式服務來收集、聚合、檢索和分析日誌,而非僅僅管理日誌文件。
十二、管理進程
將後臺管理任務看成一次性進程運行。當環境就等同於應用程序長時間運行的進程時,管理任務(如:數據庫遷移)會被做爲一次性進程而執行。