前言
接上一篇。
上一篇未完待續的原因是當時剛好是6-30號晚上馬上12點了還沒寫完,然后我想趕在7月1號之前發出去,所以當時就發了。然后在發的時候出了一點問題,結果發出去的時候剛好是 7.1號 00:00分,所以就很尷尬~~
這一篇,我們就接著說一說微服務吧。
接上文
第四步,重構。
當你寫完代碼之后,我認為有一個比較重要的步驟就是對寫的代碼進行一番重構,重構一般從兩方面下手,第一方面是代碼的命名以及格式,第二方面是代碼的組織結構。
針對于代碼命名以及格式的重構其實是有方法和技巧的,比如方法的命名以及方法的拆分等可以從<>這些書中來獲取一些指導意見等,對于代碼格式的話基本上現代的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 中的具體的解決方案,敬請期待。
重構>本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-microservice2.html
作者博客:Savorboard
歡迎轉載,請在明顯位置給出出處及鏈接
文章列表