微服務應用-基於Spring Cloud和Reactor構建網上商店微服務(上)
前言
和之前的開源社群專案:基於Spring Cloud和Docker構建電影推薦微服務(spring-cloud-microservice-example)一樣,這次翻譯的是基於Spring Cloud和Reactor實現Event Sourcing事件溯源構建網上商店微服務(spring-cloud-event-sourcing-example)開源專案,翻譯的文章是專案作者寫的關於此示例的部落格,因為在看原文時覺得寫的很詳細,所以決定翻譯下,以後好翻看。考慮外網問題,我將原英文文件pdf上傳到資源裡了,如果你對原文感興趣,可以下載看看。
文章篇幅很長,我將全文分為兩部分,上部分重點講解理論知識和專案架構要點,下部分是介紹網上商城的架構選擇和技術細節的程式碼實現,文章按照原文順序翻譯,因自己翻譯水平有限,希望讀者能指出不足以作改正。
使用Spring Cloud和Reactor在微服務中實現Event Sourcing
如果你對雲應用很瞭解,可以直接移步下載執行專案(https://github.com/kbastani/spring-cloud-event-sourcing-example),或跳轉到部署步驟。
English Tutorial provided here:
http://www.kennybastani.com/2016/04/event-sourcing-microservices-spring-cloud.html(原文翻譯如下)
當在微服務架構中構建應用時,狀態管理成為分散式系統的問題,相比於傳統monolithic單體應用,將狀態管理通過事務機制實現,微服務能夠通過一種跨多個不同應用和資料庫的新的分散式事務來管理一致性。
這篇文章中,我們將探索微服務中的資料一致性和高可用性權衡問題。我們將首先看看在處理分散式系統資料一致性背後的一些重要的概念和主題。
介紹
本文以一個線上網上商城網站為案例,使用Spring Boot和Spring Cloud實現,展示如何使用Reactor在微服務中實現Reactive流,從而通過event sourcing事件溯源實現分散式事務,最後,我們會使用Docker 和 Maven構建、執行、協調多容器應用。
最終一致性
當建立微服務時,我們被強迫面對結構狀態的最終一致性問題,這是因為每個微服務都特定暴露自己擁有的資料庫資源,每個資料庫都根據自己型別配置了不同的一致性和高可用性權衡策略。
最終一致性是一種用於描述在分散式系統中資料的操作模型,在分散式系統中狀態是被複制然後跨網路多節點儲存,在關係資料庫叢集中,最終一致性被用來在叢集多個節點之間協調資料複製的寫操作,資料庫叢集中這種寫操作挑戰是:各個節點接受到的寫操作必須嚴格按照複製的次序進行,這個次序是有時間損耗的,從這個角度看,資料庫在叢集節點之間的這種狀態複製還是可以被認為是一種最終一致性,所有節點狀態在未來某個時刻最終匯聚到一個一致性狀態,也就是說,最終達成狀態一致性。
當首次構建微服務時,最終一致性是開發者 DBA和架構師頻繁打交道的問題,當開始在分散式系統中進行狀態處理時,頭疼問題更加嚴重。核心問題是:
如何在保證資料一致性基礎上保證高可用性呢?
要回答這個問題,我們需要了解如何最好地處理在分散式系統中的事務,碰巧大多數分散式資料庫與健康這個問題確定科學的幫助。
事務日誌
現在幾乎所有資料庫都支援高可用性叢集,大多數資料庫對系統一致性模型提供一個易於理解的方式,保證強一致性模型的安全方式是維持資料庫事務操作的有序日誌,理論上理由非常簡單,一個事務日誌是一系列資料更新操作的動作有序記錄集合,當其他節點從主節點獲得這個事務日誌時,能夠按照這種有序動作集合重新播放這些操作,從而更新自己所在節點的資料庫狀態,當這個事務日誌完成後,次節點的狀態最終會和主節點狀態一致。
上面的圖表表示群集中的三個資料庫在使用共享事務日誌複製資料。拉鍊標記的主鍵在這種情況下表示最權威資料庫的當前檢視。拉鍊之間的差異代表每個副本的一致性,當事務被重播,每個副本和主鍵靠攏於一個一致的狀態。這裡的基本思想是用最終一致性,即所有拉鍊最終都將壓縮,和主鍵一致。
資料庫的事務日誌,即預日期計算,在使用歷史上有深厚的根基。管理有序事務日誌的基本方法是威尼斯商人早在15世紀首先使用的,這些威尼斯商人開始使用的方法被稱為複式簿記系統,這是一個簿記系統,要求每個交易需要兩個並排的條目。為了每一筆交易,信用卡和借記卡都指定了從一個帳戶到目的地帳戶。計算一個帳戶的平衡,任何商家都可以簡單地複製所有賬戶的當前狀態,在分類帳重現事件記錄。同樣的記賬概念在今天依舊使用著,並在某種程度上成為現代資料庫系統的事務管理基本概念。
對於聲稱最終一致性的資料庫,它是保證資料庫叢集中的每個節點通過簡單重演導致事務日誌合併寫事務的副本,而收斂到一個全域性一致的狀態。然而不管怎樣,這種說法只是一種保證資料庫的活躍屬性,而忽略對其安全屬性的保障。安全與活躍性之間的區別是,最終一致性,我們只能保證所有更新將觀察到最後,但不保證正確性。
現在大多數可見的內容都試圖讓我們接受微服務的好處,這背後將包含一個非常稀疏的解釋說“微服務使用最終一致性”——有時引用CAP定理來支援任何意義上的存在的困惑。這往往是一個膚淺的解釋,導致問題多於答案。一個最合適解釋微服務的最終一致性問題將是下面的觀點。
Microservice architectures provide no guarantees about the correctness of your data.(微服務架構對於你資料的正確性不提供擔保)
通過道路上存在的巨大炒作去建立微服務,不僅是重要的,它是一個向所有開發人員必須面對的可能性。這是因為當涉及構建軟體時,一個分散式系統是一個分散式系統,一組相連的微服務集合也不例外。好訊息是,有嘗試和真正的設計如何成功構建和維護複雜的分散式系統,這就是本文的其餘部分的主題。
事件溯源
Event sourcing(事件溯源)是借鑑資料庫事務日誌的一種資料持久方式,在ES中,事務單元變得更細粒度,使用一系列有序的事件來代表儲存在資料庫中的領域模型狀態,一旦一個事件被加入事件日誌,它就不能被移走或重新排序,事件被認為是不可變的,事件序列只能被追加方式儲存。
在微服務架構中使用事件溯源處理狀態有很多的好處:
- 聚合可以被認為是產生任何物件的一致性狀態;
- 它提供校訂方法用來進行重播產生物件中狀態變化的歷史;
- 它能使用事件流提供分析資料許多必要輸入;
- 能夠採取補償方式對不一致應用狀態實現事件回滾;
- 它也避免了複雜的微服務之間的同步,為微服務之間的非同步非阻塞操作鋪平了道路。
在本文中,我們將著眼於使用Spring Cloud和Spring Boot實現基於JVM的事件溯源應用。如同大多數的文章,你會發現在這個部落格上,我們將參觀一個現實的示例應用程式,您可以執行和部署它。這一次我已經將一個使用微服務的端到端的原生雲應用例子整合在一起,這個甚至包括了AngularJS的前端。謝謝在Spring Engineering團隊的Dave Syer博士提供的一些非常聰明的基礎工作。
應用參考
如前所述,這個參考應用被設計為一個雲原生應用。雲原生應用和架構的設計和使用一組標準的方法,最大限度地發揮雲平臺的效用。雲原生應用程式使用的東西被稱為十二因素(twelve-factor)應用方法。十二因素論是一套實踐和有益的指導,由Heroku工程師編制,已成為創造適合部署到雲平臺上的應用程式的參考標準。
雲原生應用架構通常會擁抱擴充套件基礎設施原則,如應用程式和資料庫的水平擴充套件。應用程式還注重在彈性和自動癒合,防止停機基礎上構建,通過使用一個平臺,可用性可以自動調整為必要的一組使用政策。同時,對服務的負載均衡轉移到客戶端和應用程式之間處理,擺脫對新的應用程式例項負載均衡器配置的困窘。
網上商店網站
在這個部落格上,你會發現我已經從其他微服務引用應用程式中有了大的飛躍。此應用程式被建立,以展示一個完全形成的微服務架構,實現了一個線上商店的核心功能。
這個線上商店應用程式的使用者將和託管的網上商店網站的前端頁面互動(https://github.com/kbastani/spring-cloud-event-sourcing- example/tree/master/online-store-web)。這是一個Spring Boot應用程式,並在上圖中使用紫色顏色標註,這個應用程式提供了AngularJS應用網站的靜態內容。
在後端的微服務上寫一個前端應用是面臨的主要問題,當使用客戶端JavaScript框架如AngularJS的時候,如何安全地暴露REST API在包裹靜態JS內容的同一主機上。我們需要解決這一挑戰,以防止可能的來自多個領域公開訪問我們後端REST APIS服務導致的安全漏洞。但是如果我們在不同的領域部署這些微服務叢集,我們就需要啟用跨源資源共享(CORS),這將使我們的應用程式的後端容易受到各種形式的攻擊。
為了解決跨源資源共享(CORS)的問題,我們需要有一個優秀的工具套件,而這正是Spring Cloud專案生態系統的一部分。
Spring Cloud支援服務
回顧參考架構的圖例,我們可以看到,Online Store Web微服務可通過HTTP連線的中間層直接到其他四個應用程式,這些服務包括:
- User Service(使用者服務)
- Edge Service(邊緣服務)
- Discovery Service(發現服務)
- Configuration Server(配置管理)
每一個Spring Boot應用程式被認為是為線上商店的Web應用程式提供支援服務。支援服務是一個術語,它是十二因素推廣的方法,提倡的前提是對第三方服務依賴關係應該被視為原生雲應用程式的附加資源(我的理解是降低耦合度)。支援服務的關鍵特徵是,他們提供了類似在其部署環境中繫結到應用程式的雲平臺。
圖中的四個支援服務在部署的目標環境執行時,將被繫結到線上商店Web上。一個雲平臺,比如廣受歡迎的開源PaaS Cloud Foundry,將為應用提供安全證書和URI以注入環境變數形式作為外部配置屬性。
這些支援服務不同於上圖例底層的原因是,這些支援服務必須使用靜態定義的路由位置才可以作為一個環境變數注入到線上商店的Web應用程式容器中。支援服務總是有這個定義的特徵,這種方法被認為是一個為連線到資料庫或服務提供一個安全憑據的生產應用程式的標準做法。這裡的規則是:如果它不能被發現使用發現服務和你部暑應用程式時將依賴一個靜態定義的路由,那麼它就被認為是支援服務。
返回到圖中,底層的服務不需要有任何靜態定義的路由。只要四個支援服務定位到了一個地址,通過支援服務使用Discovery Service(發現服務)和Edge Service(邊緣服務),底層服務都可以發現。
使用者服務
User Service(使用者服務)是在應用程式微服務架構中保護後端資源的身份驗證閘道器,對於暴露給前端應用的資源,它有兩種暴露方式:受保護和不受保護。受保護的資源是一個需要使用者級別的身份驗證。未受保護的資源通常是一個只讀的資源集,這些資源可以由未經身份驗證的使用者檢視,如產品目錄。
使用者服務通常包含一個Spring Cloud OAuth2授權伺服器類似於資源伺服器。正是這項服務,在目標環境中的所有其他應用程式將能夠使用檢索和驗證令牌資訊,驗證的令牌資訊將自動地提供在請求保護資源的請求頭中,並用於對使用者會話進行身份驗證。
如果使用者在訪問受保護的資源時,不提供身份驗證細節的頭請求,他們將被重定向到使用者服務登入頁面,在那裡他們能夠安全地登入和授權,並獲得一個訪問令牌。
邊緣服務
Edge Service(邊緣服務)是一個Spring cloud應用程式,負責從後端微服務中安全暴露HTTP路由。邊緣服務在Spring Cloud微服務架構中是一個非常重要的組成部分,因為它提供了暴露所有來自後端服務API,作為一個統一的REST API,給前端應用使用的一種方式。
利用邊緣服務,一個Spring Boot應用程式將簡單地把它作為一個在目標環境中的支援服務。在這個過程中,邊緣服務將提供安全認證訪問所有REST API所暴露的後端服務。為了能夠做到這一點,邊緣服務匹配一個來自前端應用程式到後端微服務請求路由的URL片段,通過一個反向代理來獲得遠端REST API介面的響應。
最終的結果是,邊緣服務提供了一個無縫的REST API,將適合嵌入任何Spring Boot應用,將它作為一個使用Spring Cloud Netflix Zuul啟動專案的支援服務。
發現服務
Discovery Service(發現服務)是一個Spring Cloud應用程式,該應用程式負責維護目標環境中服務資訊的登錄檔。每個服務應用程式在目標環境啟動的時候都會去訂閱服務發現應用程式,訂閱應用程式將提供其當地的網路資訊,包括網路地址。通過這樣做,在環境中的所有其他應用程式通過下載一個服務登錄檔並快取它在本地,將能夠找到其他使用者。本地服務登錄檔將被用於作為一個應用程式依賴於目標環境中的其他服務的網路地址的所需的基礎上。
配置管理
Configuration Server(配置管理)是一個集中外部配置使用各種方法建築十二要素應用的Spring Cloud應用。十二因素的應用程式將配置檔案儲存在環境中,而不是在專案的原始碼裡,此服務將允許其他應用程式檢索其針對目標環境的定製配置。
後端微服務
雖然在中間層的支援服務仍然被認為是微服務,他們解決了一系列對純粹操作和安全相關的關注,而這個應用程式的業務邏輯幾乎完全位於我們的底層,它將圍繞在虛構的線上商店的業務能力上做設計。(我現在已經提前貼上原生雲,一個假設的矽谷創業公司要銷售四件真正聰明的t恤和連帽衫)
作為一個線上商店的業務能力的一部分,我們有以下5個微服務,將作為我們後端的REST API。這些api的主要消費者是Online Store Web,以及其他計劃面向客戶的應用程式,可能無法看到的情況下,原生雲公司是無法等到在沙丘路光明的一天,即從一個頂級的風投公司獲得種子輪投資。
這些微服務通過在中間層的邊緣服務應用程式,公開為一個無縫的REST API。邊緣服務使用Spring Netflix的Zuul代理將請求對映路由從線上商店的Web應用程式到適當的後端微服務的REST API。
這些應用程式可以發現:
- Catalog Service(目錄服務)
- Account Service(帳戶服務)
- Inventory Service(庫存服務)
- Cart Service(購物車服務)
- Order Service(訂單服務)
在此示例專案的GitHub庫上,有對這些微服務作用的描述。我將定期貢獻出應用在這個專案庫中的有預見的文章,文章將專注於更多的模式和最佳實踐的微服務架構。
在這篇文章的下一部分將集中在微服務中使用Spring Boot、Spring Cloud和Project Reactor實現事件溯源的原始主題。