基于Spring Boot、Spring Cloud、Docker的微服務系統(tǒng)架構實踐

這個項目的名字叫:Piggy Metrics,一個供個人處理財務的解決方案。

簡介
這是一款概念性的應用程序,基于Spring Boot,Spring Cloud和Docker 簡單演示了微服務的架構模式,順便說一句,它還有一個非常漂亮整潔的用戶界面.

功能服務

PiggyMetrics被分解為三個核心微服務。這些服務都是圍繞某些業(yè)務能力組織的可獨立部署的應用程序。


這里寫圖片描述

賬戶服務
包含一般用戶輸入邏輯和驗證:收入/費用項目,儲蓄和帳戶設置。

Method Path Description User authenticated Available from UI
GET /accounts/{account} 獲取指定的帳戶數(shù)據(jù)
GET /accounts/current 獲取當前帳戶數(shù)據(jù) × ×
GET /accounts/demo 獲取模擬賬戶數(shù)據(jù)(預填收入/費用項目等) ×
PUT /accounts/current 保存當前帳戶數(shù)據(jù) × ×
POST /accounts/ 注冊新帳號 ×

統(tǒng)計服務
對主要統(tǒng)計參數(shù)執(zhí)行計算,并為每個帳戶的時間序列。數(shù)據(jù)點包含基準貨幣和時間段的值。此數(shù)據(jù)用于跟蹤帳戶生命周期中的現(xiàn)金流動動態(tài)(尚未在UI中實現(xiàn)的花式圖表)。

Method Path Description User authenticated Available from UI
GET /statistics/{account} 獲取指定的帳戶統(tǒng)計信息
GET /statistics/current 獲取當前帳戶統(tǒng)計信息 × ×
GET /statistics/demo 獲取模擬帳戶統(tǒng)計信息 ×
PUT /statistics/{account} 創(chuàng)建或更新指定帳戶的時間序列數(shù)據(jù)點

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

Method Path Description User authenticated Available from UI
GET /notifications/settings/current 獲取當前的帳戶通知設置 × ×
PUT /notifications/settings/current 保存當前帳戶通知設置 × ×

****小結:**

  • 每個微服務都有自己的數(shù)據(jù)庫,因此沒有辦法繞過API和直接訪問數(shù)據(jù)庫。
  • 在這個項目中,使用MongoDB作為每個服務的主數(shù)據(jù)庫。它是支持多種編程語言持久性架構(包括最適合服務需求的數(shù)據(jù)庫類型)。
  • Service-to-service的通信是相當簡單的:各個微服務之間的通信只使用同步的REST API。在現(xiàn)實世界中通常的做法是使用交互風格的組合。例如,執(zhí)行同步GET請求以檢索數(shù)據(jù),并通過消息代理使用異步方法進行創(chuàng)建/更新操作,以便分離服務和緩沖消息,這為我們帶來了一致性。

基礎服務設施

在分布式系統(tǒng)中有一些常見的架構,這可以幫助我們理解核心服務的工作原理。Spring Cloud提供了強大的工具來增強基于Spring Boot的應用程序,以此來實現(xiàn)這些架構。


這里寫圖片描述

Config service
Spring Cloud Config是用于分布式系統(tǒng)的水平可擴展的集中式配置服務。支持本地存儲、Git和Subversion。

在這個項目中,使用native profile,它從本地類路徑加載配置文件。可以查看shared在Config服務資源中的目錄?,F(xiàn)在,當通知服務請求其配置時,配置服務以shared/notification-service.ymlshared/application.yml響應(在所有客戶端應用程序之間共享)。

客戶端使用
只需構建具有spring-cloud-starter-config依賴的Spring Boot應用程序,自動配置將完成其余所有工作。

現(xiàn)在,不需要在應用程序中使用任何嵌入式屬性。只需提供bootstrap.yml應用程序名稱和配置服務url:

spring:
   application:
     name:notification-service 
  cloud:
     config:
       uri:http:// config:8888 
      fail-fast:true

使用Spring Cloud Config,可以動態(tài)地更新配置。
例如,EmailService bean已注釋@RefreshScope。這意味著,可以更改電子郵件文本和主題,而不需要重新部署啟動通知服務。

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

此外,也可以使用Repository webhooks自動執(zhí)行此過程

****小結:**

  • 動態(tài)更新有一些限制。@RefreshScope不與@Configuration類一起使用,并且不影響@Scheduled方法
  • fail-fast屬性意味著Spring Boot如果它無法連接到Config
    Service就將啟動失敗,這在批量啟動時非常有用。
  • 安全注意事項請往下看

Auth service
授權的責任完全抽取到單獨的服務器,它為后端資源服務授予OAuth2令牌。Auth服務器用于用戶授權以及在外圍內(nèi)的安全的機器對機器通信。

在這個項目中,我使用Password credentials授權類型的用戶授權(因為它只由本地PiggyMetrics UI使用)和Client Credentials授予微服務權限。

Spring云安全提供了方便的注釋和自動配置,使得從服務器端和客戶端端都很容易實現(xiàn)。您可以在文檔中了解更多信息,并在Auth Server代碼中檢查配置詳細信息。

從客戶端,一切工作與傳統(tǒng)的基于會話的授權完全相同。您可以Principal從請求中檢索對象,檢查用戶的角色和其他使用基于表達式的訪問控制和@PreAuthorize注釋的東西。

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

@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {
    return statisticsService.findByAccountName(name);
}

API Gateway
可以看到,有三個核心服務,它們向客戶端公開外部API。在現(xiàn)實世界的系統(tǒng)中,這個數(shù)字可以快速增長以及整個系統(tǒng)的復雜性。實際上,上百個服務可能涉及到渲染一個復雜的網(wǎng)頁。

在理論上,客戶端可以直接向每個微服務器發(fā)出請求。但是顯然,這個選項有挑戰(zhàn)和限制,如需要知道所有端點地址,分別執(zhí)行每個信息的http請求,在客戶端合并結果。另一個問題是非web友好的協(xié)議,可能在后端使用。

通常一個更好的方法是使用API??網(wǎng)關。它是進入系統(tǒng)的單個入口點,用于通過將它們路由到適當?shù)暮蠖朔諄硖幚碚埱?,或者通過調(diào)用多個后端服務并聚合結果。此外,它可以用于身份驗證,洞察,壓力和金絲雀測試,服務遷移,靜態(tài)響應處理,主動流量管理。

Netflix打開了這樣一個邊緣服務,現(xiàn)在使用Spring Cloud,我們可以使用一個@EnableZuulProxy注釋啟用它。在這個項目中,我使用Zuul來存儲靜態(tài)內(nèi)容(ui應用程序),并將請求路由到適當?shù)奈⒎?。這是一個簡單的基于前綴的路由配置Notification服務:

zuul:
   routes:
     notification-service:
         path:/ notifications / ** 
        serviceId:notification-service 
        stripPrefix:false

這意味著所有開始的請求/notifications都將路由到Notification服務。沒有硬編碼的地址,你可以看到。Zuul使用服務發(fā)現(xiàn)機制來定位通知服務實例,以及斷路器和負載平衡器,如下所述。

Service discovery
另一個公知的架構模式是服務發(fā)現(xiàn)。它允許自動檢測服務實例的網(wǎng)絡位置,由于自動擴展,故障和升級,可能會動態(tài)分配地址。

服務發(fā)現(xiàn)的關鍵部分是注冊表。我在這個項目中使用Netflix Eureka。當客戶端負責確定可用服務實例(使用注冊表服務器)和負載平衡請求的位置時,Eureka是客戶端發(fā)現(xiàn)模式的一個很好的例子。

使用Spring Boot,您可以輕松地使用spring-cloud-starter-eureka-server依賴關系,@EnableEurekaServer注釋和簡單配置屬性來構建Eureka注冊表。

支持@EnableDiscoveryClient注釋的客戶端支持bootstrap.yml應用程序名稱:

spring:
   application:
     name:notification-service

現(xiàn)在,在應用程序啟動時,它將注冊到Eureka服務器并提供元數(shù)據(jù),如主機和端口,運行狀況指示器URL,主頁等。Eureka從屬于一個服務的每個實例接收心跳消息。如果心跳故障切換到可配置的時間表,則實例將從注冊表中刪除。

此外,Eureka提供了一個簡單的界面,您可以跟蹤運行的服務和可用實例數(shù): http://localhost:8761

負載均衡器,斷路器和Http客戶端
Netflix OSS提供了另一個偉大的工具集。

Ribbon
Ribbon是一個客戶端負載均衡器,它為您提供了對HTTP和TCP客戶端行為的大量控制。與傳統(tǒng)的負載均衡器相比,每個線上調(diào)用不需要額外的跳躍 - 您可以直接聯(lián)系所需的服務。

開箱即用,它與Spring Cloud和服務發(fā)現(xiàn)本身集成。Eureka Client提供了可用服務器的動態(tài)列表,以便Ribbon可以在它們之間進行平衡。

Hystrix
Hystrix是斷路器模式的實現(xiàn),它提供了對通過網(wǎng)絡訪問的依賴性的延遲和故障的控制。主要思想是在具有大量微服務的分布式環(huán)境中停止級聯(lián)故障。這有助于快速失敗,并盡快恢復 - 自愈的容錯系統(tǒng)的重要方面。

除了斷路器控制,使用Hystrix,您可以添加一個后備方法,在主命令失敗的情況下調(diào)用該方法以獲取默認值。

此外,Hystrix生成每個命令的執(zhí)行結果和延遲的指標,我們可以用它來監(jiān)視系統(tǒng)行為。

Feign
Feign是一個聲明式Http客戶端,它與Ribbon和Hystrix無縫集成。實際上,使用一個spring-cloud-starter-feign依賴項和@EnableFeignClients注釋,您擁有一組完整的負載平衡器,斷路器和Http客戶端,并具有合理的即用型默認配置。

以下是帳戶服務的示例:

@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);

}
  • 你需要的只是一個接口
  • 你可以用@RequestMapping在Spring MVC控制器和Feign方法之間共享部分
  • 上面的示例指定只需要的服務id -
    statistics-service,由于通過Eureka自動發(fā)現(xiàn)(但顯然,您可以訪問任何資源與特定的網(wǎng)址)

監(jiān)視儀表板
在這個項目配置中,Hystrix的每個微服務通過Spring Cloud Bus(使用AMQP代理)將指標推送到Turbine。監(jiān)控項目只是一個小的Spring啟動應用程序與渦輪和Hystrix儀表板。

看下面如何讓它運行。

讓我們看看我們的系統(tǒng)在負載下的行為:帳戶服務調(diào)用統(tǒng)計服務,它的響應具有不同的模仿延遲。響應超時閾值設置為1秒。

image
image
image
image
0 ms delay 500 ms delay 800 ms delay 1100 ms delay
表現(xiàn)良好的系統(tǒng)。吞吐量約為22請求/秒。統(tǒng)計服務中的活動線程數(shù)較少。中位服務時間約為50 ms。 活動線程的數(shù)量在增加。我們可以看到紫色線程池拒絕的數(shù)量,因此約30-40%的錯誤,但電路仍然關閉。 半開狀態(tài):故障命令的比率大于50%,斷路器啟動。在睡眠窗口的時間后,下一個請求被允許通過。 100%的請求失敗。電路現(xiàn)在永久打開。在睡眠時間后重試不會再次閉合電路,因為單個請求太慢。

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

安全
高級安全配置超出了此概念驗證項目的范圍。對于真實系統(tǒng)的更真實的模擬,考慮使用https,JCE密鑰庫加密微服務密碼和配置服務器屬性內(nèi)容(有關詳細信息,請參閱文檔)。

基建自動化

部署微服務及其相互依賴性,比部署單片應用程序要復雜得多。擁有完全自動化的基礎設施非常重要。我們可以通過持續(xù)交付方法實現(xiàn)以下優(yōu)勢:

  • 隨時釋放軟件的能力
  • 任何構建可能最終都是發(fā)布
  • 構建工件一次 - 根據(jù)需要部署

這里是一個簡單的連續(xù)交付工作流,在這個項目中實現(xiàn):


這里寫圖片描述

在此配置中,Travis CI為每個成功的git push建立標記的映像。因此,latest對于Docker Hub上的每個微服務總有圖像,并且用git提交哈希標記的舊圖像。它很容易部署任何一個,并快速回滾,如果需要。

如何運行所有的東西?
記住,你要啟動8個Spring Boot應用程序,4個MongoDB實例和RabbitMq。確保您4 Gb的計算機上有可用的RAM。您可以始終運行重要的服務,雖然:網(wǎng)關,注冊表,配置,Auth服務和帳戶服務。

在你開始之前

  • 安裝Docker和Docker Compose。
  • 出口環(huán)境變量:CONFIG_SERVICE_PASSWORD,NOTIFICATION_SERVICE_PASSWORD,STATISTICS_SERVICE_PASSWORD,ACCOUNT_SERVICE_PASSWORD,MONGODB_PASSWORD

生產(chǎn)模式
在這種模式下,所有最新的圖像將從Docker Hub中提取。只需復制docker-compose.yml和打docker-compose up -d。

開發(fā)模式
如果你想自己構建圖像(例如在代碼中有一些變化),你必須使用maven克隆所有的倉庫和構建工件。然后,運行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

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

重要端口

http://DOCKER-HOST:80 - Gateway
http://DOCKER-HOST:8761 - Eureka Dashboard
http://DOCKER-HOST:9000/hystrix - Hystrix Dashboard
http://DOCKER-HOST:8989 - Turbine stream (source for the Hystrix Dashboard)
http://DOCKER-HOST:15672 - RabbitMq management (default login/password: guest/guest)

小結

所有Spring Boot應用程序都需要運行Config Server進行啟動。但是我們可以同時啟動所有容器,因為fail-fastSpring Boot屬性和docker restart: always-compose選項。這意味著所有依賴的容器將嘗試重新啟動,直到Config Server啟動并運行。

此外,在所有應用程序啟動后,服務發(fā)現(xiàn)機制需要一些時間。任何服務都不可用于客戶端發(fā)現(xiàn),直到實例,Eureka服務器和客戶端都在其本地緩存中具有相同的元數(shù)據(jù),因此可能需要3個心跳。默認心跳周期為30秒。

順便在此給大家推薦一個Java方面的交流學習群:4112676,里面會分享一些高級面試題,還有資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務架構的原理,JVM性能優(yōu)化這些成為架構師必備的知識體系,主要針對Java開發(fā)人員提升自己,突破瓶頸,相信你來學習,會有提升和收獲。在這個群里會有你需要的內(nèi)容 朋友們請抓緊時間加入進來吧

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

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