Go Micro(5)——架構(gòu)與微服務(wù)的設(shè)計(jì)模式
有很多關(guān)于 micro 架構(gòu)的疑問和微服務(wù)的設(shè)計(jì)模式的問題,今天我們討論一下這兩個(gè)話題。
關(guān)于Micro
Micro 是一個(gè)微服務(wù)工具箱,它有自己固有的設(shè)計(jì)模式,但插件化的架構(gòu)可以讓底層的實(shí)現(xiàn)很輕易的被替換。
micro 專注于定位微服務(wù)構(gòu)建過程中的最基本的需求,并通過精密的設(shè)計(jì)來滿足這些需求。
查看過往的文章可以了解微服務(wù)的理念和 Micro 的特性。
關(guān)于工具箱
Go Micro 是一個(gè)用 golang 編寫的,插件化的 RPC 框架。它提供了基礎(chǔ)的庫,比如服務(wù)發(fā)現(xiàn)、客戶端負(fù)載均衡、編解碼、同步異步通信等。
Micro API 是一個(gè) API 網(wǎng)關(guān),用于將外部的 HTTP 請(qǐng)求路由到內(nèi)部的 micro 服務(wù)上。它有單一的接入點(diǎn),可以通過反向代理或者 http 轉(zhuǎn)換成 RPC 來訪問。
Micro Web 是一個(gè) web 儀表盤,也是作為 micro web 應(yīng)用的反向代理。我們相信 web 應(yīng)用也應(yīng)該是一個(gè)微服務(wù),在微服務(wù)世界里也應(yīng)該是第一等公民。它表現(xiàn)的很像 Micro API 但也有單獨(dú)的特性比如 websocket。
Micro Sidecar 使用 http 服務(wù),提供了 go-micro 的所有特性。雖然我們喜歡 golang 來構(gòu)建微服務(wù),但你也許想使用其他語言。所以 Sidecar 提供了一種其他語言的應(yīng)用接入 Micro 世界的方式。
Micro CLI 是一個(gè)簡單直接的命令行接口,用于與你的服務(wù)交互。他也可以使用你的 Sidecar 作為代理來連接服務(wù)。
上面是很簡單的介紹,下面我們更加深入一些。
RPC,REST,Proto…
第一件你想到的事情是,為什么是 RPC,而不是 REST? 在內(nèi)部服務(wù)間的通信上,我們相信 RPC 是更合適的。或者更明確一點(diǎn),RPC 使用 protobuf 做編碼,通過 protobuf 定義 API。這種方式把兩個(gè)需求結(jié)合起來了:一個(gè)需求是需要明確定義的 API 接口,另一個(gè)需求是高性能的消息編解碼。RPC 是非常直接的通信方式。
我們?cè)谶@個(gè)選擇上并不孤獨(dú)。
Google 是 protobuf 的創(chuàng)造者,在內(nèi)部通過 gRPC 這個(gè)框架,大量的使用 RPC 調(diào)用。Hailo 也從 RPC/protobuf 的組合中收益很多,不僅是系統(tǒng)性能,開發(fā)速度也提高很多。Uber 選擇開發(fā)自己的RPC框架,名字叫 TChannel。
個(gè)人而言我認(rèn)為未來的 API 將會(huì)使用 RPC 進(jìn)行構(gòu)建,因?yàn)樗鼈兘Y(jié)構(gòu)化的格式、高效的編解碼提供了定義良好的 API 和高性能的通信。
HTTP to RPC,API…
事實(shí)上,我們?cè)?web 上 RPC 還有很長的路要走。在內(nèi)部 RPC 的表現(xiàn)是完美的,但在面對(duì)外部請(qǐng)求比如網(wǎng)站、手機(jī) app 的接口等等,就是另外一回事了。我們需要面對(duì)這個(gè),這就是為什么 Micro 需要一個(gè) API 網(wǎng)關(guān),用來接受并轉(zhuǎn)換 http 請(qǐng)求。
API 網(wǎng)關(guān)在微服務(wù)架構(gòu)中是一個(gè)常見的模式。它作為一個(gè)單一的接入點(diǎn),外部世界的請(qǐng)求,通過它進(jìn)行路由分發(fā)。它讓 HTTP API 可以由背后的很多服務(wù)所組成。
micro 的 API 網(wǎng)關(guān)使用路徑到服務(wù)的解決方案,因此不同的請(qǐng)求路徑,對(duì)應(yīng)了不同的服務(wù)。比如 /user => user api,/order => order api。
這里有一個(gè)例子。一個(gè)請(qǐng)求的路徑是 /comstomer/orders,這個(gè)請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到 go.micro.api.customer 這個(gè)服務(wù),會(huì)使用 Customer.Orders 這個(gè)方法進(jìn)行處理。

你也許會(huì)問,API 服務(wù)到底是怎樣的?我們下面來討論一下不同類型的服務(wù)。
服務(wù)的類型
微服務(wù)的關(guān)鍵理念就是業(yè)務(wù)的拆解,這是從 unix 的設(shè)計(jì)哲學(xué)中得到的啟示:『doing one thing and doing it well』,因?yàn)檫@個(gè)原因,我們認(rèn)為不同的服務(wù)需要有邏輯上和架構(gòu)上的區(qū)別,以實(shí)現(xiàn)自己不同的任務(wù)。
我們知道這些理念并沒有什么太大的新意,但在一些非常大而且成功的公司,它們的實(shí)踐取得了成功。我們的目標(biāo)是傳播這些開發(fā)理念,并通過工具來進(jìn)行指導(dǎo)。
目前我們定義了下面的幾種服務(wù)。
API
通過 micro api 運(yùn)行,API 服務(wù)在你的架構(gòu)中處于關(guān)鍵位置,大部分作用是接受外部世界的請(qǐng)求并分發(fā)到內(nèi)部的服務(wù)上。你可以通過 micro api 提供的反向代理 REST 模式進(jìn)行訪問,也可以通過 RPC 接口進(jìn)行訪問。
WEB
通過 micro web 運(yùn)行,web 服務(wù)專注于服務(wù) html 請(qǐng)求,構(gòu)建儀表盤。micro web 反向代理 http 和 websocket,目前只有這兩種協(xié)議支持,未來也許會(huì)增加。
SRV
這是后臺(tái)的 RPC 服務(wù),他們的目標(biāo)是為你的系統(tǒng)提供核心的功能,大部分并不是公開的接口。你仍然可以通過 micro api 和 micro web,使用 /rpc 接入點(diǎn)進(jìn)行訪問。這種接入方式直接使用 go-micro 的 client 進(jìn)行調(diào)用。

按照過去的經(jīng)驗(yàn),我們發(fā)現(xiàn)這樣的架構(gòu)設(shè)計(jì)非常強(qiáng)大。可以被擴(kuò)展到數(shù)以百計(jì)的服務(wù)。通過把它整合到 Micro 架構(gòu)中,我們發(fā)現(xiàn)它為微服務(wù)的開發(fā)提供了非常好的基礎(chǔ)。
Namespacing
你也許會(huì)想,怎樣區(qū)分 micro api 或者 micro web 以及服務(wù)呢。我們通過命名空間進(jìn)行拆分。通過命名的前綴,我們可以很清晰的看到,某個(gè)服務(wù)是哪種類型的。這很簡單但很高效。
micro api 會(huì)把 /customer 這樣的請(qǐng)求路徑定位到 go.micro.api.customer 服務(wù)。
默認(rèn)的命名空間是:
- API - go.micro.api
- WEB - go.micro.web
- SRV - go.micro.srv
你應(yīng)該把它設(shè)置成你的域名,比如 com.example.api。這些都可以進(jìn)行配置。
同步和異步
你經(jīng)常聽說微服務(wù)是很靈活的模式。大多數(shù)來說,微服務(wù)是關(guān)于創(chuàng)造事件驅(qū)動(dòng)的架構(gòu),以及設(shè)計(jì)通過異步通信的方式響應(yīng)的服務(wù)。
Micro 把異步通信作為微服務(wù)構(gòu)建中的第一等公民。事件通過異步消息,可以被任何人消費(fèi)并作出反應(yīng),搭建一個(gè)新服務(wù)不需要對(duì)系統(tǒng)的其他部分作出任何更改。這是一種強(qiáng)大的設(shè)計(jì)模式,因?yàn)檫@個(gè)原因,我們?cè)?go-micro 中定義了 Broker 接口。

異步和同步通信在Micro中是分離開的。Transport 接口用于構(gòu)建服務(wù)之間的點(diǎn)對(duì)點(diǎn)的通信。go-micro 中的 client 和 server 基于 transport 來進(jìn)行請(qǐng)求和返回RPC調(diào)用,提供了雙向的通信流。

在構(gòu)建系統(tǒng)時(shí),兩種通信方式都應(yīng)該使用,但關(guān)鍵是理解在什么場景下應(yīng)該用什么類型的通信方式。在大部分情況下并沒有好壞之分,我們需要權(quán)衡處理。
一個(gè) broker 和異步通信的典型使用方式是這樣:監(jiān)聽系統(tǒng)通過 broker 對(duì)服務(wù)的事件歷史進(jìn)行記錄。

在這個(gè)例子中,每個(gè)服務(wù)的每個(gè) API 在被調(diào)用時(shí),都會(huì)把事件上報(bào)到監(jiān)聽 topic,監(jiān)聽系統(tǒng)會(huì)訂閱這個(gè) topic,并把他們存儲(chǔ)到時(shí)間序列的數(shù)據(jù)庫中。在 admin 管理平臺(tái)可以看到任何用戶的操作歷史。
如果我們通過同步通信做,監(jiān)聽系統(tǒng)直接面對(duì)巨大的請(qǐng)求數(shù)。如果監(jiān)聽系統(tǒng)宕機(jī)了,我們就丟失了這些數(shù)據(jù)。通過把這些事件發(fā)布到 broker,我們可以異步的持久化這些數(shù)據(jù)。這是一種微服務(wù)中常見的事件驅(qū)動(dòng)設(shè)計(jì)模型。
我們?cè)鯓佣x微服務(wù)?
我們已經(jīng)討論了很多 Micro 能為微服務(wù)提供的工具箱,也定義了服務(wù)的類型。但還沒有真正討論,到底什么是微服務(wù)。
微服務(wù)與其他應(yīng)用的區(qū)別到底在哪里,微服務(wù)為什么叫微服務(wù)。
現(xiàn)在有很多不同的定義,但有兩條適合大部分微服務(wù)系統(tǒng)。
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
微服務(wù)的哲學(xué)與 unix 也類似
Do one thing and do it well
我們認(rèn)為微服務(wù)是這樣一種應(yīng)用程序:專注于單一的業(yè)務(wù),并通過明確定義的API對(duì)外提供服務(wù)。
看看我們?cè)谏缃痪W(wǎng)絡(luò)中怎樣使用微服務(wù):

其中一種是流行的 MVC 架構(gòu),在 MVC 世界中,每個(gè)實(shí)體代表了一個(gè)模型,模型又是作為數(shù)據(jù)庫的抽象。模型之間也許有一對(duì)多或者多對(duì)多的關(guān)系。controller 模塊負(fù)責(zé)處理請(qǐng)求,接受 model 模塊返回的數(shù)據(jù),并把數(shù)據(jù)傳輸?shù)?view 層,進(jìn)行渲染,最后輸出給用戶。
在微服務(wù)架構(gòu)中,面對(duì)同樣的例子。每個(gè)模型實(shí)際上是一個(gè)服務(wù),通過 API 進(jìn)行服務(wù)間通信。用戶請(qǐng)求,數(shù)據(jù)的集合以及渲染是通過一系列不同的 web 服務(wù)進(jìn)行處理的。每個(gè)服務(wù)有自身的專注點(diǎn),當(dāng)我們需要增加一個(gè)新特性時(shí),我們只需要把關(guān)聯(lián)的服務(wù)進(jìn)行修改,或者直接寫一個(gè)新的服務(wù)。分離的理念提供了大規(guī)模開發(fā)的模式。
版本

開發(fā)真實(shí)世界的軟件時(shí),版本是非常重要的。在微服務(wù)世界里,嚴(yán)格的把 API 和業(yè)務(wù)邏輯分離到許多不同的服務(wù)上,因?yàn)檫@個(gè)原因,服務(wù)的版本控制是核心的工具的很重要的一部分??梢宰屛覀?cè)诹髁亢艽髸r(shí)也能進(jìn)行升級(jí)。
在 go-micro 中,服務(wù)定義了名字和版本,Registry 模塊返回服務(wù)的列表,根據(jù)版本把節(jié)點(diǎn)進(jìn)行了區(qū)分。這里是 service 的接口定義。
type Service struct {
Name string
Version string
Metadata map[string]string
Endpoints []*Endpoint
Nodes []*Node
}
版本控制需要與 Selector 結(jié)合起來,selector 是客戶端的負(fù)載均衡機(jī)制,通過 selector 的策略實(shí)現(xiàn)請(qǐng)求根據(jù)版本進(jìn)行分發(fā)。
selector 是非常強(qiáng)大的接口,我們根據(jù)不同的路由算法,比如隨機(jī)、輪詢、根據(jù)標(biāo)簽、響應(yīng)時(shí)間等等。
通過使用默認(rèn)的隨機(jī)負(fù)載算法,再加上版本控制算法,我們就可以進(jìn)行灰度發(fā)布。

在未來,我們會(huì)嘗試實(shí)現(xiàn)一個(gè)全局的負(fù)載策略,根據(jù)歷史的趨勢進(jìn)行選擇,可以根據(jù)版本,設(shè)置不同的百分比,并動(dòng)態(tài)的為服務(wù)增加標(biāo)簽。
大規(guī)模擴(kuò)展
上面的介紹的版本系統(tǒng),是大規(guī)模擴(kuò)展服務(wù)時(shí)的基本模式。register 存儲(chǔ)了服務(wù)的注冊(cè)信息,我們通過 selector 實(shí)現(xiàn)了路由和負(fù)載均衡。
按照 doing one thing well 的理念,擴(kuò)展架構(gòu)也應(yīng)該是簡單、明確定義的 API、分層次的架構(gòu)。通過創(chuàng)造這些工具,我們可以構(gòu)建更加可靠的系統(tǒng),專注于更高級(jí)別的業(yè)務(wù)需求。
這是 Micro 編寫的基礎(chǔ)理念,也是我們希望微服務(wù)開發(fā)者遵循的理念。
當(dāng)我們?cè)谏a(chǎn)環(huán)境部署應(yīng)用時(shí),我們就需要構(gòu)建可擴(kuò)展、高容錯(cuò)、高性能的應(yīng)用。云計(jì)算讓我們可以進(jìn)行不受限制的擴(kuò)展,但是沒有任何東西會(huì)一直正常運(yùn)行。事實(shí)上,在構(gòu)建分布式系統(tǒng)中,怎樣對(duì)待運(yùn)行失敗的服務(wù)是非常重要的一方面,你在構(gòu)建你的系統(tǒng)時(shí),需要好好考慮。
在云計(jì)算的世界,我們想要在數(shù)據(jù)中運(yùn)行錯(cuò)誤,甚至多個(gè)數(shù)據(jù)中心運(yùn)行錯(cuò)誤的情況下,也能正常提供服務(wù)。在過去我們討論的是冷熱備份,或者是災(zāi)難恢復(fù)計(jì)劃。在今天,最先進(jìn)的技術(shù)公司,在全世界不停歇的運(yùn)作,每個(gè)程序都會(huì)有多個(gè)備份,運(yùn)行在世界上不同的數(shù)據(jù)中心。
我們需要向 google,facebook,netflix 和 Twitter 學(xué)習(xí),即使在數(shù)據(jù)中心運(yùn)行失敗時(shí),也要對(duì)用戶提供服務(wù),在多個(gè)數(shù)據(jù)中心運(yùn)行失敗時(shí),也需要盡快恢復(fù)。
Micro 可以讓你構(gòu)建這樣的應(yīng)用,通過插件化的架構(gòu),我們可以為不同的分布式系統(tǒng),實(shí)現(xiàn)不同的工具箱。
服務(wù)發(fā)現(xiàn)和注冊(cè)器是 Micro 的關(guān)鍵模塊,它們可以用于發(fā)現(xiàn)在數(shù)據(jù)中心中的一系列服務(wù),Micro API 可以用于路由和負(fù)載一系列的服務(wù)。
[圖片上傳中...(image.png-ffb75d-1513663516734-0)]
總結(jié)
希望這篇文章清晰的講解了Micro的架構(gòu),以及怎樣實(shí)現(xiàn)可擴(kuò)展的微服務(wù)設(shè)計(jì)模式。微服務(wù)首先是一種軟件設(shè)計(jì)模式,我們可以通過工具實(shí)現(xiàn)基礎(chǔ)、核心的功能,同時(shí)也能靈活組合其他設(shè)計(jì)模式。
因?yàn)?Micro 是一個(gè)插件化的架構(gòu),它強(qiáng)大的能力,可以實(shí)現(xiàn)不同的設(shè)計(jì)模式,在不同的場景中都能使用。比如你構(gòu)建一個(gè)視頻流的服務(wù),你也許需要基于 http 的點(diǎn)對(duì)點(diǎn)服務(wù)。如果你對(duì)性能不敏感,你也許需要使用消息隊(duì)列比如 NATS 或 RabbitMQ。
使用Micro這樣的工具進(jìn)行開發(fā)是非常讓人興奮的。