https://www.shengchulai.com/blog-QEFWfPcRJ6.htm
微服務架構已經(jīng)成為現(xiàn)代應用程序開發(fā)的主流。雖然說它能夠解決某些問題,但卻也不是萬金油。而我們在使用這個體系架構時,還有許多的問題要我們解決。這就需要學習這些問題的通用模式,并通過可復用的解決方案來解決問題。因此,有必要討論微服務的設計模式。但是在深入研究設計模式之前,我們還需了解微服務架構的構建原理:可拓展性
可用性
彈性
獨立自主
分散治理
故障隔離
自動配置
通過DevOps持續(xù)交付
應用這些構建原理會帶來一些挑戰(zhàn)和問題。讓我們討論這些問題及其解決方案。微服務就是讓應用服務松散耦合,但是將應用程序分解成較小的部分還必須要在邏輯上實現(xiàn)。那我們?nèi)绾螌贸绦蚍纸鉃樾⌒头漳兀?/section>一種策略就是按業(yè)務能力分解,業(yè)務能力是企業(yè)業(yè)務價值的體現(xiàn)。業(yè)務的功能取決于業(yè)務的類型。例如,保險公司的業(yè)務能力通常包括銷售,市場營銷,承保,理賠處理,開票,合規(guī)性等。每種業(yè)務能力都可以視為一種服務,但它面向的是業(yè)務而不是技術。按業(yè)務功能來分解應用程序或許是個不錯的思路。但是我們可能會遇到某些比較難以分解出來的類(God Classes),這種類在多種服務中通用。比如,訂單類用于“訂單管理”,“接單”,“訂單交付”等業(yè)務中。那我們該如何來分解呢?對于這種難以分解出來的(God Classes)類,使用DDD(即領域驅動設計)可以解決。它使用子域和有界上下文概念來解決此問題。DDD將為企業(yè)創(chuàng)建的整個域模型分解為子域。每個子域都有一個模型,該模型的范圍稱為有界上下文。每個微服務將圍繞有界的上下文進行開發(fā)。注意:確定子域并不是件容易的事,這需要對業(yè)務有一定的了解。像業(yè)務功能一樣,通過分析業(yè)務及其組織結構并確定不同的專業(yè)領域來標識子域。到目前為止,我們所討論的設計模式都是分解未開發(fā)的應用程序,但是我們所做的工作中有80%是用于已開發(fā)的應用程序(brownfield applications)中,這是個大型的整體應用程序。上述所有設計模式并不是適用于它們,因為把它們作為一個整體應用的同時將它們拆分成一個個較小的部分是一項艱巨的任務。扼殺者模式可以解決此類問題。扼殺者模式是以纏繞類的藤蔓植物作為類比。該解決方案是與Web應用程序配合使用,在Web應用程序之間來回調用,對于每個URL的調用,一個服務可以分為不同的域并作為單獨的服務托管。這個想法是一次做一個域,這將會創(chuàng)建兩個單獨的應用程序,它們并行存在于同一個URL空間中。最終,新重構的應用程序會“扼殺”或者替換原來的應用程序,直到最后可以停止整個應用程序。當一個應用程序被分解為多個微服務時,還有一些問題需要解決:如何調用多個微服務來抽象化生產(chǎn)者信息。
在不同設備上(比如臺式機,移動設備和平板電腦),由于UI可能存在不同,應用程序需要不同的數(shù)據(jù)來響應相同的后端服務。
不同的使用者對于可重復使用的微服務響應格式可能不同,那由誰來進行數(shù)據(jù)轉換或者字段操作。
生產(chǎn)者微服務可能不支持某些類型協(xié)議的處理方式。
API網(wǎng)關有助于解決因微服務實現(xiàn)而引起的許多問題,而不僅限于上述問題。API網(wǎng)關是任務微服務調用的單一入口點。
用作代理服務,將請求路由至相關的微服務,從而抽象出生產(chǎn)者的詳細信息。
將一個請求發(fā)送至多個服務,然后把響應結果聚合后發(fā)送回消費者。
通用的API網(wǎng)關無法滿足所有的消費者需求??梢詾槊糠N特定類型的客戶端創(chuàng)建細粒度的API。
將協(xié)議請求(例如AMQP)轉換成另外一個協(xié)議(例如HTTP),反之亦然,以便生產(chǎn)者和消費者處理它。
它還可以減輕微服務的身份驗證/授權責任。
我們已經(jīng)討論過如何解決API網(wǎng)關模式中的聚合數(shù)據(jù)問題。但是,接下來我們將會更加全面地討論它。比如,在將業(yè)務功能分解為幾個較小的邏輯代碼時,有必要考慮聚合每個服務返回的數(shù)據(jù)。這個任務不能留給消費者,因為如果這么做消費者可能需要了解生產(chǎn)者應用程序的內(nèi)部實現(xiàn)。聚合模式有助于解決此類問題。它討論了關于如何聚合來自不同服務的數(shù)據(jù),然后將最終響應結果發(fā)送給消費者。我們可以通過以下兩種方式來實現(xiàn):復合微服務將調用所有必需的微服務,整合數(shù)據(jù),并在回退數(shù)據(jù)之前轉換數(shù)據(jù)。
用API網(wǎng)關將請求劃分為多個微服務并聚合數(shù)據(jù),然后再將其發(fā)送給使用者。
如果要應用任何業(yè)務邏輯,建議選擇使用復合微服務。否則,API網(wǎng)關是已建立的解決方案。
當通過分解業(yè)務功能/子域來開發(fā)服務時,負責用戶體驗的服務必須從多個微服務中提取數(shù)據(jù)。在整體應用中,從UI到后端服務只有一次調用,以檢索所有數(shù)據(jù)并刷新/提交UI頁面。但是,現(xiàn)在情況不一樣了。我們需要了解如何去做。對于微服務,必須將UI設計為具有屏幕/頁面的多個部分/區(qū)域的框架。每個部分都調用單個后端微服務以提取數(shù)據(jù),這稱為組合特定服務的UI組件。比如AngularJS和ReactJS之類的框架可以輕松地做到這一點。這些屏幕稱為單頁應用程序(SPA)。這使應用程序可以刷新屏幕的特定區(qū)域而不是刷新整個頁面。如何來定義微服務的數(shù)據(jù)庫體系結構?讓我們來看下需要解決的那些問題:服務必須松耦合。它們可以獨立開發(fā),部署和擴展。
業(yè)務事務可能會強制跨越多個服務的不變量。
一些業(yè)務事務需要查詢多個服務中的數(shù)據(jù)。
為了進行擴展有時必須對數(shù)據(jù)庫進行復制和分片。
不同服務具有不同的數(shù)據(jù)存儲要求。
為了解決上述問題,必須為每個微服務設計一個數(shù)據(jù)庫。它必須僅對該服務專用,只能由微服務API訪問它,其他服務無法訪問。例如,對于關系型數(shù)據(jù)庫,我們可以使用每個服務一個專用的表,每個服務一個schema或每個服務一個數(shù)據(jù)庫服務器。每個微服務應具有一個單獨的數(shù)據(jù)庫ID,這樣就可以提供單獨的訪問來設置一個隔離,防止它使用其他服務的表。我們已經(jīng)討論了每個服務一個數(shù)據(jù)庫是微服務的理想選擇,這在應用程序開發(fā)前并且要使用DDD開發(fā)時,是可能實現(xiàn)的。但是,如果應用程序是一個整體并且試圖闖入微服務時,那么非規(guī)范化就不是那么容易了。在這種情況下合適的架構是什么呢?每個服務共享數(shù)據(jù)庫不是理想的選擇,但卻是上述情況的可行解決方案。大多數(shù)人認為這是微服務的反模式,但這對于棕地應用程序來說,是將應用程序分解成較小邏輯部分的一個很好的開始。這不適合綠地應用程序。在這種模式下,一個數(shù)據(jù)庫可以與一個以上的微服務對齊,當然也不是無限制的,最多限制為2-3個微服務,否則擴展性,自主性和獨立性將難以執(zhí)行。一旦我們實現(xiàn)了每個服務的數(shù)據(jù)庫,就肯定會有查詢,而且這需要來自多個服務的聯(lián)合數(shù)據(jù)——這是不可能的。那我們應該如何在微服務架構中實現(xiàn)查詢呢?CQRS建議將應用程序分為兩部分——命令端和查詢端。命令端負責處理創(chuàng)建,更新和刪除請求。查詢端負責通過使用實例化視圖來處理查詢的部分。通常將事件源模式與CQRS一起使用來為任何數(shù)據(jù)更改創(chuàng)建事件。通過訂閱事件流,可以使實例化視圖保持更新。當每個服務都有自己的數(shù)據(jù)庫并且一個業(yè)務事物跨越多個服務時,我們該如何確保各個服務之間的數(shù)據(jù)一致性呢?例如,對于客戶有信用額度的電子商務應用程序,該應用程序必須確保新訂單不會超過客戶的信用額度。由于訂單和客戶位于不用的數(shù)據(jù)庫中,因此應用程序不能簡單地使用本地ACID事務。Saga相當于由幾個子請求組成的高級業(yè)務流程,每個子請求在單個服務中更新數(shù)據(jù)。每個請求都會有一個補償請求,該請求在請求失敗時執(zhí)行。它通過兩種方式實現(xiàn):編排(Choreography):當沒有總協(xié)調時,每個服務都會生成和監(jiān)聽另一個服務時間,并決定是否應該采取行動。
編排器(Orchestration):負責一個Saga的決策和業(yè)務邏輯排序
一個應用程序由在多臺服務器上運行的多個服務實例組成,請求通??缭蕉鄠€服務實例。每個服務實例均以標準化格式生成日志文件。我們該如何通過日志了解特定請求的應用程序行為呢?我們需要一個集中式日志記錄服務,該服務可以匯總每個服務實例的日志。用戶可以搜索和分析日志。他們可以配置某些消息出現(xiàn)在日志中時觸發(fā)警報。例如,PCF(Pivotal Cloud Foundy)確實具有Loggeregator,它從PCF平臺的每個組件(路由器、控制器、diego等)以及應用程序中收集日志。AWS Cloud Watch也做了同樣的事情。當使用微服務架構而導致的服務組合增加時,對事務進行監(jiān)控就變得非常重要,以便在出現(xiàn)問題時可以監(jiān)視模式并發(fā)送告警。我們應該如何收集指標來監(jiān)控應用程序性能呢?需要一個度量服務來收集關于單個操作的統(tǒng)計信息。它應該聚合提供報告和告警的應用程序服務的指標。聚合度量有兩種模型:推送:服務將指標推送到指標服務,例如NewRelic,AppDynamics
提?。褐笜朔諒姆罩刑崛≈笜?,例如Prometheus
在微服務架構中,請求通??缭蕉鄠€服務。每個服務通過跨多個服務執(zhí)行一個或多個操作來處理請求。那么,我們?nèi)绾胃櫠说蕉苏埱髞斫鉀Q問題呢?為每個外部請求分配一個唯一的外部請求ID
將外部請求ID傳遞給所有服務
在所有的日志消息中包含外部請求ID
記錄有關請求和在集中服務中處理外部請求時執(zhí)行的請求和操作的信息(例如,開始時間、結束時間)
Spring Cloud Slueth以及Zipkin server都是通用實現(xiàn)。當實施了微服務架構時,服務可能會啟動,但無法處理事務。在這種情況下,如何確保請求不會轉到那些失敗的實例呢?使用負載均衡模式實現(xiàn)。每個服務都需要有一個端點,可以用來檢查應用程序的健康度,比如/health。這個API應該檢查主機的狀態(tài)、與其他服務/基礎設施的連接以及任何特定的邏輯。Spring Boot Actuator確實實現(xiàn)了一個/health端點,并且該實現(xiàn)也可以自定義。服務通常也會調用其他服務和數(shù)據(jù)庫。對于開發(fā)、QA、UAT、prod等每個環(huán)境,端點URL或某些配置屬性可能不同。任何這些屬性的更改都可能需要重新構建和重新部署服務。如何避免對配置更改進行代碼修改呢?外部化所有配置,包括端點url和憑證。應用程序應該在啟動或運行時加載它們。Spring Cloud config server提供了將屬性外部化到GitHub并將其作為環(huán)境屬性加載的選項。應用程序可以在啟動時訪問它們,也可以在不重啟服務器的情況下刷新它們。當微服務出現(xiàn)的時候,我們需要解決一些關于調用服務的問題:使用容器技術,IP地址被動態(tài)分配給服務實例。每次地址更改時,使用者服務可能會中斷,并需要手動更改。
每個服務的URL都必須被使用者記住并成為緊密耦合的。
那么消費者或者路由器如何知道所有可用的服務實例和位置呢?我們需要創(chuàng)建一個服務注冊中心,用來保存每個生產(chǎn)者服務的元數(shù)據(jù)。服務實例在啟動時注冊到注冊中心,在關閉時注銷注冊。消費者或路由器查詢注冊表并找出服務的位置。注冊中心還需要對生產(chǎn)者服務進行健康檢查,來確保只有服務的工作實例可以通過它使用。有兩種類型的服務發(fā)現(xiàn):客戶端和服務器端。客戶端發(fā)現(xiàn)的一個例子是Netflix Eureka,服務器端發(fā)現(xiàn)的一個例子是AWS ALB。服務通常會調用其他服務來檢索數(shù)據(jù),下游服務可能會出現(xiàn)故障。這樣做有兩個問題:首先,請求將繼續(xù)使用服務中斷狀態(tài),耗盡網(wǎng)絡資源并降低性能。其次,用戶體驗將是糟糕的和不可預測的。如何避免級聯(lián)服務故障并優(yōu)雅地處理故障呢?消費者應該通過代理調用遠程服務,代理的行為類似于斷路器。當連續(xù)故障數(shù)超過閾值時,斷路器跳閘,在超時期間,所有調用遠程服務的嘗試都會立即失敗。超時過期后,斷路器允許有限數(shù)量的測試請求通過。如果這些請求成功,斷路器將恢復正常工作。否則,如果出現(xiàn)故障,超時周期將再次開始。Netflix Hystrix是斷路器模式的良好實現(xiàn)。它還可以幫助你定義一個備用機制,可以使用斷路器跳閘。這提供了更好的用戶體驗。使用微服務架構時,一個應用程序可以有許多微服務。假如我們停止所有服務,然后部署一個增強版本,停機時間將是巨大的,并可能會影響到業(yè)務。此外,回滾將是一場噩夢。我們?nèi)绾伪苊饣驕p少部署期間服務的停機時間呢? 可以使用藍綠部署策略來減少或消除停機時間。它通過運行兩個相同的生產(chǎn)環(huán)境(藍色和綠色)來實現(xiàn)這一點。讓我們假設綠色是現(xiàn)有的活動實例,藍色是應用程序的新版本。在任何時候,只有一個環(huán)境是運行狀態(tài), 該環(huán)境服務于所有生產(chǎn)流量。所有云平臺都提供了實現(xiàn)藍綠部署的選項。與微服務架構一起使用的還有許多其他模式,比如Sidecar、鏈式微服務、分支微服務、事件源模式、持續(xù)交付模式等等。隨著我們在微服務方面獲得更多的經(jīng)驗,這個名單還在不斷增長。我現(xiàn)在停下來聽聽你正在使用的微服務模式。
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請
點擊舉報。