使用Spring Cloud和Docker的微服務(wù)架構(gòu)

本文通過使用Spring Boot,Spring Cloud和Docker構(gòu)建的概念驗(yàn)證應(yīng)用程序的示例,為了解常見的微服務(wù)架構(gòu)模式提供了一個(gè)起點(diǎn)。另外小編從事在線教育多年,將自己的資料整合建了一個(gè)QQ群,對(duì)于有興趣一起交流學(xué)習(xí)java的可以加群:732976516,里面有大神會(huì)給予解答,也會(huì)有許多的資源可以供大家學(xué)習(xí)分享,歡迎大家前來一起學(xué)習(xí)進(jìn)步!

該代碼可在Github上獲得,圖像可在Docker Hub上獲得。只需一個(gè)命令即可啟動(dòng)整個(gè)系統(tǒng)。

作為這個(gè)系統(tǒng)的基礎(chǔ),我選擇了一個(gè)舊項(xiàng)目,其后端曾經(jīng)是一個(gè)整體。該應(yīng)用程序提供了一種處理個(gè)人財(cái)務(wù),組織收入和支出,管理儲(chǔ)蓄,分析統(tǒng)計(jì)數(shù)據(jù)和創(chuàng)建簡(jiǎn)單預(yù)測(cè)的方法。

功能服務(wù)

整體應(yīng)用程序被分解為三個(gè)核心微服務(wù)。所有這些都是可獨(dú)立部署的應(yīng)用程序,圍繞某些業(yè)務(wù)功能組織。

帳戶服務(wù)

包含一般用戶輸入邏輯和驗(yàn)證:收入/費(fèi)用項(xiàng)目,節(jié)省和帳戶設(shè)置。

方法路徑描述用戶通過身份驗(yàn)證可從UI獲得得到/賬戶/ {帳戶}獲取指定的帳戶數(shù)據(jù)

得到/帳號(hào)/電流獲取當(dāng)前帳戶數(shù)據(jù)××得到/帳號(hào)/演示獲取模擬賬戶數(shù)據(jù)(預(yù)先填寫的收入/費(fèi)用項(xiàng)目等)

×放/帳號(hào)/電流保存當(dāng)前帳戶數(shù)據(jù)××POST/帳號(hào)/注冊(cè)新帳戶

×

統(tǒng)計(jì)服務(wù)

對(duì)主要統(tǒng)計(jì)參數(shù)執(zhí)行計(jì)算并捕獲每個(gè)帳戶的時(shí)間序列。數(shù)據(jù)點(diǎn)包含標(biāo)準(zhǔn)化為基本貨幣和時(shí)間段的值。此數(shù)據(jù)可用于跟蹤帳戶生命周期中的現(xiàn)金流動(dòng)態(tài)。

方法路徑描述用戶通過身份驗(yàn)證可從UI獲得得到/統(tǒng)計(jì)/ {}帳戶獲取指定的帳戶統(tǒng)計(jì)信

得到/統(tǒng)計(jì)/電流獲取當(dāng)前帳戶統(tǒng)計(jì)信息××得到/統(tǒng)計(jì)/演示獲取模擬賬戶統(tǒng)計(jì)信息

×放/統(tǒng)計(jì)/ {}帳戶為指定的帳戶創(chuàng)建或更新時(shí)間序列數(shù)據(jù)點(diǎn)

通知服務(wù)

存儲(chǔ)用戶的聯(lián)系信息和通知設(shè)置(如提醒和備份頻率)。計(jì)劃工作人員從其他服務(wù)收集所需信息,并向訂閱客戶發(fā)送電子郵件。

方法路徑描述用戶通過身份驗(yàn)證可從UI獲得得到/通知/設(shè)置/電流獲取當(dāng)前帳戶通知設(shè)置××放/通知/設(shè)置/電流保存當(dāng)前帳戶通知設(shè)置××

筆記

每個(gè)微服務(wù)都有自己的數(shù)據(jù)庫(kù),因此無法繞過API并直接訪問持久性數(shù)據(jù)。

對(duì)于這個(gè)項(xiàng)目,我使用MongoDB作為每個(gè)服務(wù)的主數(shù)據(jù)庫(kù)。擁有多語言持久性體系結(jié)構(gòu)(以便選擇最適合服務(wù)要求的數(shù)據(jù)庫(kù)類型)也是有意義的。

服務(wù)到服務(wù)通信非常簡(jiǎn)單:微服務(wù)僅使用同步REST API進(jìn)行通信。現(xiàn)實(shí)世界系統(tǒng)中的常見做法是使用交互方式的組合。例如,執(zhí)行同步GET請(qǐng)求以檢索數(shù)據(jù)并通過Message代理使用異步方法進(jìn)行創(chuàng)建/更新操作,以便解耦服務(wù)和緩沖消息。然而,這給我們帶來了? 最終的一致性? 世界。

基建服務(wù)

分布式系統(tǒng)中有許多常見模式,可以幫助我們使所描述的核心服務(wù)工作。 Spring云? 提供了強(qiáng)大的工具,可以增強(qiáng)Spring Boot應(yīng)用程序的行為以實(shí)現(xiàn)這些模式。我會(huì)簡(jiǎn)要介紹一下。

配置服務(wù)

Spring Cloud Config? 是分布式系統(tǒng)的水平可擴(kuò)展集中配置服務(wù)。它使用可插入的存儲(chǔ)庫(kù)層,目前支持本地存儲(chǔ),Git和Subversion。

在這個(gè)項(xiàng)目中,我使用? native profile,它只是從本地類路徑加載配置文件。您可以shared在Config服務(wù)資源中查看? 目錄? ?,F(xiàn)在,當(dāng)Notification-service請(qǐng)求它的配置時(shí),使用shared/notification-service.yml 和? 配置服務(wù)響應(yīng)? shared/application.yml (在所有客戶端應(yīng)用程序之間共享)。

客戶端使用

只需構(gòu)建具有spring-cloud-starter-config 依賴關(guān)系的Spring Boot應(yīng)用程序? ,自動(dòng)配置將完成剩下的工作。

現(xiàn)在,您的應(yīng)用程序中不需要任何嵌入屬性。只需提供? bootstrap.yml 應(yīng)用程序名稱和配置服務(wù)URL:

spring:

? application:

? ? name: notification-service

? cloud:

? ? config:

? ? ? uri: http://config:8888

? ? ? fail-fast: true

使用Spring Cloud Config,您可以動(dòng)態(tài)更改應(yīng)用程序配置

例如,? EmailService bean? 使用注釋? @RefreshScope。這意味著您可以更改電子郵件文本和主題行,而無需重建和重新啟動(dòng)Notification Service應(yīng)用程序。

首先,在Config服務(wù)器中更改所需的屬性。然后,對(duì)Notification服務(wù)執(zhí)行刷新請(qǐng)求: curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh

您還可以使用? webhooks自動(dòng)執(zhí)行此過程

筆記

但動(dòng)態(tài)刷新有一些限制。 @RefreshScope 不適用于? @Configuration 類,不能影響? @Scheduled 方法。

fail-fast property表示如果Spring Boot應(yīng)用程序無法連接到Config Service,則會(huì)立即失敗啟動(dòng)。當(dāng)你一起啟動(dòng)所有應(yīng)用程序時(shí),這非常有用? 。

下面有重要的安全說明。

驗(yàn)證服務(wù)

授權(quán)職責(zé)被完全提取到單獨(dú)的服務(wù)器,該服務(wù)器 為后端資源服務(wù)授予? OAuth2令牌。Auth Server用于用戶授權(quán)以及周邊內(nèi)部的安全機(jī)器到機(jī)器通信。

在這個(gè)項(xiàng)目中,我使用? Password credentials 授權(quán)類型進(jìn)行用戶授權(quán)(因?yàn)樗鼉H由本機(jī)應(yīng)用程序UI使用),并? Client Credentials 用作微服務(wù)授權(quán)的授權(quán)類型。

Spring Cloud Security提供方便的注釋和自動(dòng)配置,使服務(wù)器和客戶端都能輕松實(shí)現(xiàn)。您可以在文檔中了解有關(guān)它的更多信息,? 并檢查Auth Server代碼中的配置詳細(xì)信息? 。

從客戶端來看,一切都與傳統(tǒng)的基于會(huì)話的授權(quán)完全相同。您可以Principal 從請(qǐng)求中檢索? 對(duì)象,使用基于表達(dá)式的訪問控制和@PreAuthorize 注釋檢查用戶角色和其他內(nèi)容? 。

PiggyMetrics中的每個(gè)客戶端(帳戶服務(wù),統(tǒng)計(jì)服務(wù),通知服務(wù)和瀏覽器)都有一個(gè)范圍:? server用于后端服務(wù),以及? ui - 用于瀏覽器。因此,我們還可以保護(hù)控制器免受外部訪問,例如:

@PreAuthorize("#oauth2.hasScope('server')")

@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)

public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {

? ? return statisticsService.findByAccountName(name);

}

API網(wǎng)關(guān)

如您所見,有三種核心服務(wù),它們向客戶端公開外部API。在現(xiàn)實(shí)世界的系統(tǒng)中,這個(gè)數(shù)字可以非??焖俚卦鲩L(zhǎng)以及整個(gè)系統(tǒng)的復(fù)雜性。實(shí)際上,渲染一個(gè)復(fù)雜的網(wǎng)頁可能涉及數(shù)百種服務(wù)。

理論上,客戶端可以直接向每個(gè)微服務(wù)發(fā)出請(qǐng)求。但顯然這個(gè)選項(xiàng)存在挑戰(zhàn)和局限,例如必須知道所有端點(diǎn)地址,分別對(duì)每個(gè)信息的和平執(zhí)行http請(qǐng)求,在客戶端合并結(jié)果。另一個(gè)問題是非網(wǎng)絡(luò)友好協(xié)議,可能會(huì)在后端使用。

通常,更好的方法是使用API??網(wǎng)關(guān)。它是系統(tǒng)的單一入口點(diǎn),用于通過將請(qǐng)求路由到適當(dāng)?shù)暮蠖朔?wù)或通過調(diào)用多個(gè)后端服務(wù)并聚合結(jié)果來處理請(qǐng)求? 。此外,它還可用于身份驗(yàn)證,洞察,壓力和金絲雀測(cè)試,服務(wù)遷移,靜態(tài)響應(yīng)處理,主動(dòng)流量管理。

Netflix開源了? 這樣的優(yōu)質(zhì)服務(wù),現(xiàn)在使用Spring Cloud,我們可以通過一個(gè)@EnableZuulProxy注釋啟用它? 。在這個(gè)項(xiàng)目中,我使用Zuul存儲(chǔ)靜態(tài)內(nèi)容(UI應(yīng)用程序)并將請(qǐng)求路由到適當(dāng)?shù)奈⒎?wù)。以下是Notification服務(wù)的簡(jiǎn)單基于前綴的路由配置:

zuul:

? routes:

? ? notification-service:

? ? ? ? path: /notifications/**

? ? ? ? serviceId: notification-service

? ? ? ? stripPrefix: false

這意味著所有以請(qǐng)求開頭的請(qǐng)求? /notifications 都將路由到Notification服務(wù)。您可以看到,沒有硬編碼的地址。Zuul使用? 服務(wù)發(fā)現(xiàn)? 機(jī)制來定位Notification服務(wù)實(shí)例以及? Circuit Breaker和Load Balancer,如下所述。

服務(wù)發(fā)現(xiàn)

另一種眾所周知的架構(gòu)模式是服務(wù)發(fā)現(xiàn)。它允許自動(dòng)檢測(cè)服務(wù)實(shí)例的網(wǎng)絡(luò)位置,這些服務(wù)實(shí)例可能由于自動(dòng)擴(kuò)展,故障和升級(jí)而動(dòng)態(tài)分配地址。

服務(wù)發(fā)現(xiàn)的關(guān)鍵部分是注冊(cè)表。我在這個(gè)項(xiàng)目中使用了Netflix Eureka。當(dāng)客戶端負(fù)責(zé)確定可用服務(wù)實(shí)例的位置(使用注冊(cè)服務(wù)器)并在它們之間加載平衡請(qǐng)求時(shí),Eureka是客戶端發(fā)現(xiàn)模式的一個(gè)很好的例子。

使用Spring Boot,您可以輕松地使用spring-cloud-starter-eureka-server 依賴項(xiàng),? @EnableEurekaServer 注釋和簡(jiǎn)單配置屬性構(gòu)建Eureka Registry? 。

通過@EnableDiscoveryClient 注釋和? bootstrap.yml 應(yīng)用程序名稱啟用客戶端支持? :

spring:

? application:

? ? name: notification-service

現(xiàn)在,在應(yīng)用程序啟動(dòng)時(shí),它將向Eureka Server注冊(cè)并提供元數(shù)據(jù),例如主機(jī)和端口,運(yùn)行狀況指示器URL,主頁等.Eureka從屬于服務(wù)的每個(gè)實(shí)例接收心跳消息。如果心跳故障超過可配置的時(shí)間表,則實(shí)例將從注冊(cè)表中刪除。

此外,Eureka提供了一個(gè)簡(jiǎn)單的界面,您可以在其中跟蹤正在運(yùn)行的服務(wù)和可用實(shí)例的數(shù)量: http://localhost:8761

負(fù)載均衡器,斷路器和Http客戶端

Netflix OSS提供了另一套很棒的工具。

Ribbon是一個(gè)客戶端負(fù)載均衡器,可以讓您對(duì)HTTP和TCP客戶端的行為進(jìn)行大量控制。與傳統(tǒng)的負(fù)載均衡器相比,每次線上調(diào)用都不需要額外的跳 - 您可以直接聯(lián)系所需的服務(wù)。

開箱即用,它本身與Spring Cloud和Service Discovery集成。 Eureka Client? 提供可用服務(wù)器的動(dòng)態(tài)列表,因此Ribbon可以在它們之間取得平衡。

豪豬

Hystrix是Circuit Breaker模式的實(shí)現(xiàn)? ,它可以控制通過網(wǎng)絡(luò)訪問的依賴關(guān)系的延遲和故障。主要思想是在具有大量微服務(wù)的分布式環(huán)境中停止級(jí)聯(lián)故障。這有助于快速失敗并盡快恢復(fù) - 自我修復(fù)的容錯(cuò)系統(tǒng)的重要方面。

除了斷路器控制之外,您還可以使用Hystrix添加一個(gè)回退方法,以便在主命令失敗時(shí)獲取默認(rèn)值。

此外,Hystrix會(huì)為每個(gè)命令生成執(zhí)行結(jié)果和延遲的指標(biāo),我們可以使用它來? 監(jiān)控系統(tǒng)行為。

假裝

Feign是一個(gè)聲明式HTTP客戶端,可與Ribbon和Hystrix無縫集成。實(shí)際上,通過一個(gè)? spring-cloud-starter-feign 依賴關(guān)系和? @EnableFeignClients 注釋,您可以擁有一整套負(fù)載均衡器,斷路器和HTTP客戶端,并具有合理的即用型默認(rèn)配置。

以下是帳戶服務(wù)的示例:

@FeignClient(name = "statistics-service")

public interface StatisticsServiceClient {

? ? @RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)

? ? void updateStatistics(@PathVariable("accountName") String accountName, Account account);

}

你需要的一切只是一個(gè)界面

您可以@RequestMapping 在Spring MVC控制器和Feign方法之間共享

以上示例指定了所需的服務(wù)ID -? statistics-service感謝Eureka的自動(dòng)發(fā)現(xiàn)(但顯然您可以訪問具有特定URL的任何資源)

監(jiān)控儀表板

在此項(xiàng)目配置中,每個(gè)帶有Hystrix的微服務(wù)都會(huì)通過Spring Cloud Bus(使用AMQP代理)將指標(biāo)推送到Turbine。Monitoring項(xiàng)目只是一個(gè)帶有Turbine? 和? Hystrix Dashboard的小型Spring啟動(dòng)應(yīng)用程序? 。

讓我們看看我們?cè)谪?fù)載下的系統(tǒng)行為:帳戶服務(wù)調(diào)用統(tǒng)計(jì)服務(wù),它響應(yīng)模擬延遲變化。響應(yīng)超時(shí)閾值設(shè)置為1秒。

0 ms delay500 ms delay800 ms delay1100 ms delay表現(xiàn)良好的系統(tǒng)。吞吐量約為22個(gè)請(qǐng)求/秒。統(tǒng)計(jì)服務(wù)中的活動(dòng)線程數(shù)量很少。中位服務(wù)時(shí)間約為50毫秒。

活動(dòng)線程數(shù)正在增長(zhǎng)。我們可以看到紫色線程池拒絕的數(shù)量,因此大約有30-40%的錯(cuò)誤,但電路仍然關(guān)閉。

半開狀態(tài):失敗命令的比例超過50%,斷路器啟動(dòng)。睡眠窗口的時(shí)間量后,下一個(gè)請(qǐng)求通過。

100%的請(qǐng)求失敗。電路現(xiàn)在永久開放。睡眠時(shí)間后重試不會(huì)再次關(guān)閉電路,因?yàn)閱蝹€(gè)請(qǐng)求太慢。

日志分析

在嘗試識(shí)別分布式環(huán)境中的問題時(shí),集中日志記錄非常有用。Elasticsearch,Logstash和Kibana堆棧使您可以輕松搜索和分析日志,利用率和網(wǎng)絡(luò)活動(dòng)數(shù)據(jù)。我的其他項(xiàng)目中描述隨時(shí)可用的Docker配置? 。

安全

高級(jí)安全配置超出了此概念驗(yàn)證項(xiàng)目的范圍。要更真實(shí)地模擬真實(shí)系統(tǒng),請(qǐng)考慮使用https和JCE密鑰庫(kù)來加密微服務(wù)密碼和配置服務(wù)器屬性內(nèi)容( 有關(guān)詳細(xì)信息,請(qǐng)參閱? 文檔)。

基建自動(dòng)化

與部署整體應(yīng)用程序相比,部署微服務(wù)具有相互依賴性,這是一個(gè)復(fù)雜得多的過程。擁有完全自動(dòng)化的基礎(chǔ)架構(gòu)非常重要。我們可以通過持續(xù)交付方法獲得以下好處:

隨時(shí)發(fā)布軟件的能力。

任何構(gòu)建都可能最終成為一個(gè)版本。

構(gòu)建工件一次,根據(jù)需要進(jìn)行部署。

這是一個(gè)簡(jiǎn)單的Continuous Delivery工作流程,在此項(xiàng)目中實(shí)施:

在此? 配置中,Travis CI為每個(gè)成功的Git推送構(gòu)建標(biāo)記圖像。因此latest ,Docker Hub上的每個(gè)微服務(wù)始終都有一個(gè)? 映像? ,舊映像使用Git commit hash進(jìn)行標(biāo)記。如果需要,可以輕松部署其中任何一個(gè)并快速回滾。

如何運(yùn)行所有的東西?

這真的很容易,我建議你試試。請(qǐng)記住,您將啟動(dòng)8個(gè)Spring Boot應(yīng)用程序,4個(gè)MongoDB實(shí)例和RabbitMq。確保您4 Gb 的計(jì)算機(jī)上有? 可用的RAM。您始終可以通過網(wǎng)關(guān),注冊(cè)表,配置,身份驗(yàn)證服務(wù)和帳戶服務(wù)運(yùn)行重要服務(wù)。

在你開始之前

安裝Docker和Docker Compose。

出口環(huán)境變量:? CONFIG_SERVICE_PASSWORD,? NOTIFICATION_SERVICE_PASSWORD,? STATISTICS_SERVICE_PASSWORD,? ACCOUNT_SERVICE_PASSWORD, MONGODB_PASSWORD

生產(chǎn)模式

在此模式下,所有最新圖像都將從Docker Hub中提取。只需復(fù)制? docker-compose.yml 并點(diǎn)擊即可? docker-compose up -d。

發(fā)展模式

如果您想自己構(gòu)建映像(例如,代碼中有一些更改),則必須使用Maven克隆所有存儲(chǔ)庫(kù)并構(gòu)建工件。然后,跑 docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml 繼承? docker-compose.yml 了在本地構(gòu)建映像的額外可能性,并公開所有容器端口以便于開發(fā)。

重要的終點(diǎn)

localhost:80 - 網(wǎng)關(guān)

localhost:8761 - Eureka Dashboard

localhost:9000 - Hystrix儀表板

localhost:8989 - 渦輪流(Hystrix儀表板的來源)

localhost:15672 - RabbitMq管理

筆記

所有Spring Boot應(yīng)用程序都需要運(yùn)行? Config Server? 才能啟動(dòng)。但是我們可以同時(shí)啟動(dòng)所有容器,因?yàn)? fail-fast Spring Boot屬性和? restart: always docker-compose選項(xiàng)。這意味著所有相關(guān)容器都將嘗試重新啟動(dòng),直到Config Server啟動(dòng)并運(yùn)行。

此外,Service Discovery機(jī)制在所有應(yīng)用程序啟動(dòng)后需要一些時(shí)間。在實(shí)例,Eureka服務(wù)器和客戶端在其本地緩存中都具有相同的元數(shù)據(jù)之前,客戶端無法發(fā)現(xiàn)任何服務(wù),因此可能需要3次聽覺。默認(rèn)聽覺時(shí)間為30秒。

另外本人從事在線教育多年,將自己的資料整合建了一個(gè)公眾號(hào),對(duì)于有興趣一起交流學(xué)習(xí)java的初學(xué)者可以搜索:程序員文明,里面有大神會(huì)給予解答,也會(huì)有許多的資源可以供大家學(xué)習(xí)分享,歡迎大家前來一起學(xué)習(xí)進(jìn)步!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容