使用 Spring Cloud 和 Docker 輕松構建微服務架構涣雕!

原文:https://dzone.com/articles/microservice-architecture-with-spring-cloud-and-do
作者:Alexander Lukyanchikov
譯者:Oopsguy

【編者的話】如何使用Spring Boot、Spring Cloud浴鸿、Docker和Netflix的一些開源工具來構建一個微服務架構匣沼。本文通過使用Spring Boot瘪板、Spring Cloud和Docker構建的概念型應用示例,提供了了解常見的微服務架構模式的起點揩慕。

該代碼可以在GitHub上獲得亭畜,并且在Docker Hub上提供了鏡像。您只需要一個命令即可啟動整個系統(tǒng)迎卤。

https://github.com/sqshq/PiggyMetrics

我選擇了一個老項目作為這個系統(tǒng)的基礎拴鸵,它的后端以前是單一應用。此應用提供了處理個人財務蜗搔、整理收入開銷劲藐、管理儲蓄、分析統(tǒng)計和創(chuàng)建簡單預測等功能樟凄。

功能服務

整個應用分解為三個核心微服務聘芜。它們都是可以獨立部署的應用,圍繞著某些業(yè)務功能進行組織缝龄。

image

賬戶服務

包含一般用戶輸入邏輯和驗證:收入/開銷記錄汰现、儲蓄和賬戶設置。

image

統(tǒng)計服務

計算主要的統(tǒng)計參數(shù)叔壤,并捕獲每一個賬戶的時間序列瞎饲。數(shù)據(jù)點包含基于貨幣和時間段正常化后的值炼绘。該數(shù)據(jù)可用于跟蹤賬戶生命周期中的現(xiàn)金流量動態(tài)嗅战。

image

通知服務

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

image

注意

  • 每一個微服務擁有自己的數(shù)據(jù)庫驮捍,因此沒有辦法繞過API直接訪問持久數(shù)據(jù)。

  • 在這個項目中铅辞,我使用MongoDB作為每一個服務的主數(shù)據(jù)庫厌漂。擁有一個多種類持久化架構(polyglot persistence architecture)也是很有意義的。

  • 服務間(Service-to-service)通信是非常簡單的:微服務僅使用同步的REST API進行通信≌迳海現(xiàn)實中的系統(tǒng)的常見做法是使用互動風格的組合苇倡。例如富纸,執(zhí)行同步的GET請求檢索數(shù)據(jù),并通過消息代理(broker)使用異步方法執(zhí)行創(chuàng)建/更新操作旨椒,以便解除服務和緩沖消息之間的耦合晓褪。然而,這帶給我們是最終的一致性综慎。

基礎設施服務

分布式系統(tǒng)中常見的模式涣仿,可以幫助我們描述核心服務是怎樣工作的。Spring Cloud提供了強大的工具示惊,可以增強Spring Boot應用的行為來實現(xiàn)這些模式好港。我會簡要介紹一下:

image

配置服務

Spring Cloud Config是分布式系統(tǒng)的水平擴展集中式配置服務。它使用了當前支持的本地存儲米罚、Git和Subversion等可拔插存儲庫層(repository layer)钧汹。

在此項目中,我使用了native profile录择,它簡單地從本地classpath下加載配置文件拔莱。您可以在配置服務資源中查看shared目錄。現(xiàn)在隘竭,當通知服務請求它的配置時塘秦,配置服務將響應回shared/notification-service.yml和shared/application.yml(所有客戶端應用之間共享)。

客戶端使用

只需要使用sprng-cloud-starter-config依賴構建Spring Boot應用动看,自動配置將會完成其它工作尊剔。

現(xiàn)在您的應用中不需要任何嵌入的properties,只需要提供有應用名稱和配置服務url的bootstrap.yml即可:

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

使用Spring Cloud Config弧圆,您可以動態(tài)更改應用配置

比如赋兵,EmailService bean使用了@RefreshScope注解。這意味著您可以更改電子郵件的內(nèi)容和主題搔预,而無需重新構建和重啟通知服務應用霹期。

首先,在配置服務器中更改必要的屬性拯田。然后历造,對通知服務執(zhí)行刷新請求:curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh

您也可以使用webhook來自動執(zhí)行此過程船庇。

http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_push_notifications_and_spring_cloud_bus

注意

  • 動態(tài)刷新存在一些限制吭产。@RefreshScope不能和@Configuraion類一同工作,并且不會作用于@Scheduled方法鸭轮。

  • fail-fast屬性意味著如果Spring Boot應用無法連接到配置服務臣淤,將會立即啟動失敗。當您一起啟動所有應用時窃爷,這非常有用邑蒋。

  • 下面有重要的安全提示

授權服務

負責授權的部分被完全提取到單獨的服務器姓蜂,它為后端資源服務提供OAuth2令牌。授權服務器用于用戶授權以及在周邊內(nèi)進行安全的機器間通信医吊。

在此項目中钱慢,我使用密碼憑據(jù)作為用戶授權的授權類型(因為它僅由本地應用UI使用)和客戶端憑據(jù)作為微服務授權的授權類型。

Spring Cloud Security提供了方便的注解和自動配置卿堂,使其在服務器端或者客戶端都可以很容易地實現(xiàn)束莫。您可以在文檔中了解到更多信息,并在授權服務器代碼中檢查配置明細草描。

授權服務器代碼:https://github.com/sqshq/PiggyMetrics/tree/master/auth-service/src/main/java/com/piggymetrics/auth

從客戶端來看览绿,一切都與傳統(tǒng)的基于會話的授權完全相同。您可以從請求中檢索Principal對象陶珠、檢查用戶角色和其它基于表達式訪問控制和@PreAuthorize注解的內(nèi)容挟裂。

PiggyMetrics(帳戶服務、統(tǒng)計服務揍诽、通知服務和瀏覽器)中的每一個客戶端都有一個范圍:用于后臺服務的服務器、用于瀏覽器展示的UI栗竖。所以我們也可以保護控制器避免受到外部訪問暑脆,例如:

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

您可以看到,有三個核心服務狐肢。它們向客戶端暴露外部API添吗。在現(xiàn)實系統(tǒng)中,這個數(shù)量可以非撤菝快速地增長碟联,同時整個系統(tǒng)將變得非常復雜。實際上僵腺,一個復雜頁面的渲染可能涉及到數(shù)百個服務鲤孵。

理論上,客戶端可以直接向每個微服務直接發(fā)送請求辰如。但是這種方式是存在挑戰(zhàn)和限制的普监,如果需要知道所有端點的地址,分別對每一段信息執(zhí)行http請求琉兜,將結果合并到客戶端凯正。另一個問題是,這不是web友好協(xié)議豌蟋,可能只在后端使用廊散。

通常一個更好的方法是使用API網(wǎng)關。它是系統(tǒng)的單個入口點梧疲,用于通過將請求路由到適當?shù)暮蠖朔栈蛘咄ㄟ^調(diào)用多個后端服務并聚合結果來處理請求允睹。此外施符,它還可以用于認證、insights擂找、壓力測試戳吝、金絲雀測試(canary testing)、服務遷移贯涎、靜態(tài)響應處理和主動變換管理听哭。

聚合結果:http://techblog.netflix.com/2013/01/optimizing-netflix-api.html

Netflix開源這樣的邊緣服務,現(xiàn)在用Spring Cloud塘雳,我們可以用一個@EnabledZuulProxy注解來啟用它陆盘。在這個項目中,我使用Zuul存儲靜態(tài)內(nèi)容(UI應用)败明,并將請求路由到適當?shù)奈⒎瞻怼R韵率且粋€簡單的基于前綴(prefix-based)路由的通知服務配置:

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

這意味著所有以/notification開頭的請求將被路由到通知服務。您可以看到妻顶,里面沒有硬編碼的地址酸员。Zuul使用服務發(fā)現(xiàn)機制來定位通知服務實例以及斷路器和負載均衡器,如下所述讳嘱。

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

另一種常見的架構模式是服務發(fā)現(xiàn)幔嗦。它允許自動檢測服務實例的網(wǎng)絡位置,由于自動擴展沥潭、故障和升級邀泉,它可能會動態(tài)分配地址。

服務發(fā)現(xiàn)的關鍵部分是注冊钝鸽。我使用Netflix Eureka進行這個項目汇恤,當客戶端需要負責確定可以用的服務實例(使用注冊服務器)的位置和跨平臺的負載均衡請求時,Eureka就是客戶端發(fā)現(xiàn)模式的一個很好的例子拔恰。

使用Spring Boot因谎,您可以使用spring-cloud-starter-eureka-server依賴、@EnabledEurekaServer注解和簡單的配置屬性輕松構建Eureka注冊中心(Eureka Registry)仁连。

使用@EnabledDiscoveryClient注解和帶有應用名稱的bootstrap.yml來啟用客戶端支持:

spring:application:name: notification-service

現(xiàn)在蓝角,在應用啟動時,它將向Eureka服務器注冊并提供元數(shù)據(jù)饭冬,如主機和端口使鹅、健康指示器URL、主頁等昌抠。Eureka接收來自從屬于某服務的每個實例的心跳消息患朱。如果心跳失敗超過配置的時間表,該實例將從注冊表中刪除炊苫。

此外裁厅,Eureka還提供了一個簡單的界面冰沙,您可以通過它來跟蹤運行中的服務和可用實例的數(shù)量:http://localhost:8761

image

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

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

Ribbon

Ribbon是一個客戶端負載均衡器拓挥,可以很好地控制HTTP和TCP客戶端的行為。與傳統(tǒng)的負載均衡器相比袋励,每次線上調(diào)用都不需要額外的跳躍——您可以直接聯(lián)系所需的服務侥啤。

它與Spring Cloud和服務發(fā)現(xiàn)是集成在一起的,可開箱即用茬故。Eureka客戶端提供了可用服務器的動態(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依賴和@EnabledFeignClients注解溉奕,您可以使用一整套負載均衡器、斷路器和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的自動發(fā)現(xiàn)(但顯然您可以使用特定的URL訪問任何資源)同波。

監(jiān)控儀表盤

在這個項目配置中鳄梅,Hystrix的每一個微服務都通過Spring Cloud Bus(通過AMQP broker)將指標推送到Turbine。監(jiān)控項目只是一個使用了Turbine和Hystrix儀表盤的小型Spring Boot應用未檩。

讓我們看看系統(tǒng)行為在負載下:賬戶服務調(diào)用統(tǒng)計服務和它在一個變化的模擬延遲下的響應戴尸。響應超時閾值設置為1秒。

image

日志分析

集中式日志記錄在嘗試查找分布式環(huán)境中的問題時非常有用冤狡。Elasticsearch孙蒙、Logstash和Kibana技術椣钐模可讓您輕松搜索和分析您的日志、利用率和網(wǎng)絡活動數(shù)據(jù)挎峦。在我的另一個項目中已經(jīng)有現(xiàn)成的Docker配置香追。

安全

高級安全配置已經(jīng)超過了此概念性項目的范圍。為了更真實地模擬真實系統(tǒng)坦胶,請考慮使用https和JCE密鑰庫來加密微服務密碼和配置服務器的properties內(nèi)容(有關詳細信息透典,請參閱文檔)。

基礎設施自動化

部署微服務比部署單一的應用的流程要復雜得多迁央,因為它們相互依賴掷匠。擁有完全基礎設置自動化是非常重要的。我們可以通過持續(xù)交付的方式獲得以下好處:

  • 隨時發(fā)布軟件的能力岖圈。

  • 任何構建都可能最終成為一個發(fā)行版本讹语。

  • 構建工件(artifact)一次,根據(jù)需要進行部署蜂科。

這是一個簡單的持續(xù)交付工作流程顽决,在這個項目的實現(xiàn):

在此配置中,Travis CI為每一個成功的Git推送創(chuàng)建了標記鏡像导匣。因此才菠,每一個微服務在Docker Hub上的都會有一個latest鏡像,而較舊的鏡像則使用Git提交的哈希進行標記贡定。如果有需要赋访,可以輕松部署任何一個,并快速回滾缓待。

image

如何運行全部蚓耽?

這真的很簡單,我建議您嘗試一下旋炒。請記住步悠,您將要啟動8個Spring Boot應用、4個MongoDB實例和RabbitMq瘫镇。確保您的機器上有4GB的內(nèi)存鼎兽。您可以隨時通過網(wǎng)關、注冊中心铣除、配置谚咬、認證服務和賬戶中心運行重要的服務。

運行之前

  • 安裝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并執(zhí)行docker-compose up -d即可。

開發(fā)模式

如果您想自己構建鏡像(例如互捌,在代碼中進行一些修改)潘明,您需要克隆所有倉庫(repository)并使用Mavne構建工件(artifact)。然后秕噪,運行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml繼承了docker-compose.yml钳降,附帶額外配置,可在本地構建鏡像腌巾,并暴露所有容器端口以方便開發(fā)遂填。

重要的端點(Endpoint)

  • localhost:80 —— 網(wǎng)關

  • localhost:8761 —— Eureka儀表盤

  • localhost:9000 —— Hystrix儀表盤

  • localhost:8989 —— Turbine stream(Hystrix儀表盤來源)

  • localhost:15672 —— RabbitMq管理

注意

所有Spring Boot應用都需要運行配置服務器才能啟動。得益于Spring Boot的fail-fast屬性和docker-compsoe的restart:always選項澈蝙,我們可以同時啟動所有容器吓坚。這意味著所有依賴的容器將嘗試重新啟動,直到配置服務器啟動運行為止灯荧。

此外礁击,服務發(fā)現(xiàn)機制在所有應用啟動后需要一段時間。在實例逗载、Eureka服務器和客戶端在其本地緩存中都具有相同的元數(shù)據(jù)之前哆窿,任何服務都不可用于客戶端發(fā)現(xiàn),因此可能需要3次心跳厉斟。默認的心跳周期為30秒挚躯。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市擦秽,隨后出現(xiàn)的幾起案子码荔,更是在濱河造成了極大的恐慌,老刑警劉巖感挥,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件目胡,死亡現(xiàn)場離奇詭異,居然都是意外死亡链快,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門眉尸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來域蜗,“玉大人,你說我怎么就攤上這事噪猾∶够觯” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵袱蜡,是天一觀的道長丝蹭。 經(jīng)常有香客問我,道長坪蚁,這世上最難降的妖魔是什么奔穿? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任镜沽,我火速辦了婚禮,結果婚禮上贱田,老公的妹妹穿的比我還像新娘缅茉。我一直安慰自己,他們只是感情好男摧,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布蔬墩。 她就那樣靜靜地躺著,像睡著了一般耗拓。 火紅的嫁衣襯著肌膚如雪拇颅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天乔询,我揣著相機與錄音樟插,去河邊找鬼。 笑死哥谷,一個胖子當著我的面吹牛岸夯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播们妥,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼猜扮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了监婶?” 一聲冷哼從身側響起旅赢,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惑惶,沒想到半個月后煮盼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡带污,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年僵控,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鱼冀。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡报破,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出千绪,到底是詐尸還是另有隱情充易,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布荸型,位于F島的核電站盹靴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稿静,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一梭冠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧自赔,春花似錦妈嘹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至他去,卻和暖如春毙驯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灾测。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工爆价, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人媳搪。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓铭段,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秦爆。 傳聞我的和親對象是個殘疾皇子序愚,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容