Micro 架構與設計 翻譯自 "Micro architecture & design patterns for microservices" 註: 原文作者即 Micro 框架的開發者。 過去幾個月中,我們收到了很多關於 micro 的微服務架構和設計模式的問題。所以今天我們試著解釋一下這兩方面 ...
Micro 架構與設計
翻譯自 Micro architecture & design patterns for microservices
註: 原文作者即 Micro 框架的開發者。
過去幾個月中,我們收到了很多關於 micro 的微服務架構和設計模式的問題。所以今天我們試著解釋一下這兩方面的問題。
關於 Micro
Micro 是一個微服務工具集。它被用來實現它的特性和介面,同時提供強大的可插拔的架構來保證基礎組件可以被替換掉。
Micro 專註於解決構建微服務系統的基礎需求。它採用了深思熟慮地富有預見性的方式來實現它的設計。
如果你想深入研究 Micro 工具集請點這裡查看上一篇博客,或者如果你想學習微服務的基本概念請查看這裡
在我們開始討論 Micro 的架構之前,我們將快速的介紹一下 Micro 的特性.
工具集
Go Micro
Go Micro是一個用 GO 來寫微服務的、可插拔的 RPC 框架。它提供了服務發現,客戶端負載均衡,編碼,同步非同步通訊等功能的庫。
Micro API
Micro API 是為訪問微服務提供了 HTTP 服務和路由功能的 API 網管。在 Micro 中,它提供一個單一的入口,它可以被用作反向代理,或者將 HTTP 請求轉換成 RPC.
Micro Web
Micro Web 是微型網路應用(micro web application)的儀錶盤和反向代理。我們相信 web 應用應該被構建成微服務因此應被看做微服務世界的一等公民。它像一個 API 的反向代理但它同時提供對 web socket 的支持。
Micro Sidecar
Micro Sidecar 提供將 go-micro 用作 HTTP 服務的所有功能。Sidecar 提供使用其他語言寫微服務應用的途徑。
Micro CLI
Micro CLI 是和你的微服務們交互的命令行介面。它還可以讓你在不想直接連接服務的時候使用 Sidecar 作為一個代理。
下麵讓我們更深入的瞭解。
RPC, REST, Proto...
你的第一個疑問可能就是,為什麼是 RPC 而不是 REST? 我們認為 RPC 更適合內部服務通信的場景。或者更具體的, 使用 protobuf 編碼並且用 protobuf IDL 定義 API 的 RPC。聯合使用這些技術能夠很方便的創建強定義的 API 介面和有效的消息編碼。RPC 是非常直觀的通信協議。
我們並不是這一信條的獨立擁護者。
Google 是 protobuf 的創造者,在內部使用 RPC 並且最近開源的 RPC 框架 gRPC. Hailo 同樣也是 RPC/Protobuf 的強烈倡導者,並從中受益匪淺,更有趣的是在跨團隊協助方面獲得的收益比系統性能上的收益更多。Uber 正則開發資金的 PRC 框架協議 TChannel。
我個人認為未來的 API 應該是使用 RPC 構建的,因為它有諸如 protobuf 這類的有良好的結構化的格式,有易用高效的編碼方法的協議,從而能構建強定義的 API 和高效的通訊。
HTTP 到 RPC, API...
然而在現實中,在 web 上使用 RPC 還有很長的路要走。儘管在數據中心內部使用 RPC 很完美,但是支撐高併發的網站和移動 API 又是另一回事。好吧,完全從 HTTP 切換到 RPC 來由很長的路要走。這也是為什麼 micro 提供了 API 網關組件,來支撐和轉換 HTTP 請求。
API gateway 是微服務架構中使用的一種模式。它是微服務和外界溝通的唯一入口,它根據 HTTP 請求調用對應的服務。API gateway 使一個 HTTP API 能夠組合調用多個不同的微服務。
這是一個很強大的模式。因 API 一部分的更改導致整個單一部署的服務掛掉的日子將一去不復返。
微服務 API 使用 路徑-服務 的解決方案,因此每個請求路徑能夠調用不同的微服務 API,例如 /user => user api, /order => order api
舉個例子,到 /customer/orders 的請求將被帶著方法名 Customer.Orders 轉發到 API go.micro.api.customer 。
你可能好奇, API 服務到底是什麼。現在我們來討論不同類型的服務。
微服務的類型
微服務的概念主要是按關註點分離 -- 從著名的 unix 哲學 doing one thing and doing it well 中借鑒了很多。出於這個原因,我們認為有必要從邏輯上和架構上將擁有不同任務的服務分離。
這些概念並不是什麼新的概念,最近變得很引人註目是因為它被一些非常成功的技術公司證明是可行的。我們的目標是推廣這些開發哲學並通過構建工具鏈來指導設計決策。
以下是我們定義的服務的類型。
API - 基於 micro api,API 服務在設施的最頂端,一般直接支撐你的移動或 web 應用。你可以使用 HTTP handler 建造它然後使用反向代理模式啟動 micro api,或者,預設情況下處理這種專門格式的 RPC API 請求和響應。
Web - 基於 micro web, 專門用來提供 html 內容和管理面板訪問的 Web 服務。micro web 為 HTTP 和 WebSockets 提供反向代理。目前,僅支持這兩周格式,未來可能會支持更多的格式。就像之前提到過的那樣,我們相信 “web 應用即微服務”。
SRV - 基於 RPC 的後端服務。它們主要關註於為你的系統提供核心功能並且大多數情況下不會對外開放。如果你願意,你仍可以使用 micro api 或 micro web 使用 /rpc 路徑來訪問它,但一般使用 go-micro 客戶端來直接調用它們。
基於以往的經驗,我們發現這種架構模式及其強大並且見到過使用它支撐數百個微服務的系統。
Namespacing(命名空間)
你可能會好奇,如何隔斷 micro api 和 micro web 之間的通信?我們使用邏輯命名空間里做分離。通過給服務名加首碼(prefix)我們清晰的確定它的意圖以及它在系統中的位置。這個簡單但有效的模式讓我們受益良多。
micro api 和 micro web 將組成由命名空間和請求路徑的第一個路徑組成的服務名稱。例如,訪問 api/customer 的請求變為 go.micro.api.customer。
預設的命名空間為:
- API - go.micro.api
- Web - go.micro.web
- SRV - go.micro.srv
你應該為你自己的功能變數名稱設定這些命名空間: com.example.{api, web, srv}。micro api 和 micro web 能夠配置成在運行時路由到你的命名空間。
同步和非同步
我們經常聽到微服務和響應式模式一同出現。對於大多數來說,微服務是創建事件驅動的架構,並且主要通過非同步通信的服務。
Micro 將非同步通信作為一等公民對待並且將其構建成為微服務的基礎組成部分之一。通過與事件非同步通信的方式允許任何人消費這些事件,並針對這些事件執行自己的任務。可以在此基礎上新的單獨部署的服務而不需要需改他們的其他任何方面。這是一個強大的設計模式並且正由於此我們在 go-micro 中實現了一個非同步的 broker 介面。
在 Micro 中,同步和非同步通信被放到隔離的需求中。Transport 介面用來創建服務間點對點的連接。構建在 transport 基礎上的 go-micro 客戶端和伺服器能夠提供請求-響應模式的 RPC 調用,也可以提供雙向流模式下的調用。
在構建系統時兩種通信模型都應該被使用,但關鍵是要理解什麼時候,在哪兒用哪種方式更合適。很多情況下,沒有對錯,但是我們還是要權衡兩種的利弊。
舉個例子,在製作用來保存跟蹤用戶操作歷史的審計系統時,broker 和非同步通信可能更合適。
在這個例子中,每個 AI 或者說服務,當一些動作發生(客戶登錄,更新簡介或下訂單)時都會肺部一個事件。審計服務將會訂閱這些事件並將它們存儲到按時間序列存儲的資料庫中。管理員或其他任何用戶都能看到任何用戶產生的任何事件發生的歷史。
如果這個系統被設計成同步的,當流量高或服務數量增加時,審計系統很容易被壓垮。如果審計系統宕機或者請求失敗我們可能會丟失這條歷史記錄。通過將這些事件發佈給 broker 我們能保持他們非同步。這是事件驅動型架構構建的微服務的一種通用模式。
咳咳,暫停一下,微服務的定義是什麼呢?
我們講了很多 Micro toolkit 提供的功能,也定義了很多類型的服務(API, WEB, SRV)但是並沒怎麼講微服務到底是什麼。
關於微服務的定義和解釋有很多,但這組是最合適的。
基於有限上下文的架構的低耦合的服務
--Adrian Cockcroft
將單個應用開發為一組跑在獨立進程上並且互相之間使用輕量級方法進行通信的微小的服務
--Martin Fowler
就像 unix 哲學說的那樣 Do one thing and do it well
--Doug McIlroy
我們認為一個微服務就是一個專註於一個實體(或領域)的應用 -- 並且通過強定義的 API 訪問它。
讓我們拿社交網路來舉個現實中的例子。
有一個軟體架構模式隨著 Ruby On Rails 的崛起而變得流行 -- 那就是 MVC(模型 -- 視圖 -- 控制)。
在 MVC 的世界里,每個實體,或者說,域,都被表示為一個從資料庫中抽象而來的模型。模型可能和其他模型之間有相互關係,比如說一對多,多對多。控制層處理收到的請求,從 model 中查詢數據,然後把它傳遞給用戶,從而展現給用戶。
現在舉一個微服務架構中同樣的例子。模型被服務取而代之,它通過 API 傳遞數據。用戶請求,數據收集和數據呈現由多個 web service 處理。
每個服務都有一個單一的關註點。當我們想添加一個新功能或新的實體時,我們可以簡單的修改關註於那個功能的服務或者直接寫一個新的服務。這種分離的方式提供了能夠很好 scale 的軟體開發方式。
接下來我們回歸正題。
版本管理
版本管理是現實軟體開發中重要的一部分。在微服務的世界中很重要的一點是 API 和業務邏輯是被分成很多不同的服務的。正由於此,服務的版本控制很重要,被放到核心工具庫中,提供更好的細粒度的控制和升級過程中的流量遷移。
在 go-micro 中服務有一個名字和版本號定義。倉庫(Registry)返回一個 list 表示一個服務 -- 通過節點
註冊時的版本號來區分這些節點。
這是我們用於構建基於版本的路由功能的構建模塊的一段代碼
type Service struct {
Name string
Version string
Metadata map[string]string
Endpoints []*Endpoint
Nodes []*Node
}
它和 Selector -- 一個客戶端的負載均衡 -- 結合起來使用,從而在 go-micro 內部保證請求分發到不同的版本上去。
Selector 是一個強大的介面。我們在它之上提供不同類型的路由演算法:隨機(預設),round robin(環形隊列?),基於標簽,基於延遲,等等。
通過預設的基於隨機哈希的負載均衡演算法,並逐步將新版本的服務實例加入,你可以執行藍綠發佈(link)並實行金絲雀測試。
未來我們會實現一個內嵌 selector 的面向全球服務的負載均衡服務來提供為既存的系統做路由決策。它還能勝任在運行時為不同版本的服務分配不同的負載的職能,並且能動態地為服務添加原信息或標簽,從而在此之上可以做動態的路由決策。
伸縮
上文關於版本控制的說明經已提及了伸縮一個服務使用的基礎模型。倉庫(registry)用來存儲服務的相關信息,selector 用來控制路由和負載均衡。
我們再一次實踐了關註點分離(separation of concoerns)和做一件事並把它做好(dooing one thing well)的哲學。伸縮基礎設施、代碼很依賴於簡化、強定義的 API 以及分層的架構。通過編寫上面那些構建模塊,我們能夠開發伸縮性更強的軟體系統,並專註於更高層面的東西。
這是 Micro 的基礎,也是在微服務世界里我們希望引領的軟體開發的方式。
在之前的文章 Micro on NATS中我們簡要討論了關於雲端架構模型的問題。現在我們簡單回顧下其中的一些觀點。
當在生產環境部署服務時,你希望你的系統是可伸縮的、能容錯的、以及性能優異的。雲計算使我們能構建有很強伸縮性能的服務,但很難不受錯誤影響。事實上容錯性是構建分散式系統時最關鍵的考察點之一。所以在構建基礎設施時,我們應該充分考慮容錯性。
在雲的世界里,我們希望能容忍可用區的錯誤,甚至是整個區域中斷。過去,我們嘗試通過熱備份,冷備份或者災難恢復計劃來應對。現在,技術最先進的公司們有一個國際慣例,那就是把每個應用製作多個副本跑在世界各地的多個數據中心上。
我們需要向 Google, Facebook, Netflix 和 Twitter 學習。我們必須保證我們構建的系統能在可用區失敗時不影響用戶而且在大多數情況下在數分鐘內解決可用區失敗。
通過提供可插拔的介面, Micro 可以構建這樣的架構。我們能為 micro toolkit 中的每個需求選用最合適的分散式系統。
服務發現和倉庫(registry)是 Micro 的構建模塊。他能用來在可用區,區域或其他配置範圍內隔離和發現服務。
然後 Micro API 能夠在這個拓補結構中路由以及負責均衡一系列的服務。
Microservices is first and foremost about software design patterns. We can enable certain foundational patterns through tooling while providing flexibility for other patterns to emerge or be used.
Because Micro is a pluggable architecture it’s a powerful enabler of a variety of design patterns and can be appropriately used in many scenarios. For example if you’re building video streaming infrastructure you may opt for the HTTP transport for point to point communication. If you are not latency sensitive then you may choose a transport plugin such as NATS or RabbitMQ instead.
The future of software development with a tool such as Micro is very exciting.
If you want to learn more about the services we offer or microservices, check out the blog, the website micro.mu or the github repo.
總結
希望這篇文章講清了 Micro 的架構和它如何使用可伸縮的設計模式來開發微服務應用。
微服務首先是一種軟體設計模式。
.... 感覺後面沒啥用,就略了...