多年以來,咱們一直在尋找更好的方法來構建應用系統。咱們一直在學習已有的技術,嘗試新技術,使用不一樣的方式來構建IT應用系統,從而提升客戶滿意度和開發效率。html
Eric Evans的《領域驅動設計》一書幫助理解了用代碼呈現真實世界的重要性,而且告訴咱們如何更好地進行建模。持續交付理論告訴咱們如何更有效地發佈軟件產品,並指出保持每次提交都可發佈的重要性。基於對web的理解,咱們尋找到了機器與機器交互的更好方式。Alistair Cockburn的六邊形架構理論把咱們從分層架構中拯救出來,從而可以更好地體現業務邏輯。藉助虛擬化平臺,可以按需建立機器並調整其大小,藉助基礎設施的自動化,咱們也很容易從一臺機器擴展到多臺。前端
隨着領域驅動設計、持續交付、按需虛擬化、基礎設施自動化、小型自治團隊、大型集羣系統這些實踐的流行,微服務也應運而生。它並非被髮明出來的,而生從現實世界中總結出來的一種趨勢或模式。可是沒有前面體積的這些概念,微服務也很難出現。vue
不少組織發現細粒度的微服務架構能夠幫助他們更快地交付軟件,而且有更多機會嘗試新技術。微服務在技術決策上給咱們極大的自由度,使咱們可以更快地響應不可避免的變化。java
微服務架構是一種架構模式,提倡將單一應用程序劃分紅一組小的服務,每一個服務運行在其獨立的進程中,服務間採用輕量級的通訊機制互相溝通(一般是基於HTTP協議的RESTful API)。每一個服務都圍繞着具體業務進行構建,而且可以被獨立的部署到生產環境,類生產環境等。react
很小、專一於作好一件事git
隨着新功能的增長,代碼庫會愈來愈大。時間久了代碼庫會很是龐大,以致於想要知道該在什麼地方作修改都很困難。儘管咱們想在巨大的代碼庫中作到清晰地模塊化,但事實上這些模塊之間的界限很難維護。類似的功能代碼開始在代碼庫中隨處可見,使得修復bug或實現更加困難。程序員
在單塊系統內,一般會建立一些抽象層或者模塊來保證代碼的內聚性,從而避免上述問題。 內聚性是指將相關代碼放在一塊兒在考慮使用微服務的時候,內聚性這一律念很重要。github
Robert C.Martin有一個對單一職責原則的論述:把因相同緣由而變化的東西聚合到一塊兒,而把因不一樣緣由而變化的東西分離開來。該論述很好的強調了內聚性這一律念。微服務將這個理念應用在獨立的服務上,根據業務的邊界來肯定服務的邊界,這些就很容易肯定某個功能代碼應該放在那裏。並且因爲該服務專一於某個邊界以內,所以能夠很好地避免因爲代碼庫過大衍生出的不少相關問題。web
微服務,最大的挑戰就是三個原則:不要太大,不要過小,不要太緊密耦合redis
沒有規定的微觀概念,微服務不必定要小。
微服務架構風格是一種將單個應用程序開發爲一套小型服務的方法,每一個小型服務都在本身的流程中運行,並於輕量級機制(HTTP)進行通訊。
這些服務圍繞業務功能構建,能夠用全自動部署機制獨立部署。這些服務能夠進行集中管理,能夠用不一樣的編程語言編寫,並使用不一樣的數據庫存儲技術。
足夠小並且不過小,一旦一段代碼再也不感受到太大了,它可能足夠小了。
開發軟件更快
主要應用程序是一個大型代碼庫,幾個小型開發團隊試圖爲不一樣目的構建功能。意味着每一次變動都必須努力知足不一樣的羣體。
讓不一樣的開發人員團隊共享相同的代碼庫也意味着的代碼以難以想象的方式不斷變得更加複雜。隨着代碼庫變得愈來愈大,團隊中沒有人能夠擁有它而且確保全部部件都按照最佳方式進行組織和組合。
使得部署變得困難,對咱們的應用程序進行單行更改仍然須要部署整個過程以推進更改。因爲咱們的大型應用程序是高風險的,質量保證流程增加
經過微服務架構,但願可以將代碼分開,以便不一樣的開發團隊能夠徹底擁有它們。這將使團隊可以更快地進行建立,而無需繁瑣的設計,審查、部署流程。還但願經過減小開發人員處理較小的代碼庫,代碼庫將更容易開發,測試和保持良好的組織。
靈活應對技術選擇
經過微服務架構,但願將個別服務保持在較小狀態意味着用更好的實現來替換它們的成本將更容易管理。也但願可以爲每項工做選擇合適的工具,而不是一刀切的方法。能夠靈活地在咱們認爲合適的不一樣應用程序中使用多種技術。
微服務缺點
開發,託管和管理衆多服務須要大量開銷。在少數幾個進程上運行的單個總體能夠輕鬆地轉換爲幾個服務的幾十個進程,須要負載均衡器,消息傳遞層和羣集以實現彈性。
微服務涉及分佈式系統,這些系統引入了許多問題,例如:網絡延遲、容錯、事務、不可靠的網絡和異步性
構建爲統一單元。一般由三部分組成:數據庫、客戶端界面(HTML)、服務端應用。
服務端應用將處理HTTP請求,執行邏輯,從數據庫檢索和更新數據,以及填充要發送到瀏覽器的HTML視圖
一般是一個龐大的代碼庫。服務器端的應用邏輯,前端客戶端邏輯,後臺做業等都在同一個代碼庫定義。開發人員想要進行更改或更新,須要一次構建和部署整個堆棧
優勢:
缺點:
微服務架構是指將單個應用程序開發爲一套小型服務的概念,而不是將它們開發爲一個大型的「總體」
每一個分解的個性化的服務都在本身的進程上運行,與輕量級機制(HTTP)進行通訊。徹底成熟的微服務可獨立部署,但必要時能夠協同工做
優勢:
缺點:
考慮幾個關鍵因素,以下
適合使用單片應用
適合微服務
使用微服務開發新系統的核心好處之一是該架構容許開發人員獨立構建或修改單個組件時,當涉及最小化每一個API之間的回調數量時會出現問題
避免任意規則
設計和建立微服務時,不須要陷入使用任意規則的陷阱。下面的規則,並非肯定微服務邊界的正確方法
精心設計的服務特色
高內聚,鬆耦合
高內聚是指一個軟件模塊是由相關性很強的代碼組成
特徵1:不與其餘服務共享數據庫表
若是多個服務引用相同的表,那麼在設計微服務時就不適合,由於可能意味着你的數據庫是耦合的來源。
開發新服務時使用的主要基本原則之一就是它們不該該跨越數據庫邊界。每一個服務都應該依賴於本身的一組底層數據存儲。這使得咱們能夠集中訪問控制,審計日誌記錄,緩存邏輯等
若是數據庫表的一個子集與數據集的其他部分沒有或不多有鏈接,那麼組件能夠唄隔離到一個單獨的API或單獨的服務中,這是一個強烈信號
每一個服務應該有本身的表和永遠不該該共享數據庫表
特徵2:具備最少許的數據庫表
微服務的理想大小應該足夠小,每一個數據庫表也是同樣的。最佳狀況是一個或兩個數據庫表
特徵3:考慮有狀態和無狀態
設計微服務時,須要考慮它是否須要訪問數據庫,或者它是否處理過TB級別數據的無狀態服務。
經過定義服務的輸入和輸出來定義服務的邊界。有時候服務是網絡API,但它也多是使用文件並在數據庫中生成記錄的進程
特徵4:考慮數據可用性需求
設計微服務時,須要記住那些服務將依賴於此新服務,以及在該數據不可用時的整個系統的影響。
考慮到這一點,也能夠正確地設計此服務的數據備份和恢復系統
特徵5:單一的真實來源
設計服務時,讓其稱爲系統中某些內容的惟一真實來源。
注意事項
整個團隊能夠專門擁有服務,在肯定邊界時,組織性就會發揮做用。
還有兩個須要考慮的因素:獨立的發佈計劃和不一樣的正常運行時間
如何判斷服務是否過小或未正肯定義
第一個指標是服務之間的任何過分依賴,若是兩個服務不斷地相互呼叫,那麼這是一個強烈的耦合指示和一個信號,可能會更好地組成一個服務
第二個,若是設置服務的開銷大於使其獨立的好處
#
使用Java搭建微服務框架語言
未使用微服務框架問題分析:
統一用戶認證平臺
統一用戶認證平臺用於集中管理組織與人員信息,提供統一標準的人員主數據。經過SOA服務總線與各業務系統進行集成,同時爲單點登陸提供統一的身份認證信息。
統一用戶認證平臺與企業郵箱,企業微信息,AD域進行集成。實現一個帳號,全網登陸
Spring Framework 基礎框架支持
Spring Boot 做爲服務的開發框架
Spring Cloud 進行微服務設計與開發
Spring Cloud Netflix 爲Spring Boot應用提供Netflix OSS集成
Eureka 做爲雲服務器中服務註冊與發現中心,實現負載均衡
Feign 進行服務訪問,簡化Eureka訪問參數
Ribbon 實現Eureka集羣的負載均衡
Hystrix 進行服務容錯處理,具有回退機制和斷路器功能的線程和信號隔離,請求緩存\打包以及監控和配置
Zuul 做爲服務網關
ZooKeeper 實現高度可靠的分佈式協調
Dubbo 阿里開源高性能優秀服務框架。
部署
Jenkins,GitLab CI 自動化部署
Docker 集裝箱部署
爲現代基於Java語言的企業應用提供全面的編程和配置模型-在任何類型部署平臺上。
Spring的一個關鍵要素是應用程序級別的基礎架構支持:Spring專一於企業應用程序的管道,以便團隊能夠專一於應用程序級人物邏輯,而無需與特定部署環境創建沒必要要的聯繫。
特徵
核心技術:依賴注入,事件,資源,i18n,驗證,數據綁定,類型轉換,SpEL,AOP。
測試:模擬對象,TestContext框架,Spring MVC測試,WebTestClient
。
數據訪問:事務,DAO支持,JDBC,ORM,編組XML。
Spring MVC和 Spring WebFlux Web框架。
集成:遠程處理,JMS,JCA,JMX,電子郵件,任務,調度,緩存。
語言:Kotlin,Groovy,動態語言。
#
能夠輕鬆建立獨立的,生產級的基於Spring的應用程序。
爲Spring平臺及第三方庫提供開箱即用的設置。多數Spring應用只須要不多的配置。
特徵
#
爲開發人員提供了快速構建分佈式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智能路由,微代理,控制總線,一次性令牌,全局鎖定,領導選舉,分佈式會話,集羣狀態)
使用Spring Cloud開發人員能夠快速搭建實現這些模式的服務和應用程序。適用於任何分佈式環境,包括開發人員本身的筆記本、數據中心和Cloud Foundry等託管平臺
特徵
Spring Cloud專一於爲典型用例提供良好的開箱即用體驗,併爲其餘用戶提供可擴展性機制
採用了一種很是具備聲明性的方法,一般只須要更改類路徑和/或註釋便可得到大量內容
主要項目
Spring Cloud Config:git存儲庫支持的集中式外部配置管理。配置資源直接映射到Spring
Spring Cloud Netflix:與各類Netflix OSS組件集成(Eureka,Hystrix,Zuul,Archaius)
Spring Cloud Bus:用於將服務和服務實例與分佈式消息傳遞鏈接在一塊兒的事件總線,用於在羣集中傳播狀態更改
Spring Cloud Cloudfoundry:將應用程序與Prvotal Cloud Foundry集成。提供服務發現實現,還能夠輕鬆實現SSO和OAuth2保護的資源
Spring Cloud Open Service Broker:提供構建實現Open Service Broker API的服務代理的起點
Spring Cloud Cluster:領導者選舉和共同的狀態模式與Zookeeper,Redis,Hazelcast,Consul的抽象和實現
Spring Cloud Consul:Hashicorp Consul的服務發現和配置管理
Spring Cloud Security:Zuul代理中的負載均衡OAuth2 rest客戶端和身份驗證頭中繼續提供支持
Spring Cloud Sleuth:Spring Cloud應用程序的分佈式跟蹤,與Zipkin,HTrace和基於日誌的跟蹤兼容
Spring Cloud Data Flow:適用於現代運行時的可組合微服務應用程序的雲本機編排服務。
Spring Cloud Stream:輕量級事件驅動的微服務框架,可快速構建可鏈接到外部系統的應用程序。在應用程序之間使用Kafka或RabbitMQ發送和接受消息的簡單聲明模型
Spring Cloud Stream App Starters:基於Spring Boot的Spring Integration應用程序,可提供與外部系統的集成
Spring Cloud Task:用於快速構建執行有限數據處理的應用程序。嚮應用程序添加功能和非功能的簡單聲明
Spring Cloud Task App Starters:Spring Boot應用程序,多是任何進程,包括不能永遠運行的Spring Batch做業,在有限的數據處理後結束/中止
Spring Cloud Zookeeper:服務發現和配置管理
Spring Cloud AWS:與託管的Amazon Web Service輕鬆集成。
Spring Cloud Connectors:使各類平臺中的PaaS應用程序能夠輕鬆鏈接到數據庫和消息代理等後端服務
Spring Cloud Starters:能夠簡化Spring Cloud用戶的依賴管理
Spring Cloud CLI:用於在Groovy中快速建立Spring Cloud組件應用程序
Spring Cloud Contract:整體項目,包含幫助用戶成功實施消費者驅動合同方法的解決方案
Spring Cloud Gateway:基於Project Reactor的只能可編程路由器
Spring Cloud OpenFeign:自動配置和Spring環境以及其餘Spring編程模型習慣用法提供Spring Boot應用程序的集成
Spring Cloud Pipelines:固定部署管道,其中包含確保您的應用程序能夠熱部署而且輕鬆回滾出錯的步驟
Spring Cloud Function:支持無服務器提供商之間的統一編程模型
#
Netflix OSS指Netflix Open Source Software
關注點是OOS中的Common Runtime Services & Libraries,包括爲微服務提供支持的運行容器,類庫和服務
Netflix OOS是一組開源的框架和組件庫,是Netflix公司開發出來解決分佈式系統的一些有趣的可擴展類庫。對Java開發者來講,是在雲端環境中開發微服務的很是棒的工具代名詞。在服務發現,負載均衡,容錯等模式方面,都給出了很是重要的概念和解決方案。
組件和功能
Eureka:服務註冊和服務發現
Archaius:分佈式配置管理
Ribbon:客戶端負載均衡
Hystrix:斷路器,運行時提供延遲和容錯的隔離
Karyon:實現雲就緒Web服務的構建藍圖
Governator:擴展和實用程序庫,可經過@PostConstruct和@PreDestory加強Google Guice以提供注入生命週期以及對對象生命週期的支持
Pranae:使其易於與NetflixOSS服務繼承
Zuul:服務網關
Fenzo:Apache Mesos框架的調度程序Java庫,支持用於調度優化的插件並促進集羣自動擴展。
Spring Cloud Netflix
Spring Cloud Netflix經過自動配置和Spring環境以及其餘Spring編程模型習慣用法爲Spring Boot應用程序提供Netflix OSS集成。經過一些簡單的註釋,能夠快速啓用和配置應用程序內的常見模式,並使用通過實戰考研的Netflix組件構建大型分佈式系統。提供的模式包括服務發現(Eureka),斷路器(Hystrix),智能路由(Zuul),客戶端負載均衡(Ribbon)
特徵
服務發現:能夠註冊Eureka實例,客戶端可使用Spring管理的bean發現實例
服務發現:可使用聲明性Java配置建立嵌入式Eureka服務器
斷路器:Hystrix客戶端可使用簡單的註釋驅動方法裝飾器構建
斷路器:帶有聲明性Java配置的嵌入式Hystrix儀表板
聲明性REST客戶端:Feign建立使用JAX-RS或Spring MVC註釋修飾的接口的動態實現
客戶端負載均衡器:Ribbon
外部配置:從Spring Environment到Archaius的橋接(使用Spring Boot約定啓用Netflix組件的本機配置)
路由器和過濾器:Zuul過濾器的自動註冊,以及反向代理建立的配置方法的簡單約定
#
一種基於REST的服務,用於發現定位服務,以實現中間層服務器的負載平衡和故障轉移。將此服務稱爲Eureka Server。
Eureka還附帶了一個基於Java的客戶端組件Eureka Client,使與服務的交互變得更加容易。客戶端還有一個內置的負載均衡器,能夠進行基本的循環負載均衡。在Netflix,一個更復雜的負載均衡器包裝Eureka,根據流量,資源使用,錯誤條件等多種因素提供加權負載平衡,以提供卓越的彈性。
簡單的多個服務,經過API調用會面臨如下幾個問題
服務發現是基於微服務架構的關鍵原則之一。嘗試配置每一個客戶端或某種形式的約定可能很是困難,很是脆弱。Eureka能夠將服務器配置和部署爲高可用性,每一個服務器將註冊服務的狀態複製到其餘服務器。
使用服務發現框架Eureka能夠實現如下功能
Eureka爲咱們提供了以上的解決方案,分別爲Eureka-server和Eureka-client兩個部分。
Eureka提供服務註冊服務發現功能,能夠部署爲Eureka-server集羣。
Eureka-client的主要功能是將服務註冊到Eureka-server,經過Eureka-server發現服務。
高可用性
Eureka服務器沒有後端存儲,可是註冊表中的服務實例必須發送心跳包以保持註冊更新,所以能夠在內存中完成。
Eureka客戶端還具備服務註冊表緩存,當客戶端獲取註冊表中的服務實例時,會從本身的緩存中獲取,客戶端的緩存會定時更新。
當Eureka服務掛了以後,並不會致使客戶端找不到須要請求的服務實例。可是當Eureka服務器掛掉以後,原來註冊表中的服務發生故障或更新,這是就會出現危險的狀況。
Eureka服務器同時也是一個客戶端,須要提供serviceUrl來同步註冊信息,若是不提供就會在日誌中出現大量錯誤。
Eureka服務器配置eureka.client.registerWithEureka=false,eureka.client.fetchRegistry=false
關閉了Eureka服務器之間的同步信息。爲了提升可用性,須要配置多個Eureka服務器,並讓它們之間互相同步註冊信息,當其中一個掛掉以後,Eureka客戶端會自動切換到另外的Eureka服務器。
#
Feign的第一個目標是下降將Denominator統一綁定到HTTP API的複雜性。
能夠解決API訪問中拼接字符串複雜繁瑣的問題。方便快捷的發送Eureka的REST請求。
#
Ribbon是一個基於HTTP和TCP客戶端的負載均衡器。提供如下功能
Ribbon能夠在經過客戶端配置的ribbonServerList服務端列表去輪詢訪問以達到均衡負載的做用。
與Eureka聯合使用,能夠擴展成從Eureka註冊中心獲取服務端列表。
#
避免異常故障蔓延
一個延遲和容錯庫,在隔離對遠程系統,服務和第三方庫的訪問點,中止級聯故障,並在複雜的分佈式系統中實現彈性。
Spring Cloud使用了Hystrix來實現斷路器的共呢個。經過控制那些訪問遠程系統、服務、第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。
Hystrix具有回退機制和斷路器隔絕的線程和信號隔離,請求緩存和請求打包,監控和配置等功能
執行如下操做
複雜分佈式系統結構中的應用程序具備許多依賴關係,每一個依賴關係在某些時候都將不可避免地失敗。若是主機應用程序未與這些外部故障隔離,則會將它們取下
例如:對於依賴於30個服務的應用程序,其中每一個服務的正常運行時間爲99.99%,爲了不級聯錯誤,其中的0.01能夠將其隔離。
能夠設置當調用一個服務達到必定的閾值(5秒失敗20次)打開斷路器。開啓斷路回滾,阻止級聯失敗並容許關閉服務一段時間進行癒合。
而且能夠監控每一個服務訪問的運行狀態時間
#
使用Eureka實現了服務註冊,Ribbon或Feign實現服務的消費以及均衡負載。Hystrix的斷路機制來避免異常故障蔓延
Zuul就是對外提供的一個服務網關。跟Nginx實現一樣的功能
經過服務網關統一貫外系統提供REST API的過程當中,除了具有服務路由、負載均衡功能外,還具有了權限控制等功能。
Zuul是從設備和網站到Netflix流應用程序後端的全部請求的攔截。
Zuul使用一系列不一樣類型的過濾器,使咱們可以快速靈活地將功能應用於咱們的邊緣服務。過濾器能夠幫助咱們執行如下功能:
服務路由
經過服務路由的功能,對外提供服務時,只須要經過暴露Zuul中配置的調用地址,就可讓調用方統一來訪問咱們的服務,而不須要了解具體提供的主機信息。
經過上面配置,全部訪問 /api-a-url/** 的訪問都映射到 localhost:2222上面
提供兩種方式映射
服務過濾
對開放服務還須要一些安全措施來保護客戶端只能訪問它應該訪問到的資源。能夠用過濾器來實現對外服務的安全控制
例子:檢查請求中是否包含accessToken參數,若是沒有就拒絕訪問
#
分佈式應用程序的分佈式開源協調服務。
公開了一組簡單的基礎原件,分佈式應用能夠在這些原件之上實現更高級別的服務。
好比同步、配置維護、羣集和命名。
設計目標
Zookeeper容許程序經過一個共享的相似於標準文件系統的有組織的分層命名空間分佈式處理協調。
Zookeeper的實現提供了一個優質的高性能、高可用,嚴格的訪問順序。
Zookeeper是很是簡單和高效的。由於它的目標就是,做爲建設複雜服務的基礎,好比同步。zookeeper提供了一套保證,他們包括:
#
Apache Dubbo是一個高性能,輕量級,基於Java的RPC框架。提供三個關鍵功能,包括基於接口的遠程調用,容錯和負載平衡,以及自動服務註冊和發現。
功能
#
獨立的開源自動化服務器,可用於自動執行與構建,測試,交付或部署軟件相關的各類任務。
#
重溫一下微服務的概念:微服務架構是一種架構模式,提倡將單一應用程序劃分紅一組小的服務,每一個服務運行在其獨立的進程中,服務間採用輕量級的通訊機制互相溝通(一般是基於HTTP協議的RESTful API)。每一個服務都圍繞着具體業務進行構建,而且可以被獨立的部署到生產環境,類生產環境等。
獨立部署和自動化部署不是一個概念。自動化部署相對簡單,但獨立部署關鍵和難點在於獨立
若是失去了服務獨立部署的能力,一個微服務架構的威力將大打折扣。
舉一個例子
程序員,開發了一個網上商城。代碼Push到Github並經過持續集成(Continuous integration,CI)構建持續交付流水線,最終自動化部署到雲端產品環境,供用戶訪問使用。
隨着用戶和訪問量的增長,需求和功能也愈來愈多。
使用微服務能夠將後臺部分拆成3個服務,簡稱ABC。
當對A服務作了一次新的提交以後,A服務的最新版本升級到了1.1 。這個新的版本之外的破壞了A與B之間的契約,錯誤的調用了B的接口,致使出現了錯誤。
雖然有完善的UT(單元測試),但UT沒法發現服務之間的集成是否被破壞。那麼是否能夠加集成測試呢?
測試多服務集成的測試統一稱做端到端測試(End-to-End tests,簡稱E2E測試)
當A服務逇新版本破壞了B服務的集成時,E2E測試就會及時診斷出來,並阻止A服務的最新版本想產品環境流動,保證不被破壞。
但添加了E2E測試,解決了服務間集成的驗證問題,但也失去了微服務架構的重要特徵:服務的獨立交付。
假設A服務的修復過程當中,BC服務也提交了代碼,可是A服務因E2E測試掛掉的問題還未被修復,因此B和C的新版本也被E2E測試攔下來。此時E2E測試就像是一個亮起紅燈的路由,阻塞了全部服務通往產品環境的通道。
因此說,隨着集中E2E測試的添加,質量被保證的同時,微服務架構也悄然失去了服務獨立交付的能力。
雖然可以在代碼庫,部署結構上,甚至在組織上進行服務劃分,但最後一個交付的E2E測試,讓全部的服務又糾纏在一塊兒了,服務化拆分形同虛設,最終獲得了一個看起來像微服務架構的單體應用。
解決方法也很簡單:Inline E2E tests
即並不添加新的集中的Pipeline作E2E測試,而是爲每個服務的Pipeline都添加一個相同的E2E測試的Stage,至關於將E2E測試lnline到每一個服務各自的部署流水線中
其實lnline E2E測試還不是最關鍵的,變化點就是假設A服務有了新的提交,運行到A服務本身Pipeline的E2E測試的時候,此時的E2E測試並非像以前同樣獲取B和C服務的最新代碼庫版本作集成驗證,而獲取當前產品環境上的B和C服務的已部署當前版本作集成驗證。
如圖所示A服務的版本從1.0升級到1.1,當前產品環境的B和C版本是2.0和3.0。執行A服務Pipeline上的E2E測試時,驗證過A和B集成存在問題,測試變紅,Pipeline掛掉,從而阻斷了A服務的1.1版本部署到產品環境,保證了產品環境不會被1.1版本破壞。
假設A尚未被修復,B也有了新的提交,此時B服務Pipeline上的E2E測試並不獲取當前A服務的代碼庫作集成測試,而是獲取產品環境上的當前版本作集成測試。假設B和A之間的集成沒有問題,那麼B就被成功交付到產品環境裏面了。
契約測試也是這兩年伴隨微服務架構的興起,常常被說起的一種比較新的測試類型。測試金字塔中,位於E2E和Component Test(單個服務API)之間
簡單的理解,契約測試就是一種能夠用相似於單元測試的技術驗證兩個服務之間集成的測試技術。相比於更低層次的單元測試的優點是實現方式上又相似於單元測試,更輕量,跑的更快,覆蓋的範圍天然能夠更廣更細
契約測試替換掉E2E測試以後,這個架構也會變得更復雜,目前契約測試的框架也有不少,例如Pact或SpringContracts等。
A服務調用B服務的一個API,稱爲A和B之間存在一個契約,即B應該提供知足契約要求的API,而A也應該按照這個契約約定的方式來調用B的這個API。
這個過程當中A做爲調用方,稱之爲Consumer端。B做爲被調用方,稱之爲Provider端
若是A和B都履行契約,按照契約定義的約定調用和被調用,就能夠認爲集成不會有問題。但不管是B修改了API破壞契約,仍是A修改了調用API的方式破壞契約,都會致使契約被破壞,反映到測試上就是契約測試失敗。
每一個契約,例如A->B,都會有Consumer端和Provider端生成的兩個產出物:分別是a-b.consumer.json.1.1(由Consumer端生成的契約文件,因此版本也是Consumer端A的版本號)和a-b.provider.jar.2.0(由Provider端生成的契約驗證測試包)這個jar包其實就是一組測試,輸入的是a-b.consumer.json,產出則是測試的結果,也就是契約的驗證結果:成功或失敗
能夠把契約文件當成一把鑰匙,測試包當成一把鎖。契約測試的執行過程就像是用鑰匙試着去開這把鎖:若是能夠打開,認爲這A1.1->B.20的契約是知足的,反之契約就是被破壞了。
契約測試不像E2E測試,是有方向的,因此看到a-b和b-a是兩個不一樣契約。
只有當A1.1->B.2.0和B2.0->A1.1雙向的契約都被驗證經過後,才能認爲A和B的集成是沒有問題的。
假設已經構建了ABC三個服務兩兩之間的契約測試。此時A服務有了新的提交升級到了1.1版本,如何才能經過契約測試來驗證A1.1版本可否交付到產品環境呢?
只要經過A的1.1版本的最新代碼,生成全部A做爲Consumer端的契約文件(a.b.consumer.json.1.1和a-c.consumer.json.1.1),用兩把鑰匙去試着開對應的鎖。
若是均可以打開,就證實A的新版本做爲Consumer端與產品環境的B和C的服務是兼容的。
還要考慮A做爲Provider的狀況,是經過A的1.1版本的最新diamante生成A版本做爲Provider端的契約測試,拿着這兩把新鎖,去試着用產品環境上的兩把鑰匙去開。
重點
¥