1. 程式人生 > >想要設計自己的微服務?看這篇文章就對了

想要設計自己的微服務?看這篇文章就對了

歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~

本文通過使用Spring Boot,Spring Cloud和Docker構建的概念驗證應用程式的示例,為了解常見的微服務架構模式提供了一個起點。

該程式碼在Github上可用,並且可以在Docker Hub上獲得影象。只需一個命令即可啟動整個系統。

作為這個系統的基礎,我選擇了一箇舊專案,其後端曾經是一個整體。該應用程式提供了一種處理個人財務,組織收入和支出,管理儲蓄,分析統計資料和建立簡單預測的方法。

功能服務

整體應用程式被分解為三個核心微服務。所有這些都是可獨立部署的應用程式,圍繞某些業務功能組織。

img

帳戶服務

包含一般使用者輸入邏輯和驗證:收入/費用專案,節省和帳戶設定。

METHOD PATH DESCRIPTION USER AUTHENTICATED AVAILABLE FROM UI
GET /accounts/{account} Get specified account data
GET /accounts/current Get current account data × ×
GET /accounts/demo Get demo account data (pre-filled incomes/expenses items, etc) ×
PUT /accounts/current Save current account data × ×
POST /accounts/ Register new account

統計服務

對主要統計引數執行計算並捕獲每個帳戶的時間序列。資料點包含標準化為基本貨幣和時間段的值。此資料可用於跟蹤帳戶生命週期中的現金流動態。

METHOD PATH DESCRIPTION USER AUTHENTICATED AVAILABLE FROM UI
GET /statistics/{account} Get specified account statistics
GET /statistics/current Get current account statistics × ×
GET /statistics/demo Get demo account statistics ×
PUT /statistics/{account} Create or update time series datapoint for specified account

通知服務

儲存使用者的聯絡資訊和通知設定(如提醒和備份頻率)。計劃工作人員從其他服務收集所需資訊,並向訂閱客戶傳送電子郵件。

METHOD PATH DESCRIPTION USER AUTHENTICATED AVAILABLE FROM UI
GET /notifications/settings/current Get current account notification settings × ×
PUT /notifications/settings/current Save current account notification settings × ×

注意

  • 每個微服務都有自己的資料庫,因此無法繞過API並直接訪問永續性資料。
  • 對於這個專案,我使用MongoDB作為每個服務的主資料庫。擁有多語言永續性體系結構(以便選擇最適合服務要求的資料庫型別)也是有意義的。
  • 服務到服務通訊非常簡單:微服務僅使用同步REST API進行通訊。現實世界系統中的常見做法是使用互動方式的組合。例如,執行同步GET請求以檢索資料並通過Message broker使用非同步方法進行建立/更新操作,以便解耦服務和緩衝訊息。這帶給我們 一致性

基建服務

分散式系統中有許多常見模式,可以幫助我們使所描述的核心服務工作。Spring cloud 提供了強大的工具,可以增強Spring Boot應用程式的行為以實現這些模式。我簡要介紹一下:

img

配置服務

Spring Cloud Config 是分散式系統的水平可擴充套件集中配置服務。它使用可插入的儲存庫層,目前支援本地儲存,Git和Subversion。

在這個專案中,我使用 native profile,它只是從本地類路徑載入配置檔案。你可以在Config服務資源中檢視 share 目錄 。現在,當Notification-service請求它的配置時,使用shared/notification-service.yml 和 配置服務響應 shared/application.yml (在所有客戶端應用程式之間共享)。

客戶端使用

只需構建具有spring-cloud-starter-config 依賴性的Spring Boot應用程式 ,自動配置將完成剩下的工作。

現在,你的應用程式中不需要任何嵌入屬性。只需提供 bootstrap.yml 應用程式名稱和配置服務URL:

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

使用Spring Cloud Config,可以動態更改應用程式配置

例如, EmailService bean 使用註釋 @RefreshScope。這意味著你可以更改電子郵件文字和主題行,而無需重建和重新啟動Notification Service應用程式。

首先,在Config伺服器中更改所需的屬性。然後,對Notification服務執行重新整理請求: curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh

注意

  • 動態重新整理有一些限制。 @RefreshScope 不適用於 @Configuration 類,不能影響 @Scheduled 方法。
  • fail-fast property表示如果Spring Boot應用程式無法連線到Config Service,則會立即失敗啟動。當你同時啟動所有應用程式時,這非常有用 。
  • 下面有重要的安全說明。

驗證服務

授權職責完全提取到單獨的伺服器,該伺服器 為後端資源服務授予 OAuth2令牌。Auth Server用於使用者授權以及周邊內部的安全機器到機器通訊。

Spring Cloud Security提供方便的註釋和自動配置,使伺服器和客戶端都能輕鬆實現。你可以在文件中瞭解有關它的更多資訊, 並檢查Auth Server程式碼中的配置詳細資訊 。

從客戶端來看,一切都與傳統的基於會話的授權完全相同。你可以從Principal 請求中檢索 物件,使用基於表示式的訪問控制和@PreAuthorize 註釋檢查使用者角色和其他內容 。

PiggyMetrics中的每個客戶端(帳戶服務,統計服務,通知服務和瀏覽器)都有一個範圍: 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閘道器

如你所見,有三種核心服務,它們將外部API暴露給客戶端。在現實世界的系統中,這個數字可以非常快速地增長,並且整個系統的複雜性也會增加。實際上,渲染一個複雜的網頁可能涉及數百種服務

理論上,客戶端可以直接向每個微服務發出請求。但顯然這個選項存在挑戰和侷限,例如必須知道所有端點地址,分別對每個資訊和平執行http請求,在客戶端合併結果。另一個問題是非網路友好協議,可能在後端使用。

通常,更好的方法是使用API閘道器。它是進入系統的單一入口點,用於通過將請求路由到適當的後端服務或通過呼叫多個後端服務並聚合結果來處理請求 。此外,它還可用於身份驗證,壓力測試,服務遷移,靜態響應處理,主動流量管理。

Netflix開源了 這樣的優質服務,現在有了Spring Cloud,我們可以通過一個@EnableZuulProxy註釋啟用它 。在這個專案中,我使用Zuul儲存靜態內容(UI應用程式)並將請求路由到適當的微服務。以下是Notification服務的簡單基於字首的路由配置:

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

這意味著所有以請求開頭的請求 /notifications 都將路由到Notification服務。可以看到,沒有硬編碼的地址。Zuul使用 服務發現 機制來定位Notification服務例項以及 Circuit Breaker和Load Balancer

Service Discovery

另一種眾所周知的架構模式是Service Discovery。它允許自動檢測服務例項的網路位置,這些服務例項可能由於自動擴充套件,故障和升級而動態分配地址。

服務發現的關鍵部分是登錄檔。我在這個專案中使用了Netflix Eureka。當客戶端負責確定可用服務例項的位置(使用註冊伺服器)並在它們之間載入平衡請求時,Eureka是客戶端發現模式的一個很好的例子。

使用Spring Boot,你可以輕鬆地使用spring-cloud-starter-eureka-server 依賴項, @EnableEurekaServer 註釋和簡單配置屬性構建Eureka Registry 。

通過@EnableDiscoveryClient 註釋和 bootstrap.yml 應用程式名稱啟用客戶端支援 :

spring:
  application:
    name: notification-service

現在,在應用程式啟動時,它將向Eureka Server註冊並提供元資料,例如主機和埠,執行狀況指示器URL,主頁等.Eureka從屬於服務的每個例項接收訊息。如果故障超過可配置的時間表,則例項將從登錄檔中刪除。

此外,Eureka提供了一個簡單的介面,你可以在其中跟蹤正在執行的服務和可用例項的數量: http://localhost:8761

img

負載均衡器,斷路器和Http客戶端

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

Ribbon

Ribbon是一個客戶端負載均衡器,可以讓你對HTTP和TCP客戶端的行為進行大量控制。與傳統的負載均衡器相比,每次線上呼叫都不需要額外的跳過 - 你可以直接聯絡所需的服務。

開箱即用,它本身與Spring Cloud和Service Discovery整合。 Eureka Client 提供可用伺服器的動態列表,因此Ribbon可以在它們之間取得平衡。

Hystrix

Hystrix是Circuit Breaker模式的實現 ,它可以控制通過網路訪問的依賴關係的延遲和故障。主要思想是在具有大量微服務的分散式環境中停止級聯故障。這有助於快速失敗並儘快恢復 - 自我修復的容錯系統的重要方面。

除了斷路器控制之外,使用Hystrix還可以新增一個回退方法,以便在主命令失敗時獲取預設值。

此外,Hystrix會為每個命令生成執行結果和延遲的指標,我們可以使用它來 監控系統行為

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);
}
  • 你需要的只是一個介面
  • 你可以在Spring MVC控制器和Feign方法之間共享 @RequestMapping
  • 以上示例指定了所需的服務ID - statistics-service感謝Eureka的自動發現(但顯然你可以訪問具有特定URL的任何資源)

監控儀表板

在此專案配置中,每個帶有Hystrix的微服務都通過Spring Cloud Bus(使用AMQP代理)將指標推送到Turbine。Monitoring專案只是一個帶有TurbineHystrix Dashboard的小型Spring啟動應用程式 。

讓我們看看我們在負載下的系統行為:帳戶服務呼叫統計服務,它響應模仿延遲。響應超時閾值設定為1秒。

img

0 ms delay 500 ms delay 800 ms delay
表現良好的系統。吞吐量約為22個請求/秒。統計服務中的活動執行緒數量很少。中位服務時間約為50毫秒。 活動執行緒的數量正在增長。我們可以看到紫色執行緒池拒絕的數量,因此大約有30-40%的錯誤,但電路仍然關閉。 半開狀態:失敗命令的比例超過50%,斷路器啟動。睡眠視窗的時間量後,下一個請求通過。

日誌分析

在嘗試識別分散式環境中的問題時,集中日誌記錄非常有用。Elasticsearch,Logstash和Kibana堆疊使你可以輕鬆搜尋和分析日誌,利用率和網路活動資料。我的其他專案中描述隨時可用的Docker配置 。

安全

高階安全配置超出了此概念驗證專案的範圍。要更真實地模擬真實系統,請考慮使用https和JCE金鑰庫來加密微服務密碼和配置伺服器屬性內容( 有關詳細資訊,請參閱 文件)。

基建自動化

與部署整體應用程式相比,部署微服務具有相互依賴性,這是一個複雜得多的過程。擁有一個完全自動化的基礎設施非常重要。我們可以通過持續交付方法獲得以下好處:

  • 隨時釋出軟體的能力。
  • 任何構建都可能最終成為一個版本。
  • 構建工件一次,根據需要進行部署。

這是一個簡單的Continuous Delivery工作流程,在此專案中實現:

img

在此 配置中,Travis CI為每個成功的Git推送構建標記影象。因此latestDocker Hub上的每個微服務始終都有一個 映像,舊的映像使用Git commit hash進行標記。如果需要,可以輕鬆部署其中任何一個並快速回滾。

如何執行所有的東西?

這真的很容易,我建議你試試。請記住,你要啟動8個Spring Boot應用程式,4個MongoDB例項和RabbitMq。確保4 Gb 的計算機上有 RAM。你始終可以通過閘道器,登錄檔,配置,身份驗證服務和帳戶服務執行重要服務。

在你開始之前

  • 安裝Docker和Docker Compose。
  • 出口環境變數: CONFIG_SERVICE_PASSWORDNOTIFICATION_SERVICE_PASSWORDSTATISTICS_SERVICE_PASSWORDACCOUNT_SERVICE_PASSWORDMONGODB_PASSWORD

生產模式

在此模式下,所有最新影象都將從Docker Hub中提取。只需複製 docker-compose.yml 並點選即可 docker-compose up -d

發展模式

如果你想自己構建映像(例如,在程式碼中進行一些更改),則必須使用Maven克隆所有儲存庫並構建工件。然後,執行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml 繼承 docker-compose.yml 在本地構建映像的額外可能性,並公開所有容器埠以便於開發。

重要的終點

  • localhost:80 - 閘道器
  • localhost:8761 - Eureka Dashboard
  • localhost:9000 - Hystrix儀表板
  • localhost:8989 - Hystrix儀表板源
  • localhost:15672 - RabbitMq管理

注意

所有Spring Boot應用程式都需要執行 Config Server 才能啟動。但是我們可以同時啟動所有容器,因為 fail-fast Spring Boot屬性和 restart: always docker-compose選項。這意味著所有相關容器將嘗試重新啟動,直到Config Server啟動並執行。

此外,Service Discovery機制在所有應用程式啟動後需要一些時間。在例項,Eureka伺服器和客戶端在其本地快取中都具有相同的元資料之前,客戶端無法發現任何服務,因此可能需要3次偵聽。預設偵聽時間為30秒。

原文標題《Microservice Architectures With Spring Cloud and Docker》

作者:Alexander Lukyanchikov

譯者:我就靜靜地看

不代表雲加社群觀點,更多詳情請檢視原文連結

此文已由作者授權騰訊雲+社群釋出,更多原文請點選

搜尋關注公眾號「雲加社群」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!

海量技術實踐經驗,盡在雲加社群