微服務(wù)架構(gòu)和微服務(wù)的設(shè)計模式
微服務(wù)在企業(yè)中可以帶來積極的影響。 因此白魂,如何處理微服務(wù)體系架構(gòu)(MSA)和一些微服務(wù)設(shè)計模式以及微服務(wù)體系架構(gòu)的一般目標或原則是很有必要的福荸。 以下是微服務(wù)架構(gòu)實現(xiàn)中要考慮的四個目標
- 降低成本 — MSA將降低設(shè)計肴掷,實施和維護IT服務(wù)的整體成本
- 提高發(fā)布速度 — MSA將提高項目從構(gòu)建到部署的速度呆瞻。
- 提升彈性 — MSA將提升我們服務(wù)網(wǎng)絡(luò)的彈性
- 有可見性 — MSA為您的服務(wù)和網(wǎng)絡(luò)上提供更好的可見性痴脾。
MSA是建立在哪些原則基礎(chǔ)之上是需要你去了解的
- 可擴展性
- 可用性
- 彈性擴展
- 靈活性
- 獨立性,自主性
- 去中心化治理
- 故障隔離
- 自動配置
- 通過DevOps持續(xù)交付
在堅持這些原則基礎(chǔ)上推廣自己的解決方案或者系統(tǒng)會帶來一些挑戰(zhàn)和問題,這些問題在許多解決方案中都很常見买窟,而且可以通過使用正確的設(shè)計模式來解決丰泊, 這些就是微服務(wù)的設(shè)計模式,這些模式可以分為五個大類始绍,而每一類又包含了許多設(shè)計模式瞳购。具體如下圖所示:
解耦模式(Decomposition Patterns)
按業(yè)務(wù)能力解耦
通過運用單一職責(zé)原則,微服務(wù)總是會把服務(wù)之間的耦合變?yōu)樗神詈峡魍疲⒎?wù)通過業(yè)務(wù)能力解耦学赛,而且服務(wù)的定義是對應(yīng)于業(yè)務(wù)能力。業(yè)務(wù)能力這個概念來自于業(yè)務(wù)架構(gòu)模型盏浇,某種程度上來說,業(yè)務(wù)確實是可以產(chǎn)生價值芽狗,業(yè)務(wù)能力經(jīng)常是對應(yīng)于一個業(yè)務(wù)實體對象绢掰。例如:
- 訂單管理對應(yīng)于訂單
- 客戶管理對應(yīng)于客戶
按照子域解耦
按照業(yè)務(wù)能力解耦一個應(yīng)用可能是一個好的開始,但是你可能會遇到所謂的“神類”(God Classes),就是哪些不容易解耦的類童擎,而且這些類在多個服務(wù)之間很常見滴劲。領(lǐng)域驅(qū)動設(shè)計(DDD) 參考應(yīng)用問題空間--業(yè)務(wù)--做為一個域(domain)。一個域由多個子域組成顾复,而每一個子域?qū)?yīng)于業(yè)務(wù)的不同的部分班挖。
子域可以分類如下:
- 核心(Core) — 區(qū)分業(yè)務(wù)的關(guān)鍵 和 應(yīng)用中最有價值的部分
- 支撐(Supporting?) — 與業(yè)務(wù)相關(guān),但是不是關(guān)鍵部分芯砸,可以內(nèi)部實現(xiàn)萧芙,也可以外部實現(xiàn)
- 泛化(Generic?) — 不針對特定的業(yè)務(wù),理想情況下使用現(xiàn)成的軟件實施
訂單管理的子域包括:
- 產(chǎn)品目錄服務(wù)
- 庫存管理服務(wù)
- 訂單管理服務(wù)
- 交付管理服務(wù)
按事務(wù)解耦/兩階段提交(2PC)模式
可以通過事務(wù)分解服務(wù)假丧,然后系統(tǒng)中將會有多個事務(wù)双揪。 分布式事務(wù)處理的重要參與者之一是事務(wù)處理協(xié)調(diào)器[3]。分布式事務(wù)包括兩個步驟:
- 準備階段 — 在此階段中包帚,事務(wù)的所有參與者都準備提交并通知協(xié)調(diào)器他們已準備好完成事務(wù)渔期。
- 提交或者回滾階段 — 在此階段中,事務(wù)協(xié)調(diào)器向所有參與者發(fā)出提交或回滾命令
2PC的問題是和單個微服務(wù)執(zhí)行時間來對比耗時長婴噩。即使微服務(wù)在相同的網(wǎng)段中擎场,協(xié)調(diào)微服務(wù)之間的事務(wù)依舊會拖慢整個系統(tǒng)。因此這個解決方案一般不使用在高負載的場景中
扼殺模式
以上三種設(shè)計模式用于對未開發(fā)的應(yīng)用(greenfield apps)的解耦, 但是我們80%的工作都是和龐大而僵化的應(yīng)用(遺留代碼庫)打交道几莽。扼殺模式(Strangler Pattern)就是為了解決這個問題而來的迅办。在相同的URI空間中創(chuàng)建兩個獨立共存的應(yīng)用,隨著時間的推移章蚣,重構(gòu)過的新應(yīng)用將“扼殺”或者替代原來的應(yīng)用站欺,直到最終把龐大而僵化的應(yīng)用關(guān)閉掉姨夹。扼殺應(yīng)用(Strangler Application)的步驟分為轉(zhuǎn)換,共存和消滅三步[4]:
- 轉(zhuǎn)換(Transform?) —? 用現(xiàn)代方式創(chuàng)建一個新的平行的站點
- 共存(Coexist?) —? 將已有的站點重定向到新的站點矾策,新站點逐步實現(xiàn)老站點的功能
- 消滅(Eliminate?) —? 移除已有的站點的舊的功能
隔板模式
將應(yīng)用程序的元素隔離到池中磷账,以便如果其中一個失敗,其他應(yīng)用程序?qū)⒗^續(xù)運行提供服務(wù)贾虽,這個設(shè)計模式稱為隔板模式(Bulkhead), 因為他類似于船體中一個個被隔離的分區(qū)逃糟。根據(jù)使用者負載和可用性要求,這些分區(qū)服務(wù)實例被分割到不同的組里面蓬豁。這種設(shè)計模式有助于隔離故障(isolate failures), 并允許即使在故障期間仍可為某些使用者維持服務(wù)功能.
數(shù)據(jù)庫模式(Database Patterns)
為微服務(wù)定義數(shù)據(jù)庫架構(gòu)時绰咽,我們需要考慮以下幾點:
- 服務(wù)之間必須是松散耦合的, 它們可以獨立開發(fā),部署和擴展地粪。
- 業(yè)務(wù)事務(wù)在跨越多個微服務(wù)的時候保證不變
- 一些業(yè)務(wù)事務(wù)跨越多個微服務(wù)來查詢數(shù)據(jù)
- 有時數(shù)據(jù)庫必須可以復(fù)制取募,并且可以彈性共享
- 不同的服務(wù)有不同的數(shù)據(jù)存儲要求
每一個服務(wù)對應(yīng)一個數(shù)據(jù)庫(Database per Service)
為了解決上述問題,必須為每個微服務(wù)設(shè)計一個數(shù)據(jù)庫. 該數(shù)據(jù)庫只能是該服務(wù)私有的,并且只能通過微服務(wù)的API訪問蟆技,不能被其他的微服務(wù)直接訪問玩敏。例如,對關(guān)系型數(shù)據(jù)庫质礼,我們可以使用 每個服務(wù)有私有化的表(private-tables-per-service), 每個服務(wù)有自己的schema (schema-per-service), 或者每個服務(wù)有私有的數(shù)據(jù)庫服務(wù)器 (database-server-per-service)
每一個服務(wù)共享數(shù)據(jù)庫 (Shared Database per Service)
我們已經(jīng)討論了每個服務(wù)一個數(shù)據(jù)庫是微服務(wù)的理想選擇旺聚,但它是微服務(wù)的反模式(anti-pattern)。如果一個單一而又龐大的應(yīng)用几苍,并試圖把它拆分為微服務(wù)翻屈,那么數(shù)據(jù)庫的反范式化(denormalization )就不那么容易陈哑。將每個微服務(wù)共享數(shù)據(jù)庫不是理想的情況妻坝,但是是可行的解決方案。大多數(shù)人認為這是微服務(wù)的反模式惊窖,但對于brownfield 應(yīng)用刽宪,這是將應(yīng)用程序分解成較小邏輯部分的一個很好的開始。但是對于greenfield 應(yīng)用不太適用界酒。
命令查詢的責(zé)任分離 (Command Query Responsibility Segregation圣拄,CQRS)
一旦我們實現(xiàn)了每個服務(wù)對應(yīng)一個數(shù)據(jù)庫,就需要將從多個微服務(wù)查詢返回的數(shù)據(jù)連接起來毁欣。顯然這是不可能的庇谆。CQRS建議將應(yīng)用分為兩個部分 — 命令端 (command side)和查詢端 (query side):
- 命令端處理創(chuàng)建,更新和刪除請求
- 查詢端通過使用物化視圖來處理查詢部分
通常 事件溯源模式(event sourcing pattern)和它一起用來為任何數(shù)據(jù)更改創(chuàng)建事件凭疮。通過訂閱事件流饭耳,可以使物化視圖保持不斷的更新
事件溯源模式(event sourcing pattern)
大多數(shù)應(yīng)用程序都使用數(shù)據(jù),一個典型的途徑就是應(yīng)用保持當前的狀態(tài)执解。例如寞肖,傳統(tǒng)的創(chuàng)建,讀取,更新和刪除(CRUD)中新蟆,典型的數(shù)據(jù)處理是從存儲中讀取數(shù)據(jù)觅赊,它包含經(jīng)常使用事務(wù)鎖定數(shù)據(jù)的限制。
事件溯源模式定義了一系列事件驅(qū)動的數(shù)據(jù)的處理操作琼稻,每一個事件處理操作都會記錄在僅追加存儲中(append-only store)吮螺。應(yīng)用程序代碼發(fā)送一系列 命令式的描述了數(shù)據(jù)上發(fā)生的動作的事件到事件持久化存儲的地方。每個事件代表一組數(shù)據(jù)更改(例如帕翻,AddedItemToOrder)
這些事件持久化存儲在充當系統(tǒng)記錄系統(tǒng)的事件存儲中规脸。
觀察者模式(Observability Patterns)
日志聚合
考慮這樣一種情況:一個應(yīng)用包含多個微服務(wù)實例,每個請求經(jīng)常在橫跨多個微服務(wù)實例熊咽,那么每一個微服務(wù)實例都產(chǎn)生一個表轉(zhuǎn)化格式的日志文件莫鸭。 因此我們需要一個中心化的日志服務(wù)來將每個服務(wù)實例的日志收集起來。用戶可以搜索分析并分析日志横殴,并且配置一些當日志中出現(xiàn)特定信息的報警規(guī)則被因。例如:PCF確實有一個日志聚合器(Log aggregator), 用來收集PCF平臺上各個應(yīng)用的各個組件(router, controller, Diego, 等等…)的日志。AWS Cloud Watch也這樣做衫仑。
性能指標
因為微服務(wù)架構(gòu)導(dǎo)致服務(wù)的數(shù)量增加時梨与,密切注意事務(wù)變得十分關(guān)鍵,以便監(jiān)控微服務(wù)模式并且在問題發(fā)生的時候發(fā)出警告文狱。
一個指標服務(wù)用來收集每個單獨操作的統(tǒng)計信息粥鞋。它應(yīng)該聚合一個應(yīng)用服務(wù)的所有指標,以便提供報告和警報瞄崇。 聚合指標應(yīng)該包含兩個模塊:
- 推送 — 服務(wù)推送指標給指標服務(wù) 例如:NewRelic, AppDynamics
- 拉取 — 指標服務(wù)可以從每個服務(wù)中拉取指標 例如:Prometheus
分布式跟蹤
在微服務(wù)架構(gòu)中呻粹,請求通常跨越多個微服務(wù)苏研。 每個服務(wù)通過跨多個服務(wù)執(zhí)行一個或多個操作來處理一個請求等浊。 在進行故障排除時,有一個跟蹤ID是非常值得的摹蘑,這樣我們可以端對端的跟蹤請求筹燕。
解決方案是引入一個事務(wù)ID,可以使用以下方法:
- 為每個外部請求分配唯一的外部請求ID
- 將外部請求ID傳遞給所有服務(wù)
- 在所有日志消息中包括外部請求ID
健康檢查
實施微服務(wù)架構(gòu)后衅鹿,有一種可能是:服務(wù)可能會啟動但無法處理事務(wù)撒踪。每個服務(wù)都需要具有一個端點用來檢查應(yīng)用的健康程度,例如health大渤。這個API應(yīng)該檢查主機的狀態(tài), 與其他服務(wù)/基礎(chǔ)結(jié)構(gòu)的連接以及其他任意特定的邏輯制妄。
交叉關(guān)注模式(Cross-Cutting Concern Patterns)
外部配置(External Configuration)
一個典型的服務(wù)通常還會調(diào)用其他服務(wù)和數(shù)據(jù)庫,對于每一個環(huán)境兼犯,例如dev, QA, UAT, prod忍捡,這些環(huán)境的端點URL或某些配置屬性可能不同集漾,這些屬性中的任何一項更改都可能需要重新構(gòu)建或重新部署服務(wù)。
為了避免代碼修改砸脊,我們可以使用配置具篇,將所有的配置信息都外部化,包括端點URL和認證信息凌埂。應(yīng)用程序應(yīng)該在啟動時或運行時加載這些配置驱显。這些配置可以在應(yīng)用啟動的時候訪問到,或者這些配置在不需要重啟服務(wù)的情況下可以更新瞳抓。
服務(wù)發(fā)現(xiàn)模式
當遇見如圖所示的微服務(wù)架構(gòu)時埃疫,在微服務(wù)調(diào)用方面我們需要關(guān)注一些問題。
使用容器技術(shù)孩哑,IP地址可以動態(tài)分配給每個微服務(wù)實例栓霜, 每次地址更改時,消費者服務(wù)的調(diào)用都會中斷横蜒,需要手動更改才能恢復(fù)憾朴。
消費者必須記住每個服務(wù)URL申屹,并使其緊密耦合酬滤。
因此需要創(chuàng)建服務(wù)注冊贺喝,該服務(wù)注冊將保存每個生產(chǎn)型服務(wù)的元數(shù)據(jù)和每個服務(wù)的說明規(guī)范。服務(wù)實例在啟動時應(yīng)注冊到注冊中心澎蛛,而在實例關(guān)閉時應(yīng)注銷抚垄。服務(wù)發(fā)現(xiàn)有兩種類型:
- 客戶端,例如:Netflix Eureka
- 服務(wù)端:例如: AWS ALB
斷路器模式
一個服務(wù)通常會調(diào)用其他服務(wù)來查詢數(shù)據(jù)谋逻,有一種可能性是下游的服務(wù)會關(guān)閉呆馁,這將會帶來兩個問題:第一個是:上游服務(wù)繼續(xù)請求關(guān)閉的網(wǎng)絡(luò)服務(wù),直到耗盡網(wǎng)絡(luò)資源斤贰,并且降低系統(tǒng)性能智哀。第二個是:用戶體驗將是糟糕的且不可預(yù)測的次询。
消費者應(yīng)通過代理來調(diào)用遠程服務(wù)荧恍,該代理的行為類似于電路中的斷路器。當連續(xù)的請求失敗的次數(shù)超過閾值時屯吊,斷路器將跳閘一段時間送巡,并且在跳閘的這段時間內(nèi),所有的調(diào)用遠程服務(wù)的嘗試都將立即失敗盒卸。當超過了斷路器跳閘時間之后骗爆,斷路器將允許有限數(shù)量的測試請求通過。如果這些請求成功蔽介,則斷路器將恢復(fù)正常操作摘投。否則煮寡,如果有一個請求失敗,則斷路器再次跳閘犀呼。對于 一個應(yīng)用試圖嘗試調(diào)用一個遠程服務(wù)或者獲取共享資源幸撕,并且該操作很容易的失敗的情況來說, 這個模式非常適用外臂。
藍綠發(fā)布模式
在微服務(wù)架構(gòu)中坐儿,一個應(yīng)用程序可以具有許多微服務(wù)。 如果我們在停止所有服務(wù)之后然后部署增強版本宋光,則停機時間將是巨大的貌矿,并且可能影響業(yè)務(wù)。同樣罪佳,回滾將是一場噩夢逛漫。藍綠發(fā)布模式可以避免這種情況。
實施藍綠發(fā)布模式可以減少或消除停機時間赘艳,它通過運行兩個相同的生產(chǎn)環(huán)境:Blue和Green尽楔,來實現(xiàn)這一目標。這里我們假設(shè)綠色是已存在的工作實例第练,藍色是該應(yīng)用程序的新版本阔馋。在任何時候,只有一個環(huán)境處于活動狀態(tài)娇掏,該活動環(huán)境為所有生產(chǎn)流量提供服務(wù)呕寝。 所有云平臺均提供用于實施藍綠色部署的選項。