Go Micro(5)——架構與微服務的設計模式
有很多關于 micro
架構的疑問和微服務的設計模式的問題,今天我們討論一下這兩個話題。
關于Micro
Micro
是一個微服務工具箱,它有自己固有的設計模式,但插件化的架構可以讓底層的實現很輕易的被替換。
micro
專注于定位微服務構建過程中的最基本的需求,并通過精密的設計來滿足這些需求。
查看過往的文章可以了解微服務的理念和 Micro
的特性。
關于工具箱
Go Micro
是一個用 golang
編寫的,插件化的 RPC
框架。它提供了基礎的庫,比如服務發現、客戶端負載均衡、編解碼、同步異步通信等。
Micro API
是一個 API
網關,用于將外部的 HTTP
請求路由到內部的 micro
服務上。它有單一的接入點,可以通過反向代理或者 http
轉換成 RPC
來訪問。
Micro Web
是一個 web
儀表盤,也是作為 micro web
應用的反向代理。我們相信 web
應用也應該是一個微服務,在微服務世界里也應該是第一等公民。它表現的很像 Micro API
但也有單獨的特性比如 websocket
。
Micro Sidecar
使用 http
服務,提供了 go-micro
的所有特性。雖然我們喜歡 golang
來構建微服務,但你也許想使用其他語言。所以 Sidecar
提供了一種其他語言的應用接入 Micro
世界的方式。
Micro CLI
是一個簡單直接的命令行接口,用于與你的服務交互。他也可以使用你的 Sidecar
作為代理來連接服務。
上面是很簡單的介紹,下面我們更加深入一些。
RPC,REST,Proto…
第一件你想到的事情是,為什么是 RPC
,而不是 REST
? 在內部服務間的通信上,我們相信 RPC
是更合適的?;蛘吒鞔_一點,RPC
使用 protobuf
做編碼,通過 protobuf
定義 API
。這種方式把兩個需求結合起來了:一個需求是需要明確定義的 API
接口,另一個需求是高性能的消息編解碼。RPC
是非常直接的通信方式。
我們在這個選擇上并不孤獨。
Google
是 protobuf
的創造者,在內部通過 gRPC
這個框架,大量的使用 RPC
調用。Hailo
也從 RPC/protobuf
的組合中收益很多,不僅是系統性能,開發速度也提高很多。Uber
選擇開發自己的RPC框架,名字叫 TChannel
。
個人而言我認為未來的 API
將會使用 RPC
進行構建,因為它們結構化的格式、高效的編解碼提供了定義良好的 API
和高性能的通信。
HTTP to RPC,API…
事實上,我們在 web
上 RPC
還有很長的路要走。在內部 RPC
的表現是完美的,但在面對外部請求比如網站、手機 app
的接口等等,就是另外一回事了。我們需要面對這個,這就是為什么 Micro
需要一個 API
網關,用來接受并轉換 http
請求。
API
網關在微服務架構中是一個常見的模式。它作為一個單一的接入點,外部世界的請求,通過它進行路由分發。它讓 HTTP API
可以由背后的很多服務所組成。
micro
的 API
網關使用路徑到服務的解決方案,因此不同的請求路徑,對應了不同的服務。比如 /user => user api,/order => order api
。
這里有一個例子。一個請求的路徑是 /comstomer/orders
,這個請求會被轉發到 go.micro.api.customer
這個服務,會使用 Customer.Orders
這個方法進行處理。
你也許會問,API
服務到底是怎樣的?我們下面來討論一下不同類型的服務。
服務的類型
微服務的關鍵理念就是業務的拆解,這是從 unix
的設計哲學中得到的啟示:『doing one thing and doing it well』,因為這個原因,我們認為不同的服務需要有邏輯上和架構上的區別,以實現自己不同的任務。
我們知道這些理念并沒有什么太大的新意,但在一些非常大而且成功的公司,它們的實踐取得了成功。我們的目標是傳播這些開發理念,并通過工具來進行指導。
目前我們定義了下面的幾種服務。
API
通過 micro api
運行,API
服務在你的架構中處于關鍵位置,大部分作用是接受外部世界的請求并分發到內部的服務上。你可以通過 micro api
提供的反向代理 REST
模式進行訪問,也可以通過 RPC
接口進行訪問。
WEB
通過 micro web
運行,web
服務專注于服務 html
請求,構建儀表盤。micro web
反向代理 http
和 websocket
,目前只有這兩種協議支持,未來也許會增加。
SRV
這是后臺的 RPC
服務,他們的目標是為你的系統提供核心的功能,大部分并不是公開的接口。你仍然可以通過 micro api
和 micro web
,使用 /rpc
接入點進行訪問。這種接入方式直接使用 go-micro
的 client
進行調用。
按照過去的經驗,我們發現這樣的架構設計非常強大??梢员粩U展到數以百計的服務。通過把它整合到 Micro
架構中,我們發現它為微服務的開發提供了非常好的基礎。
Namespacing
你也許會想,怎樣區分 micro api
或者 micro web
以及服務呢。我們通過命名空間進行拆分。通過命名的前綴,我們可以很清晰的看到,某個服務是哪種類型的。這很簡單但很高效。
micro api
會把 /customer
這樣的請求路徑定位到 go.micro.api.customer
服務。
默認的命名空間是:
- API - go.micro.api
- WEB - go.micro.web
- SRV - go.micro.srv
你應該把它設置成你的域名,比如 com.example.api
。這些都可以進行配置。
同步和異步
你經常聽說微服務是很靈活的模式。大多數來說,微服務是關于創造事件驅動的架構,以及設計通過異步通信的方式響應的服務。
Micro
把異步通信作為微服務構建中的第一等公民。事件通過異步消息,可以被任何人消費并作出反應,搭建一個新服務不需要對系統的其他部分作出任何更改。這是一種強大的設計模式,因為這個原因,我們在 go-micro
中定義了 Broker
接口。
異步和同步通信在Micro中是分離開的。Transport
接口用于構建服務之間的點對點的通信。go-micro
中的 client
和 server
基于 transport
來進行請求和返回RPC調用,提供了雙向的通信流。
在構建系統時,兩種通信方式都應該使用,但關鍵是理解在什么場景下應該用什么類型的通信方式。在大部分情況下并沒有好壞之分,我們需要權衡處理。
一個 broker
和異步通信的典型使用方式是這樣:監聽系統通過 broker
對服務的事件歷史進行記錄。
在這個例子中,每個服務的每個 API
在被調用時,都會把事件上報到監聽 topic
,監聽系統會訂閱這個 topic
,并把他們存儲到時間序列的數據庫中。在 admin
管理平臺可以看到任何用戶的操作歷史。
如果我們通過同步通信做,監聽系統直接面對巨大的請求數。如果監聽系統宕機了,我們就丟失了這些數據。通過把這些事件發布到 broker
,我們可以異步的持久化這些數據。這是一種微服務中常見的事件驅動設計模型。
我們怎樣定義微服務?
我們已經討論了很多 Micro
能為微服務提供的工具箱,也定義了服務的類型。但還沒有真正討論,到底什么是微服務。
微服務與其他應用的區別到底在哪里,微服務為什么叫微服務。
現在有很多不同的定義,但有兩條適合大部分微服務系統。
Loosely coupled service oriented architecture with a bounded context
An approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms
微服務的哲學與 unix
也類似
Do one thing and do it well
我們認為微服務是這樣一種應用程序:專注于單一的業務,并通過明確定義的API對外提供服務。
看看我們在社交網絡中怎樣使用微服務:
其中一種是流行的 MVC
架構,在 MVC
世界中,每個實體代表了一個模型,模型又是作為數據庫的抽象。模型之間也許有一對多或者多對多的關系。controller
模塊負責處理請求,接受 model
模塊返回的數據,并把數據傳輸到 view
層,進行渲染,最后輸出給用戶。
在微服務架構中,面對同樣的例子。每個模型實際上是一個服務,通過 API
進行服務間通信。用戶請求,數據的集合以及渲染是通過一系列不同的 web
服務進行處理的。每個服務有自身的專注點,當我們需要增加一個新特性時,我們只需要把關聯的服務進行修改,或者直接寫一個新的服務。分離的理念提供了大規模開發的模式。
版本
開發真實世界的軟件時,版本是非常重要的。在微服務世界里,嚴格的把 API
和業務邏輯分離到許多不同的服務上,因為這個原因,服務的版本控制是核心的工具的很重要的一部分??梢宰屛覀冊诹髁亢艽髸r也能進行升級。
在 go-micro
中,服務定義了名字和版本,Registry
模塊返回服務的列表,根據版本把節點進行了區分。這里是 service
的接口定義。
type Service struct {
Name string
Version string
Metadata map[string]string
Endpoints []*Endpoint
Nodes []*Node
}
版本控制需要與 Selector 結合起來,selector
是客戶端的負載均衡機制,通過 selector
的策略實現請求根據版本進行分發。
selector
是非常強大的接口,我們根據不同的路由算法,比如隨機、輪詢、根據標簽、響應時間等等。
通過使用默認的隨機負載算法,再加上版本控制算法,我們就可以進行灰度發布。
在未來,我們會嘗試實現一個全局的負載策略,根據歷史的趨勢進行選擇,可以根據版本,設置不同的百分比,并動態的為服務增加標簽。
大規模擴展
上面的介紹的版本系統,是大規模擴展服務時的基本模式。register
存儲了服務的注冊信息,我們通過 selector
實現了路由和負載均衡。
按照 doing one thing well 的理念,擴展架構也應該是簡單、明確定義的 API
、分層次的架構。通過創造這些工具,我們可以構建更加可靠的系統,專注于更高級別的業務需求。
這是 Micro
編寫的基礎理念,也是我們希望微服務開發者遵循的理念。
當我們在生產環境部署應用時,我們就需要構建可擴展、高容錯、高性能的應用。云計算讓我們可以進行不受限制的擴展,但是沒有任何東西會一直正常運行。事實上,在構建分布式系統中,怎樣對待運行失敗的服務是非常重要的一方面,你在構建你的系統時,需要好好考慮。
在云計算的世界,我們想要在數據中運行錯誤,甚至多個數據中心運行錯誤的情況下,也能正常提供服務。在過去我們討論的是冷熱備份,或者是災難恢復計劃。在今天,最先進的技術公司,在全世界不停歇的運作,每個程序都會有多個備份,運行在世界上不同的數據中心。
我們需要向 google,facebook,netflix 和 Twitter 學習,即使在數據中心運行失敗時,也要對用戶提供服務,在多個數據中心運行失敗時,也需要盡快恢復。
Micro
可以讓你構建這樣的應用,通過插件化的架構,我們可以為不同的分布式系統,實現不同的工具箱。
服務發現和注冊器是 Micro
的關鍵模塊,它們可以用于發現在數據中心中的一系列服務,Micro API
可以用于路由和負載一系列的服務。
[圖片上傳中...(image.png-ffb75d-1513663516734-0)]
總結
希望這篇文章清晰的講解了Micro的架構,以及怎樣實現可擴展的微服務設計模式。微服務首先是一種軟件設計模式,我們可以通過工具實現基礎、核心的功能,同時也能靈活組合其他設計模式。
因為 Micro
是一個插件化的架構,它強大的能力,可以實現不同的設計模式,在不同的場景中都能使用。比如你構建一個視頻流的服務,你也許需要基于 http
的點對點服務。如果你對性能不敏感,你也許需要使用消息隊列比如 NATS
或 RabbitMQ
。
使用Micro這樣的工具進行開發是非常讓人興奮的。