我眼中的ASP.NET Core之微服务
前言
前幾天在博客園看到有園友在分享關于微軟的一個微服務架構的示例程序,想必大家都已經知道了,那就是eShopOnContainers。
我們先不看項目的后綴名稱 OnXXX ,因為除了 OnContainers 還有 OnAzure,OnWeb,OnKubernetes 以及 OnServiceFabric。
我們就還是來先說說 eShop 這個項目吧,eShop 是 ASP.NET Core 發布之后微軟新開源出來的一個示例項目,想必大家之前也都知道微軟放出來的關于 Web 的示例項目還有 PetShop, Music Store 這兩個項目。關于這兩個項目我們就不做過多的介紹了,但是關于這兩個項目的架構風格我們不得不提起。
PetShop:WebFrom 的示例程序。典型的三層架構風格的應用程序。
MusicStore: 針對于 MVC3-5 框架和 EF 的一個示例程序。無明顯架構風格。
eShop: 針對于 ASP.NET Core 的示例程序。它是一個 Rest 架構風格的應用程序。
我們從微軟放出來的這些示例程序中也許可以看出些許東西,那就是近些年來關于架構風格的演變,或者叫微軟架構風格的演變,在這里我不打算討論關于軟件架構更加深層次的一些這種東西,我們只從我們能夠理解的東西看起。
微軟架構風格
我不知道有沒有人看過這本書,目前已經絕版了,它是早年間關于微軟架構風格的一本指南書,里面描述了微軟體系的架構風格的一些匯總。
這本書中列出來了以下這些架構風格:
Client/Server Architectural Style
Component-Based Architectural Style
Domain Driven Design Architectural Style
Layered Architectural Style
Message-bus Architectural Style
N-Tier / 3-Tier Architectural Style
Object-Oriented Architectural Style
Service-Oriented Architectural Style
我們可以看到微軟所開源出來的這些示例程序其實都是在遵循這些架構風格中的某一種或者是多種。 PetShop 屬于 N-Trie ,Music Store 屬于 Layered,eShop 屬于 Service-Oriented。
當然在 eShop 中微軟不但使用了 Service-Oriented ,其中還包括 Domain Driver Design(DDD), Message-bus 也都應用到了示例程序中。
由此,我們可以看出,在現代的應用程序架構風格中,已經不是某一種架構風格可以獨自獨領風騷了,它一定是多種架構風格的混合體,互相補充來構建更加強大的應用程序解決方案。
下面進入到我們本篇博客的主題微服務。不,應該是 ASP.NET Core 中的微服務,有同學可能會說了,微服務是一種架構風格,它并不和某一種語言相關,也不是只有.NET 中才有微服務。在這里我想說的是我不想去討論大眾眼中的微服務,因為太多人去說這些東西了,不就你打開 InfoQ 或者 cnBeta 這些網站,滿屏的都是微服務的東西。 所以你可以說我的微服務叫 Savorboard 式微服務。
既然要說 ASP.NET Core 中的微服務,那就必須又要說到 eShop 這個項目了,之前沒有給大家分享關于 eShop 這個項目的一些信息其實是有原因的,因為這個項目有很多東西它沒有實現完,或者是叫它還是一個半成品,給大家分享的話大家又運行不起來,所以就一直在等一個合適的時間來做。
ASP.NET Core 微服務
ASP.NET Core 其實是一個非常適合做微服務的一個 Web 框架,它足夠的輕量級并且擁有超高的性能。并且對于 Rest 這些風格的接口支持的非常的友好。更多好處我其實不太愿意去說,因為只有你自己去體會才會知道。還不如來點實在的,去教你們怎么在 ASP.NET Core 中構建一個或者叫一組微服務集群。在我看來,有時候講那么多理論也都是扯淡的。那就廢話不多說,開始吧。
在開始之前還是要說一句,你的架構一定要符合你的業務和需求,不要為了架構而架構。舉個例子,你的網站每天的訪問量就那么幾百號人,以后也不會大量的增加,你又是分布式又是大數據又是docker集群的這不沒事給自己找事干么。切記。
第一步,業務拆分。
業務拆分其實有時候是需要經驗積累的,有時候不僅僅是需要你有軟件架構經驗,還需要你有行業知識的經驗。這時候你的業務拆分的才足夠合理,不會隨著時間的推移導致你的微服務變“大”。
如果你對 DDD 中領域建模這種軟件建模方式在行的話可能會幫助你解決大量的潛在問題,如果你不會也沒關系,因為你可以去學呀~ 2333
第二步,建模。
在微服務架構中,建模仍然是重要的一步,因為你使用的是 EF Code First , 建模質量的好壞肯定是和你以后的代碼質量掛鉤了。如果你不使用 EF,那我們就不能愉快的做朋友了。
給大家個小提示,如果你的項目中全是增刪改查,沒有什么業務算法或者邏輯可言的話,就讓你的模型盡量的符合你的界面上的顯示字段,這樣可以最大化的提升開發效率。
第三步,寫代碼。
這個時候我希望你拋棄掉三層架構這種架構風格的設計,不是說那種不好,而是有更加便捷的方式了,你需要知道,你寫的每一個 Action 都應該是盡量的簡單,再去調用 BLL 層繞一大圈子就為了一個增刪改查純粹是給自己找活干,那樣并沒有提高項目的可維護度。
前段時間在 QQ 群聽學姐說過這么一句話,就是佛家的人生三重境界之說, 即:“看山是山, 看水是水; 看山不是山, 看水不是水; 看山還是山, 看水還是水。”
這一句話對于軟件架構的設計過程中同樣適用,在最初的時候,我們對于軟件程序不懂就按照官方給的示例程序來進行設計,即看山是山;隨著我們的知識,見解,經驗的積累我們有了自己的一些看法理解,出了自己的各種框架,即看山不是山;隨著時間的推移,我們已經悟到了其中的精髓,又回到了官方示例,大道至簡,即看山還是山。
第四步,重構。
當你寫完代碼之后,我認為有一個比較重要的步驟就是對寫的代碼進行一番重構,重構一般從兩方面下手,第一方面是代碼的命名以及格式,第二方面是代碼的組織結構。
針對于代碼命名以及格式的重構其實是有方法和技巧的,比如方法的命名以及方法的拆分等可以從<<重構>>這些書中來獲取一些指導意見等,對于代碼格式的話基本上現代的IDE都提供了很好的格式化工具,使用便是。
針對于組織結構的重構有時候是需要依賴很多你的經驗的,經驗豐富的程序員知道如果的去對寫過的代碼進行抽象,然后利用某種設計模式或者是面向對象的原則來讓代碼更加的利于維護和擴展,這種技能往往更難掌握,需要你去閱讀很多的別人優秀的代碼,然后去思考和學習。
OK,以上就是在構建單個微服務程序的個人總結的一些指導原則吧。
部署方式
指導原則可以幫助我們在構建系統的時候使其保持一個良好的結構,但是你還需要從整體上來把控整個微服務的布局。什么意思呢?
我們知道,微服務最良好的部署方式就是使用 Docker 容器進行部署,因為這樣便于管理和配置。
在以前的單體結構的項目中也可以使用Docker進行整塊的部署,我們可能部署到多個容器中,然后前置一個負載均衡器進行路由的轉發,這樣也是可以的。
通常情況下,即使我們的程序架構風格不是微服務,那么在組織代碼結構時,也會進行模塊的劃分,比如劃分為會員,商品,庫存等。下面是一個單體應用整塊部署使用Docker的部署圖:
但是這種模式其實與容器的初衷是有一點違背的,容器所倡導的是一個容器只做一件事情。整塊部署有一個明顯的缺點是,如果隨著應用程序的擴展那么每次代碼的修改都要全部進行重新發布,但是我們經常修改的代碼可能就是某一快的功能,而另外一些代碼則永遠不會動,這樣不但發布程序的時候發布包很大,也容易出錯,出問題造成的影響也比較廣。
比如,在一個電商網站中,有一些模塊是經常發生變化的,比如一些促銷,產品等頁面,這些頁面的訪問量也很大,而另外一些頁面比如用戶中心積分查看,歷史訂單查看這些功能則不會經常變動,并且訪問量要小很多。那么如果他們都在一個系統中,勢必會引起這些問題:1、性能優化,如果訪問量很高的模塊出現性能問題,那么你只能針對整個程序進行擴展部署,而不是單個模塊。2、測試,由于模塊的依賴,那么在修改一塊地方的時候,必須重新對整個應用程序進行一次測試,并且重新部署所有這些實例。3、無法進行擴展,你無法簡單的進行接口或者服務的擴展,這會使SOA變得很困難。
那么我們就再順便說一下SOA,我們知道大多數的公司在 .NET FX 時代使用 WCF 技術進行項目的 SOA 化,比如常見簡單的會使用 SOAP ,HTTP,MQ等進行通訊,他們也會把系統進行劃分(子系統)和分層。聽起來可能和微服務有點像,那么他們有什么區別呢? 想必這是一個很多人討論過的話題,那么直接說結論吧。 微服務它來自于SOA,但是和SOA不同的是它并沒有那么重量級,什么意思呢?比如它沒有SOA中的像集群的Broker, 那么大的組織的劃分,中央負責人, 還有企業服務總線 (ESB)等。
然后就是我們的主題微服務,微服務架構的定義就是一組小型的服務。每一個服務都位于自己的進程中,并且使用諸如HTTP, WebSockets,或者 AMQP 之類的協議進行通訊。它很小,并且專注于做好一件事,這個很重要,它看起來像OOP中的單一職責原則,如果你2周之內不能完成一個微服務模塊,那么可能你對于邊界劃分出了點問題。
關于微服務的優缺點不做過多的介紹了,有興趣的同學可以看一下在我博客里面的 Martin Fowler 的?這篇文章。
這篇文章提到了『微服務設計』這本書,如果你想對微服務有更多了解的話可以看一下這本書,建議購買。
微服務中的一些技術挑戰
下面需要說的是個人對于在構建微服務的過程中會面臨的一些問題,或者說叫做挑戰吧。
1、微服務的邊界怎么定義。
上一篇文章已經提到過了,在定義微服務邊界的過程中,DDD中的指導原則會幫助你大忙。 這可能是你在構建微服務過程中遇到的第一個難題,一個良好的微服務能夠對其他微服務盡可能少的依賴,同一個應用程序中你需要用不同的上下文進行解耦,每個上下文有可能是使用不同的程序語言的。這些上下文應該被獨立的定義和管理。比如一個User,在 Identity 上下文可能是一個用戶,在 CRM 中是一個客戶,在訂單上下文是一個買家,等等。
2、如何跨微服務進行查詢。
因為我們已經微服務化了,所以我們的應用程序數據可能分布在不同的數據庫中,那么如何實現從多個為微服務器數據庫中查詢數據成為一個難題了。
比如,我們前臺的數據展示頁面需要一個銷售統計的報表,其中的數據分別來源于訂單,庫存和商品。那么我們應該怎么樣來處理這種復雜性呢? 目前流行的解決方案有以下幾種:
API網關。?使用API網關來對多個微服務器的數據庫進行聚合。 但是在實現這種模式的時候你需要非常的小心,它有可能是你系統中性能的瓶頸,甚至它有可能違背微服務的自治原則。為了盡可能避免這個陷阱,你需要設計多個細粒度的 API 網關,每個網關關注系統一個垂直領域的“切片”區域,或者是一個業務領域。現在大部分的云提供商都提供的有 API 網關相關服務,比如AWS的 Amazon API Gateway,Azure 的 Establish API Gateways 等,借助于這些服務可以方便的對 API 進行管理。
CQRS與讀表。?不知道大家有沒有聽說話物化視圖(Materialized View)這個名詞。你可以理解為遠程視圖,使用這種方法,你可以提前準備好一個只讀表,其中包括多個微服務的數據,這個只讀表的結構和你展示給客戶的頁面數據是對應的。
那么有同學可能會存在這樣一個問題,假如我基于不同的數據庫建立一個物化視圖,那么在我建立物化視圖的過程中,我應該怎么樣進行查詢,因為對于單個數據庫的查詢可能仍然是復雜的。確實如此,在以前單個應用程序的時候,我們在呈現個客戶端需要的數據的時候,可能會是一個復雜的SQL Join連接查詢的結果。那么這里的解決方案就是,我們需要建立一個和我們業務無關的一個單獨的數據庫,然后這個數據庫中會包含一些和界面上需要的數據進行一一對應的一些查詢用的表,然后我們應用程序中引入 CRQS 這種模式,將需要的數據寫入到這些查詢表中。
這不僅解決了跨微服務查詢這個難題,并且也提高了性能。但是引入CQRS也就意味著你需要擁抱最終一致性。
數據中心的 “冷數據”。?對于一些不需要做實時數據的復雜查詢或者報表,通常是將微服務的“熱數據”作為“冷數據”導出到數據中心以供報表。這個數據中心可能是一個基于大數據的系統,比如 Hadoop,AWS的Redshit,Azure的SQL Data warehosue等。
同步的過程你可以使用事件驅動這種通訊技術,或者是一些數據庫提供的基礎設施中的導入/導出工具等。如果使用事件驅動的話,其過程有點類似上面的CRQS查詢過程。
3、如何實現多個微服務的數據一致性。
我們知道在每個微服務都是具有高內聚的特點的,外部想訪問微服務的數據只能通過API訪問,那么我們在實現一個微服務到另外一個微服務這種業務流程的時候,怎么同時保持多個微服務之間的一致性呢?
我們回到 eShop 這個微軟的示例項目上來,來看看怎么處理的。 首先,Catelog 這個微服務是負責維護商品相關的信息,包括庫存。 Ordering 這個微服務負責訂單的管理,當新創建一個訂單的時候,它必須驗證這個訂單的商品是否具有足夠的庫存(如果不夠可能涉及到缺貨登記),所以它就必須要和Catelog微服務打交道。在以前單服務的程序中可以簡單的使用ACID事務來進行檢查并且直接更新可用庫存。但是現在不能這樣了,每個微服務都擁有自己的數據庫,當前的服務不能直接去操作其他服務的數據庫的,這個時候我們為了實現我們需要的功能怎么辦呢?我們可以使用異步通訊,比如消息或者事件驅動這種方式,這也是 eShop使用的方式。
這里就涉及到一個理論知識,就是?CAP定理。也就是說你必須要在可用性和ACID強一致性之間做出選擇。大多數基于微服務的場景都需要可用性和高可擴展,而不是強一致性。所以為了保證在關鍵場景下應用程序能夠正常響應,我們一般會選擇犧牲強一致行從而追求最終一致性。
4、如何跨微服務進行通訊。
微服務之間的通訊,是一個比較大的技術挑戰。這個時候你不應該去關注你應該使用什么協議,比如是使用 Http、Rest、AMQP
、消息、或者其他東西。相反,你應該了解每種協議的優缺點,你使用該協議想達到什么樣的一個目的,以及這種協議怎么樣和你的微服務更好的進行耦合。根據耦合程度,當發生故障的時候,是不是對系統有非常大的影響。
像微服務這種分布式系統中,是由許多的組件在很多的服務器之間共享的。這些組件最終可能會發生故障,當這些組件故障的時候,你需要考慮的是是否會引起更大的故障,所以你需要在設計你的微服務的時候充分考慮到這些通訊過程中常見的風險。
目前一種比較流行的做法是使用基于 HTTP 協議 REST 方式的微服務,這是因為它們很簡單。而且基于 HTTP 的這種方式是完全可以接受的,當然這也取決于你當前的使用場景。 假如說你是在客戶端或者是API網關中使用 HTTP 進行請求和相應以及進行微服務交互,那么它足夠用了。但是,假如你是跨微服務之間進行HTTP的調用長鏈的話,就像在使用數據庫事務那樣使用,那么你的應用程序最終會遇到麻煩的問題。
事實上,如果你在內部微服務之間通訊也是通過HTTP的方式,那么我可以理解為你正在使用的是一個單機的應用程序,只是他們是基于進程之間的HTTP,而不是進程內的通訊。
因此,我們在設計微服務的時候,為了其具有更好的彈性,我們應該盡量減少這種跨微服務的通訊。這種情況下,我們可以使基于消息或者事件的異步通訊方式來達到目的。
那么在 .net 中有沒有什么現成的解決方案可以用呢? 答案是肯定的,請向下看。
總結
這一篇主要是對上一篇的一個補充,以及涵蓋了微服務的部署方式以及在構建服務器的過程中會遇到的一些技術挑戰。
下一節,我們將說一下?基于消息的異步通訊, 我將會給出在 .NET Core 中的具體的解決方案,敬請期待。
相關文章:
開篇有益-解析微軟微服務架構eShopOnContainers(一)
Identity Service - 解析微軟微服務架構eShopOnContainers(二)
Catalog Service - 解析微軟微服務架構eShopOnContainers(三)
EventBus In eShop -- 解析微軟微服務架構eShopOnContainers(四)
微服務的概念——《微服務設計》讀書筆記
微服務架構師的職責——《微服務設計讀書筆記》
建模:確定服務的邊界——《微服務設計》讀書筆記
微服務集成——《微服務設計》讀書筆記
服務的協作:服務間的消息傳遞——《微服務設計》讀書筆記
拆分:分解單塊系統——《微服務設計》讀書筆記
部署:持續集成(CI)與持續交付(CD)——《微服務設計》讀書筆記
測試——《微服務設計》讀書筆記
監控——《微服務設計》讀書筆記
安全——《微服務設計》讀書筆記
康威定律和系統設計——《微服務設計》讀書筆記
規模化微服務——《微服務設計》讀書筆記
Net分布式系統之:微服務架構
原文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-microservice2.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的我眼中的ASP.NET Core之微服务的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 微服务中的异步消息通讯
 - 下一篇: ASP.NET Core之跨平台的实时性