“微服務(wù)架構(gòu)”是現(xiàn)在編程中很流行的概念,未來能和最新趨勢保持同步,我也一直在學(xué)習(xí)了解這個(gè)架構(gòu),如果具體點(diǎn)說,我一直在尋找一種使用Spring在Java中實(shí)現(xiàn)微服務(wù)架構(gòu)的方法。
為什么我會(huì)有這個(gè)想法,這是有一定的背景的:我們公司很好但是卻有一個(gè)過時(shí)的技術(shù)堆棧,基本上沒有使用Java 8或者微服務(wù)器。所以我想要了解關(guān)于微服務(wù)器的事情,必須自己去收集學(xué)習(xí),為此我創(chuàng)建了一個(gè)待辦事項(xiàng)系統(tǒng),記錄我的學(xué)習(xí)經(jīng)歷以供將來參考!
概述
本文的目的是為不同微服務(wù)提供源代碼演練,不會(huì)深入解讀概念和工具,主要是介紹一個(gè)包含用于開發(fā)微服務(wù)的模式、工具和技術(shù)的應(yīng)用示例。
既然是一個(gè)參考應(yīng)用程序,我會(huì)使它盡量簡單,源碼易于理解!本文中,這個(gè)待辦事項(xiàng)系統(tǒng)應(yīng)用程序由8個(gè)部分組成:
Reminder
User
Service discovery server
Mailer
OAuth Server
System integration test
API Gateway
Web application client
系統(tǒng)如何與Microservices交互
上圖中顯示了系統(tǒng)與所有微服務(wù)器的交互,用戶訪問使用Angular 2編寫的Web應(yīng)用程序。然后連接到OAuth授權(quán)服務(wù)器,OAuth授權(quán)服務(wù)器將是可以分配用戶和權(quán)限的中心點(diǎn)。此服務(wù)器將返回一個(gè)JSON Web令牌,其中包含客戶端及其權(quán)限的信息以及格式范圍。在用戶認(rèn)證并具有令牌之后,Web應(yīng)用程序與API網(wǎng)關(guān)通信。通過JWT來驗(yàn)證它是否來自授權(quán)服務(wù)器,然后調(diào)用微服務(wù)器并構(gòu)建響應(yīng)。
OAuth服務(wù)器使用用戶服務(wù)來獲取用戶的身份驗(yàn)證詳細(xì)信息。此外,API網(wǎng)關(guān)使用OAuth服務(wù)器來獲取用戶的信息。
Remainder Service由ToDo功能來提供,,ToDo服務(wù)有一個(gè)計(jì)劃工作來檢查并通過電子郵件通知用戶,電子郵件由郵件服務(wù)發(fā)送,該事件使用Kafka的事件提醒服務(wù)觸發(fā)。
系統(tǒng)集成測試是一個(gè)Java應(yīng)用程序,負(fù)責(zé)到達(dá)提醒服務(wù)的端點(diǎn)。
連接微服務(wù)
在微服務(wù)體系結(jié)構(gòu)中,我們必須處理許多在不同IP和端口上運(yùn)行的微服務(wù)器。因此,我們需要找到一種無需硬編碼來管理每個(gè)地址的方式。
這就需要用到Netflix Eureka,它是客戶端服務(wù)發(fā)現(xiàn),允許服務(wù)自動(dòng)查找和相互通信。我們?cè)谙到y(tǒng)中使用了Spring Cloud Eureka,如果Eureka查找到服務(wù)運(yùn)行的位置,我們就可以添加實(shí)例并應(yīng)用負(fù)載平衡來在微服務(wù)器之間分配傳入的應(yīng)用流量。
在系統(tǒng)中,我們使用Netflix Ribbon作為客戶端負(fù)載均衡器,實(shí)現(xiàn)容錯(cuò),并通過冗余增加可靠性和可用性。我們使用Netflix Foreign編寫聲明性REST客戶端,并集成Ribbon和Eureka來提供負(fù)載平衡HTTP客戶端。
我們的系統(tǒng)中存在一些依賴。我們正在使用Netflix Hystrix斷路器將應(yīng)用程序與依賴性故障隔離開來。它有助于阻止級(jí)聯(lián)故障,并允許快速恢復(fù)或添加后備。Hystrix為每個(gè)依賴關(guān)系維護(hù)一個(gè)線程池,如果線程池耗盡,它會(huì)拒絕請(qǐng)求。它還提供斷路器功能,可以停止對(duì)依賴關(guān)系的所有請(qǐng)求。當(dāng)請(qǐng)求失敗,拒絕或超時(shí)時(shí),還可以實(shí)現(xiàn)備用邏輯。
認(rèn)證
開發(fā)任何類型的系統(tǒng)時(shí),安全性都是非常重要的,微服務(wù)架構(gòu)也沒什么不同。當(dāng)“如何保持微服務(wù)的安全性?”這個(gè)問題出現(xiàn)時(shí),我的第一個(gè)答案是OAuth2。OAuth2絕對(duì)是一個(gè)很好的解決方案:它是一種眾所周知的授權(quán)技術(shù),廣泛應(yīng)用于Google,F(xiàn)acebook和Github。
當(dāng)然沒有Spring Security的情況下,是不可能談?wù)摪踩?。。在討論分布式系統(tǒng)的安全性時(shí),Spring Security和OAuth2是顯而易見的選擇。
不過,我們?cè)诎踩珕栴}上還增加了一個(gè)元素:JSON Web Token(JWT)。如果僅使用OAuth,我們需要一個(gè)OAuth授權(quán)服務(wù)器來驗(yàn)證用戶,生成令牌,并充當(dāng)資源服務(wù)器的端點(diǎn),詢問該令牌是否有效以及授權(quán)的權(quán)限。與授權(quán)服務(wù)器相比,這需要兩倍的請(qǐng)求。而JWT提供了一種在訪問令牌中傳輸權(quán)限和用戶數(shù)據(jù)的簡單方法,一旦所有數(shù)據(jù)都已經(jīng)在令牌字符串中,資源服務(wù)器就不需要請(qǐng)求令牌檢查。所有信息都被序列化為JSON,用base64編碼,最后用私有RSA密鑰簽名。
您可以查看OAuth2授權(quán)服務(wù)器(OAuth-server)和資源服務(wù)器(API Gateway)的代碼實(shí)現(xiàn)。
REST
在系統(tǒng)中,我們有兩種交互方式:同步和異步。異步,我們使用了分布式事件與Kafka,遵循發(fā)布/訂閱模型。同步,我們支持了JSON和XML的REST風(fēng)格。
Martin Fowler認(rèn)為RESTful可以分為四個(gè)級(jí)別,level 0-level 3。我們的微服務(wù)處于level 2,為了簡單起見,這里不使用HATEOAS設(shè)計(jì)模式實(shí)現(xiàn)超媒體控件。
因?yàn)槲覀兪褂昧薙pring Cloud,所以必須實(shí)現(xiàn)開箱即用的可擴(kuò)展性模式,將其放在HTTP連接中,例如:斷路器,負(fù)載平衡,連接池,超時(shí)和重試等。
分布式事件
如上所述,我們通過使用Kafka 進(jìn)行提醒服務(wù)和 Mailer服務(wù)之間的通信,并異步地與其他Microservices進(jìn)行通信。在提醒服務(wù)中,我們有一個(gè)計(jì)劃任務(wù)來檢查提醒時(shí)間,并發(fā)布RemainderFound事件。Mailer服務(wù)中將會(huì)有一個(gè)訂閱的事件,向用戶發(fā)送電子郵件。
Event sourcing和 CQRS
單片應(yīng)用通常具有單個(gè)關(guān)系數(shù)據(jù)庫。我們可以使用ACID交易。因此,如果出現(xiàn)問題,我們的應(yīng)用程序可以簡單地開始一個(gè)事務(wù),更改多個(gè)行,并提交事務(wù),如果錯(cuò)誤的話,還可以恢復(fù)到之前。不幸的是,處理微服務(wù)架構(gòu)中的數(shù)據(jù)訪問要復(fù)雜得多。這些數(shù)據(jù)分布在不同的數(shù)據(jù)庫中,跨多個(gè)服務(wù)實(shí)施業(yè)務(wù)交易是一個(gè)很大的挑戰(zhàn)。
在“ToDo”項(xiàng)目中,我們使用事件來處理跨多個(gè)服務(wù)的業(yè)務(wù)事務(wù)。 您可以查看在Mailer服務(wù)中應(yīng)用的CQRS實(shí)施事件。 可以看到如何分離讀和寫,輕松地縮放每個(gè)部分。 我們使用關(guān)系數(shù)據(jù)庫作為事件存儲(chǔ),然后使用Kafka分發(fā)事件。 當(dāng)然我們需要將這兩個(gè)動(dòng)作定義為原子操作并避免存儲(chǔ)事件,這樣就不會(huì)導(dǎo)致JVM崩潰。 不使用Kafka作為事件存儲(chǔ),是因?yàn)閺年P(guān)系數(shù)據(jù)庫構(gòu)建聚合更簡單。
未來的計(jì)劃
您可能也注意到這個(gè)項(xiàng)目中尚且還有很多事情尚未解決,這是一個(gè)開發(fā)中的項(xiàng)目,未來我們會(huì)添加更多的東西,例如Spring云配置,Docker容器,與Jenkins的持續(xù)集成,Spring Sleuth的分布式跟蹤,ELK的日志管理等。