中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》
  • 首頁 > 
  • 教程 > 
  • 數據庫 > 
  • 微服務業務開發三個難題-拆分、事務、查詢(上)

微服務業務開發三個難題-拆分、事務、查詢(上)

發布時間:2020-08-10 13:53:02 來源:網絡 閱讀:15515 作者:yushiwh 欄目:數據庫

微服務架構變得越來越流行了。它是模塊化的一種方法。它把一整塊應用拆分成一個個服務。它讓團隊在開發大型復雜的應用時更快地交付出高質量的軟件。團隊成員們可以輕松地接受到新技術,因為他們可以使用最新且推薦的技術棧來實現各自的服務。微服務架構也通過讓每個服務都被部署在最佳狀態的硬件上而改善了應用的擴展性。


但微服務不是萬能的。特別是在 領域模型、事務以及查詢這幾個地方,似乎總是不能適應拆分。或者說這幾塊也是微服務需要專門處理的地方,相對于過去的單體架構。


在這篇文章中,我會描述一種開發微服務的方法,這個方法可以解決這些問題。主要是通過領域模型設計,也就是DDD以及事件源(Event Sourcing)以及CQRS。讓我們首先來看看開發人員在開發微服務的時候會遇到哪些問題吧。



微服務開發過程中的挑戰


模塊化在開發大型復雜的應用的時候是非常有必要的。


現在許多應用大到一個人根本無法完成。而且復雜到光靠一個人去理解是不可能的。


這種情況下,應用就必須被拆分成一個個模塊。在單體應用中,模塊被定義為比方一個java package。然而,這種做法在實踐中并不是很理想,時間長了,單體應用就變得越來越龐大。微服務架構把服務作為一個模塊單元。


每個服務對應一個業務能力,這個業務能力是組織為了創造價值而需要的。例如,基于微服務的在線商店包括各種服務,包括訂購服務(Order Service),客戶服務(Customer Service),目錄服務(Catalog Service)。


微服務業務開發三個難題-拆分、事務、查詢(上)

每個服務都有一個不可***且很難違反的邊界。也就是每個微服務要提供一種單獨而獨立的能力。這樣的話,應用程序的模塊化就更容易隨時間保存。


微服務架構還有其他優點。包括獨立地部署服務,獨立地擴展服務等等這些能力。相比單體來說。


不幸的是,拆分并沒有聽起來那么容易。相當難。


應用的領域模型,事務,查詢這三個東西就是拆分過程中和拆分后你所面臨的拆分難題。讓我們來看看具體原因吧。


問題1 – 拆分領域模型


領域模型模式是實現復雜業務邏輯的一種非常好的方式。比如針對一個在線商店,領域模型將會包含這么幾個類: Order, OrderLineItem, Customer 和 Product。在微服務架構中,Order和OrderLineItem類是Order Service的一部分;Customer是Customer Service的一部分;Product屬于Catalog Service的一部分。


微服務業務開發三個難題-拆分、事務、查詢(上)


拆分領域模型的挑戰之一就是class們通常會引用一個或多個其他類。


比如,Order類引用了該訂單的客戶Customer;OrderLineItem引用了該訂單所訂產品Product。


對于這些想要橫跨服務邊界的引用,我們該怎么辦呢?


稍后你將會看到一個來自領域模型設計的概念:聚合(Aggregate)。我們通過聚合來解決這個問題。


微服務和數據庫


微服務架構的一個非常明顯的功能就是一個服務所擁有的數據只能通過這個服務的API來訪問。


在一個電商網站中,比如,OrderService占有一個數據庫,里邊有一張表ORDERS;CustomerService也有自己的數據庫包含表CUSTOMERS。


通過這樣的封裝,微服務之間就解耦了。


在開發期間,開發人員可以獨立修改自己服務的數據庫shema而不需要與其他服務的開發協調勾兌。


在生產上,服務之間都是隔離的。比如,一個服務從來不會因為另外一個服務占有了數據庫的鎖而導致阻塞等待。


不幸的是,這種數據庫的拆分讓管理數據的一致性以及不同服務間跨表查詢變得困難。


問題2 – 跨服務分布式事務實現


一個傳統的單體應用可以通過ACID事務來強制業務規則從而實現一致性。


想象一下,比如,電商里的用戶都有信用額度,就是在創建訂單之前必須先看信用如何。


應用程序必須確保潛在的多個并發嘗試去創建訂單不超過客戶的信用限額。


如果Orders和Customers都在同一個庫中,那么就可以使用ACID事務來搞定:


BEGIN TRANSACTION
…
SELECT ORDER_TOTAL
 FROM ORDERS WHERE CUSTOMER_ID = ?
…
SELECT CREDIT_LIMIT
FROM CUSTOMERS WHERE CUSTOMER_ID = ?
…
INSERT INTO ORDERS …
…
COMMIT TRANSACTION


不幸的是,在微服務架構中我們無法通過這種方式管理數據的一致性。



ORDERS和CUSTOMERS表被不同的服務所擁有,只能通過各自的服務API訪問。他們甚至可能在不同的數據庫。


一種比較常見的做法就是使用分布式事務來搞定,比如2PC等。但是這種做法對于現代應用來說也許不是一種可行的方案。CAP定理要求你必須在可用性和一致性之間選擇,可用性通常是較好的選擇。


而且,許多現代技術,例如大多數NoSQL數據庫,甚至不支持ACID事務,更不用說2PC。


所以管理數據的一致性需要使用其他的方式。


稍后你將會看到我們使用事件驅動架構中的一種技術叫事件源(event sourcing)來解決分布式事務。



問題3 -查詢


管理數據一致性不是唯一的挑戰。還有一個問題就是查詢問題。


在傳統的單體應用中,我們通常使用join來實現跨表查詢。

比如,我們可以通過下面的sql輕松的查詢出最近客戶所訂的大額訂單:


SELECT *
FROM CUSTOMER c, ORDER o
WHERE
   c.id = o.ID
     AND o.ORDER_TOTAL > 100000
     AND o.STATE = 'SHIPPED'
     AND c.CREATION_DATE > ?


但我們無法在微服務架構中實現這樣的查詢。


就像前面提到的那樣,ORDERS與CUSTOMERS表分屬不同的服務,只能通過服務API來訪問。


而且他們可能使用了不同的數據庫。

而且,即使你使用事件源(Event Sourcing )處理查詢問題可能更麻煩。


稍后,你將會學習到一種解決方案就是通過一種叫CQRS(Command Query Responsibility Segregation)做法來解決分布式查詢問題。


但首先,讓我們看看領域驅動設計(DDD)這個工具,在我們的微服務架構下基于領域模型開發業務邏輯是必要的。


DDD聚合是微服務的構建塊


像你看到的那樣,為了使用微服務架構成功的開發業務應用,我們必須去解決上面所說的那些問題。


這幾個問題的解決辦法你可以去Eric Evans的書Domain-Driven Design中找得到。


這本書,是2003年出版的,主要介紹了設計復雜軟件的一些方法。這些方法對開發微服務也同樣有用。


尤其是領域驅動設計可以讓你創建一個模塊化的領域模型,這個領域模型可以被多個微服務所使用。 



什么是聚合?


在領域驅動設計中,Evans為領域模型定義了幾個構建塊。


許多已經成為日常開發人員語言的一部分,包括entity,就是指一個具有唯一標識的持久化對象。value object,也就是VO,你經常聽說的,是用來存放數據的,可以與數據庫表對應,也可以不對應,有點類似用來傳輸數據的DTO。service,就是指包含業務邏輯的服務。但不應歸類到entity或者value object

repository,表示一堆entity 的集合就是一個repository


構建塊(building block),聚合(aggregate)常常被開發人員忽略,除了那些DDD愛好者,或者叫狂熱分子


然而,聚合(aggregate)被證明是開發微服務的關鍵,非常重要。


一個聚合(aggregate)就是一組domain的集合,可以被當作一個單元來處理。這里說的一個單元就是可以當做原子來處理。


它包含了一個root entity以及可能還有一到多個關聯的entity以及value object


比如,針對一個在線商店的domain model就會有幾個聚合,比如OrderCustomer


Order聚合又由一個root entity Order和一個以上的OrderLineItem value object組成,而且OrderLineItem還有可能關聯有其他vo,比如快遞地址(Address)以及支付賬戶信息PaymentInformation


Customer聚合又由一個root entity Customer和其他的vo比如DeliveryInfo PaymentInformation組成。




使用聚合將領域模型(domain model)分散和參與到每個聚合中,這也使得領域模型更容易理解了。這也同時厘清了操作的scope,比如查詢操作和刪除操作等。


一個聚合通常作為一個整體被從數據庫中load出來。刪除一個聚合,也就是刪除了里邊所有的object


然而,聚合的好處遠遠超出了模塊化一個領域模型。 這是因為聚合必須遵守一定的規則。


聚合之間的引用必須使用主鍵


第一個規則就是聚合通過id(例如主鍵)來引用而不是通過對象引用 


比如,Order通過customerId來引用Customer,而不是引用Customer的對象。

類似的,OrderLineItem通過productId來引用Product



這種做法與傳統的object modeling非常的不同。雖然后者認為通過外鍵引用在領域模型中這樣做看起來怪怪的。


通過使用ID而不是object引用,意味著聚合是松耦合。你可以輕松地把不同的聚合放在不同的service


事實上,一個微服務的業務邏輯是由一個領域模型組成。這個領域模型是幾個聚合的一個組合。比如,OrderService包含了Customer聚合。


一個事務只創建或更新一個聚合


第二個規則就是聚合必須遵循一個事務只能對一個聚合進行創建或更新。


當我第一次看這些規則的時候,當時并沒有什么感覺。因為那時候,我還在開發傳統的單體應用,那種基于RDBMS的應用。所以事務可以更新任何的數據。今天,這些約束依然適用于微服務架構。它確保一個事務只被包含在一個微服務中。此約束還符合大多數NoSQL數據庫的有限事務模型。


當開發一個領域模型,一個很重要的事情就是你必須確定每個聚合得搞多大。


一方面,聚合理想情況下應該是小的。它通過分離關注點來改善模塊化。

這是更有效的,因為聚合通常被全部加載。

此外,由于對每個聚合的更新是順序發生的,因此使用細粒度聚合將增加應用程序可以處理的并發請求數,從而提高可擴展性。

它還將改善用戶體驗,因為它降低了兩個用戶嘗試更新同一聚合的可能性。


另一方面,因為聚合是事務的范圍,您可能需要定義一個較大的聚合,以使特定的更新原子化。

例如,之前我描述了在在線商店領域模型中,OrderCustomer是獨立的聚合。


另一種設計可以是把Orders作為Customer聚合的一部分。

一個較大的Customer聚合的好處就是應用可以強制對于信用額度進行原子驗證。這種方法的缺點是它將訂單和客戶管理功能組合到同一服務中。這也降低了可擴展性,因為更新同一客戶的不同訂單的事務將被順序化。


類似的,兩個用戶去嘗試編輯同一個客戶下的不同訂單有可能會沖突。而且,隨著訂單數量的增加,加載一個Customer聚合的成本也會變得更昂貴。


由于這些問題,盡可能的把聚合細粒度是最好的。

即使一個事務只能創建和更新一個單獨的聚合,微服務應用中也依然必須去管理聚合之間的一致性。

Order服務中必須驗證一個新建的Order聚合將不超過Customer聚合的信用額度。


這里有兩種不同的解決一致性的方法。


一個做法就是在單個事務中欺騙的創建和/或更新多個聚合。這種做法的前提是,所有的聚合都被一個服務所擁有并且這些聚合都被持久保存在同一個RDBMS中才有可能。


另一個做法就是使用最終一致的事件驅動(event-driven)方法來維護聚合之間的一致性。


使用事件驅動來維護數據一致性


在現代應用中,對事務有各種約束,這使得難以在服務之間維持數據一致性。

每個服務都有自己的私有的數據,這時候2PC的方案就變得不可行了。

更重要的是,很多的應用使用的是NoSQL數據庫,這些數據庫根本就不支持本地ACID事務,更不用說分布式事務了。


因此,現代應用程序必須使用事件驅動的,最終一致的事務模型。


什么是事件(Event)?


根據Merriam-Webster(一個單詞網站),事件的意思就是:something that happens:




在本文中,我們將領域事件定義為聚合發生的事件。一個事件(event)通常表示一個狀態的改變。現在還是拿電商系統舉例,一個Order聚合。其狀態更改事件包括訂單已創建(Order Created),訂單已取消(Order Cancelled),訂單已下達(Order Shipped)。事件可以表示違反業務規則的動作,如客戶(Customer)的信用額度。


使用Event-Driven架構


服務們使用事件來管理聚合之間的一致性,像下面這樣的一個場景:一個聚合發布事件,比如,這個聚合的狀態改變或者一次違反業務規則的嘗試等等。

其它聚合訂閱這個事件,然后負責更新他們自己的狀態。


在線商店制創建一個訂單(order)的時候驗證客戶(customer)信用額度使用下面一系列步驟:

1.一個訂單(Order)聚合創建,并且狀態為NEW,發布一個OrderCreated 事件。

2.客戶(Customer)消費這個OrderCreated事件,然后保存為這個訂單保存信用值然后發布一個CreditReserved事件。

3.訂單(Order)聚合消費CreditReserved事件,然后修改自己的狀態為APPROVED

如果信用檢查由于資金不足而失敗,則客戶(Customer)聚合發布CreditLimitExceeded事件。


這個事件不對應于一個狀態的改變,而是表示一次違反業務規則的失敗嘗試。 訂單(Order)聚合消費這個事件后,并將自己的狀態更改為CANCELLED


微服務架構可以比作事件驅動聚合的Web


在這個架構下,每個服務的業務邏輯都是由一個或多個聚合組成。

一個事務只能包含一個服務,并且是更新或創建一個單獨的聚合。也就是聚合內事務。


服務們通過使用事件管理聚合之間的一致性。


微服務業務開發三個難題-拆分、事務、查詢(上)


這種做法一個非常明顯的好處就是一個個聚合變成了松散而解耦的構建塊。

他們可以被作為單體應用來部署或者作為一組服務來部署。

這種情況下,在一個project開始的時候,你可以使用單體架構。

之后,隨著應用的體積和開發團隊的規模的擴大,你就可以很容易的切換到微服務架構上來。



總結


微服務架構從功能上把一整個應用拆分成了一個個服務,每個服務又都對應一個業務能力。當我們開發基于微服務架構的業務應用的時候,一個關鍵的挑戰就是事務、領域模型以及查詢,這三個主要的麻煩都是拆分之后所帶來的問題。你可以通過使用DDD聚合的概念來拆分領域模型。每個服務的業務邏輯是一個領域模型,然后這個領域模型是由一個或多個DDD聚合組成。


在每個服務中,一個事務只能創建或更新一個單獨的聚合。由于2PC對于現代應用來說并不是一個可行的解決方案,所以我們需要使用事件機制來去實現聚合之間的一致性(以及服務之間)。在下一集,我們會描述使用event sourcing來實現一個事件驅動的架構。我們也會向你展示在微服務架構下通過使用CQRS來實現查詢。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

红河县| 阿坝县| 靖江市| 三台县| 嘉义县| 公主岭市| 赤城县| 拉孜县| 田东县| 上林县| 大悟县| 开原市| 威宁| 吉首市| 英超| 三台县| 定襄县| 灵武市| 平潭县| 祁东县| 囊谦县| 嵊州市| 渝中区| 连城县| 三亚市| 咸阳市| 保定市| 行唐县| 阳城县| 晋城| 承德县| 奈曼旗| 西藏| 白河县| 潮安县| 潜山县| 昌黎县| 项城市| 二手房| 祁东县| 玉门市|