Go Micro(6)——構(gòu)建彈性、高容錯(cuò)的應(yīng)用

Go Micro(6)——構(gòu)建彈性、高容錯(cuò)的應(yīng)用

構(gòu)建分布式系統(tǒng)是很有挑戰(zhàn)性的,這毫無(wú)疑問(wèn)。雖然我們已經(jīng)解決了很多工程上的問(wèn)題,我們?nèi)匀恢貜?fù)的在構(gòu)建許多模塊。目前,由于我們開(kāi)始了更高級(jí)別的抽象,虛擬機(jī)到容器技術(shù),適應(yīng)新的語(yǔ)言,作用于云計(jì)算,都對(duì)微服務(wù)提出了要求。總有一些事情需要我們不斷的去學(xué)習(xí),怎樣構(gòu)建高性能的、高容錯(cuò)的系統(tǒng)仍然是下一波的技術(shù)浪潮。

重復(fù)與創(chuàng)新之間的戰(zhàn)爭(zhēng)從未停止,但我們需要做一些事情,通過(guò)云計(jì)算、容器技術(shù)、微服務(wù)來(lái)緩解我們的痛苦。

動(dòng)機(jī)

我們?yōu)槭裁催@樣做?為什么我們持續(xù)的重新構(gòu)建同樣的模塊,為什么我們持續(xù)的嘗試解決大規(guī)模、容錯(cuò)性和分布式系統(tǒng)的問(wèn)題?

我腦海中出現(xiàn)的是『bigger, stronger, faster』,或者是『speed, scale, agility』,你可能經(jīng)常從 C 級(jí)別的管理人員口中聽(tīng)到這個(gè)說(shuō)法。但關(guān)鍵的是,確實(shí)存在這樣的需求,需要我們構(gòu)建更加高性能和要彈性的系統(tǒng)。

在互聯(lián)網(wǎng)的早期,只有數(shù)千或者數(shù)萬(wàn)用戶在線,隨著時(shí)間的推移,我們看到開(kāi)始加速,現(xiàn)在我們面對(duì)的是數(shù)十億用戶和數(shù)十億的設(shè)備。我們需要學(xué)習(xí)怎樣為目前的情況構(gòu)建系統(tǒng)。

上一代的人也許記得 C10K problem,我不確定我們現(xiàn)在處在什么階段,但我想我們現(xiàn)在談?wù)摰氖前偃f(wàn)級(jí)的并發(fā)。世界上最大的技術(shù)公司,在10年前就已經(jīng)解決了這個(gè)問(wèn)題,也有了模式來(lái)構(gòu)建這樣大規(guī)模的系統(tǒng)。但剩下的其他人仍然在學(xué)習(xí)。

像 Amazon,Google,Microsoft 現(xiàn)在提供給我們的云計(jì)算平臺(tái),對(duì)大規(guī)模部署是有益的。但我們?nèi)匀慌υ诟闱宄鯓泳帉?xiě)應(yīng)用程序,可以高效的利用這些大規(guī)模的資源。你也許這些天聽(tīng)說(shuō)了容器的編排,微服務(wù)、云計(jì)算很多了。工作在很多層面上推進(jìn)著,當(dāng)我們完全確定了我們的模式,確定了需要解決的問(wèn)題,我們的 Micro 就能作為工業(yè)級(jí)的產(chǎn)品發(fā)布了,這還需要一段時(shí)間。

許多公司現(xiàn)在求助的問(wèn)題是『我該怎樣構(gòu)建可擴(kuò)展的、高容錯(cuò)的系統(tǒng)?』但目前對(duì)這些重要的問(wèn)題,有幫助的回答是很少的。

我該怎樣編寫(xiě)可擴(kuò)展的、高容錯(cuò)的系統(tǒng)?

Micro 看起來(lái)通過(guò)專(zhuān)注于微服務(wù)的必要的軟件開(kāi)發(fā)工具,定位了問(wèn)題。我們會(huì)詳細(xì)的談?wù)勗鯓訋椭銟?gòu)建有彈性的、高容錯(cuò)的系統(tǒng),我們從 client 端開(kāi)始。

客戶端

客戶端在 go-micro 中是用于發(fā)起請(qǐng)求的模塊,如果你已經(jīng)構(gòu)建過(guò)微服務(wù)或者 SOA 架構(gòu),你會(huì)知道重要的一部分時(shí)間和執(zhí)行過(guò)程是花在調(diào)用其他服務(wù)獲取相關(guān)信息上面。

然而在巨大的應(yīng)用中,關(guān)注點(diǎn)主要在接受請(qǐng)求返回內(nèi)容,在微服務(wù)世界中,更像是取回或者發(fā)布內(nèi)容。

這里是精簡(jiǎn)過(guò)的 go-microclient 的接口,有最重要的三個(gè)方法 Call, PublishStream

type Client interface {
    Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error
    Publish(ctx context.Context, p Publication, opts ...PublishOption) error
    Stream(ctx context.Context, req Request, opts ...CallOption) (Streamer, error)
}

type Request interface {
    Service() string
    Method() string
    ContentType() string
    Request() interface{}
    Stream() bool
}

CallStream 是用來(lái)做同步通信請(qǐng)求,Call 返回一個(gè)單一的結(jié)果,而 Stream 是一個(gè)雙向的流式連接,與另一個(gè)服務(wù)維持著,其中任何消息都可以發(fā)進(jìn)來(lái)也可以發(fā)出去。Publish 用于發(fā)布異步的消息,通過(guò) broker,但我們今天不討論它。

客戶端是怎樣工作的,前面的文章已經(jīng)討論過(guò)了。翻看以前的文章即可。

我們只是特別的討論一些重要的內(nèi)部細(xì)節(jié)。

客戶端使用 RPC 層,結(jié)合 broker,codec,register,selectortransport 來(lái)提供豐富的組合。分層的架構(gòu)非常重要,所以我們可以把單個(gè)的組件進(jìn)行分離,減少了整體的復(fù)雜性,也提供了插件化的能力。

為什么客戶端重要?

客戶端本質(zhì)上抽象了與服務(wù)端之間的有彈性的、高容錯(cuò)的通信過(guò)程。像另一個(gè)服務(wù)發(fā)起請(qǐng)求看起來(lái)是非常直接的,但有幾種情況是可能潛在的發(fā)生失敗的。

下面我們開(kāi)始了解這些功能和他們是怎樣運(yùn)作的。

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

在分布式系統(tǒng)中,服務(wù)因?yàn)楦鞣N原因會(huì)頻繁的加入和脫離集群。網(wǎng)絡(luò)隔離、機(jī)器故障、調(diào)度等等。我們并不真正想關(guān)心它們。

當(dāng)我們像另一個(gè)服務(wù)發(fā)起請(qǐng)求,我們通過(guò)名字識(shí)別服務(wù),并允許客戶端通過(guò)服務(wù)發(fā)現(xiàn)獲取到服務(wù)的一系列實(shí)例,得到各個(gè)實(shí)例的地址和端口。服務(wù)在啟動(dòng)時(shí)在服務(wù)發(fā)現(xiàn)中心進(jìn)行注冊(cè),在退出時(shí)進(jìn)行注銷(xiāo)。

image.png

正如我們提到的,任何類(lèi)型的問(wèn)題都會(huì)出現(xiàn)在分布式系統(tǒng),服務(wù)發(fā)現(xiàn)也不例外。所以我們依賴于經(jīng)過(guò)嚴(yán)格測(cè)試的分布式服務(wù)發(fā)現(xiàn)系統(tǒng),例如 consul、etcdzookeeper,使用它們存儲(chǔ)服務(wù)的信息。

它們都使用基于 PaxosRaft 算法來(lái)進(jìn)行網(wǎng)絡(luò)選舉,這解決了我們的一致性問(wèn)題。通過(guò)運(yùn)行一個(gè)3到5個(gè)節(jié)點(diǎn)的集群,我們可以容忍大部分的系統(tǒng)故障,為客戶端提供穩(wěn)定可靠的服務(wù)。

節(jié)點(diǎn)選擇

現(xiàn)在我們可靠的把服務(wù)名字解析到了一堆地址列表。我們?cè)鯓舆x擇其中的一個(gè)進(jìn)行調(diào)用呢?這就是 go-micro 中的 selector 發(fā)揮作用的地方。它基于 register 模塊構(gòu)建,提供負(fù)載均衡策略,比如輪詢或者隨機(jī),也提供過(guò)濾、緩存和黑名單的功能。

這里是定義的接口:

type Selector interface {
    Select(service string, opts ...SelectOption) (Next, error)
    Mark(service string, node *registry.Node, err error)
    Reset(service string)
}

type Next func() (*registry.Node, error)
type Filter func([]*registry.Service) []*registry.Service
type Strategy func([]*registry.Service) Next

負(fù)載策略

當(dāng)前的策略是非常簡(jiǎn)單直接的,當(dāng) Selector 被調(diào)用時(shí),它從 register 獲取到服務(wù),然后創(chuàng)建一個(gè) Next 函數(shù),從節(jié)點(diǎn)池中選擇出符合要求的節(jié)點(diǎn)。

客戶端會(huì)調(diào)用這個(gè) Next 函數(shù),根據(jù)負(fù)載均衡策略,獲取到下一個(gè)符合要求的節(jié)點(diǎn),并發(fā)出請(qǐng)求。如果這個(gè)請(qǐng)求失敗了,而且重試次數(shù)大于1,它會(huì)使用相同的程序,獲取下一個(gè)節(jié)點(diǎn),再次調(diào)用。

這里是有很多不同的策略的,比如輪詢、隨機(jī)、最少連接、權(quán)重等等。負(fù)載均衡策略對(duì)于分布式系統(tǒng)是必不可少的。

緩存

雖然有一個(gè)可靠的服務(wù)發(fā)現(xiàn)系統(tǒng)是很好的,但每次請(qǐng)求都去查詢一次并不高效。如果你想象一個(gè)大規(guī)模的系統(tǒng),每個(gè)服務(wù)都這樣做,很容易就會(huì)使服務(wù)發(fā)現(xiàn)系統(tǒng)過(guò)載。這會(huì)讓整個(gè)系統(tǒng)不可用。

為了避免這種情況,我們可以使用緩存。大部分的服務(wù)發(fā)現(xiàn)系統(tǒng)提供了一個(gè)監(jiān)聽(tīng)更新的機(jī)制,一般來(lái)說(shuō)叫做 Watcher。不是去輪詢服務(wù)發(fā)現(xiàn)系統(tǒng),而是等待事件發(fā)送給我們。go-microRegistry 提供了 Watch 的概念。

我們已經(jīng)編寫(xiě)了一個(gè)帶緩存的 selector,它把服務(wù)緩存在內(nèi)存中。如果緩存中不存在時(shí),它會(huì)去服務(wù)發(fā)現(xiàn)系統(tǒng)查找,緩存,并用于之后的請(qǐng)求。如果 watch 事件收到了,緩存模塊會(huì)與 register 進(jìn)行更新。

首先,通過(guò)移除服務(wù)查找,大大的提高了性能。這也提供了一定的容錯(cuò),萬(wàn)一服務(wù)發(fā)現(xiàn)系統(tǒng)宕機(jī)了呢?我們?nèi)匀挥幸稽c(diǎn)偏執(zhí),害怕緩存由于節(jié)點(diǎn)發(fā)生故障而被污染了,所以節(jié)點(diǎn)都維持著合適的 TTL。

黑名單

下面介紹一下黑名單,注意一下 Selector 的接口有 MarkReset 方法。我們不同真正的保證,注冊(cè)進(jìn)來(lái)的節(jié)點(diǎn)都是健康的,所以我們需要做黑名單。

任何一個(gè)請(qǐng)求發(fā)送之后,我們都會(huì)跟蹤它的結(jié)果。如果這個(gè)服務(wù)的實(shí)例出現(xiàn)了多次失敗,我們就可以大體上把這個(gè)節(jié)點(diǎn)加入黑名單,并過(guò)濾掉它。

節(jié)點(diǎn)在回到節(jié)點(diǎn)池之前會(huì)在黑名單中會(huì)存在一段時(shí)間,這是很?chē)?yán)格的,如果這個(gè)節(jié)點(diǎn)失敗了我們就需要移除掉它。這樣我們可以持續(xù)的返回成功的請(qǐng)求,不會(huì)有任何延遲。

超時(shí)與重試

Adrian Cockroft 最近開(kāi)始討論在微服務(wù)架構(gòu)中消失的組件,其中一個(gè)有意思的是,傳統(tǒng)的超時(shí)和重試策略導(dǎo)致了雪崩效應(yīng)。我建議你看看這個(gè)演示。這個(gè)演示把問(wèn)題總結(jié)的特別好。

image.png

Adrian 在上面描述的是一種常見(jiàn)的情況,一個(gè)緩慢的響應(yīng)會(huì)導(dǎo)致超時(shí),然后客戶端會(huì)觸發(fā)重試。這事實(shí)上是一個(gè)請(qǐng)求鏈路,這創(chuàng)造了一系列的新請(qǐng)求,而舊有的請(qǐng)求仍然在處理中。這樣的配置失誤會(huì)導(dǎo)致大量服務(wù)的過(guò)載,造成的調(diào)用失敗是很難回滾的。

在微服務(wù)世界,我們需要重新想想,處理重試和超時(shí)的策略。Adrian 繼續(xù)討論了潛在的解決方案。其中一種方式是超時(shí)之后,在新的節(jié)點(diǎn)上發(fā)起請(qǐng)求。

image.png

在重試的這方面,我們已經(jīng)在 Micro 中使用了。重試的次數(shù)可以進(jìn)行配置,如果你調(diào)用了一個(gè)失敗的節(jié)點(diǎn),客戶端會(huì)在新的節(jié)點(diǎn)發(fā)起重試。

超時(shí)經(jīng)常被深思熟慮,但事實(shí)上經(jīng)常從傳統(tǒng)的靜態(tài)超時(shí)設(shè)置開(kāi)始。直到Adrian演示了他的想法,超時(shí)策略變得很清晰了。

預(yù)算型超時(shí)策略現(xiàn)在也內(nèi)置在Micro中,讓我們看看它是怎樣工作的。

第一個(gè)調(diào)用設(shè)置了超時(shí),每個(gè)調(diào)用鏈上的請(qǐng)求都會(huì)消耗整體的超時(shí)時(shí)間。如果時(shí)間為0了,我們就會(huì)停止請(qǐng)求或重試,并返回調(diào)用鏈。

按照 Adrian 提到的,提供動(dòng)態(tài)的預(yù)算型超時(shí)是非常好的,避免了不必要的雪崩。

更遠(yuǎn)一點(diǎn)來(lái)說(shuō),下一步應(yīng)該是移除任何類(lèi)型靜態(tài)的超時(shí)。服務(wù)的響應(yīng)時(shí)間根據(jù)環(huán)境的不同,請(qǐng)求的不同是不同的。這應(yīng)該是動(dòng)態(tài)的 SLA,根據(jù)當(dāng)前的狀態(tài)進(jìn)行調(diào)整,但這些事會(huì)留在未來(lái)解決。

連接池

連接池是構(gòu)建可擴(kuò)展系統(tǒng)的很重要部分,我們很快就看到了沒(méi)有連接池的局限性,經(jīng)常導(dǎo)致文件描述符數(shù)量達(dá)到限制,導(dǎo)致端口用盡。

目前有個(gè)進(jìn)行中的 PRgo-micro 增加了連接池,由于 Micro 插件化的特性,把連接池放在 transport 的上層很重要,這樣 HTTP,NATS,RabbitMQ 等等,都會(huì)受益。

你也許會(huì)想,這是特定實(shí)現(xiàn)的,一些 transport 也許已經(jīng)支持了。這是對(duì)的,不能總是保證在不同的 transport 下工作效果是一樣的。通過(guò)把這個(gè)放置于上層,我們減少了 transport 模塊的復(fù)雜性。

其他?

確實(shí)有很多好用的東西是go-micro內(nèi)置的,那么還有什么呢?我很高興你這么問(wèn)…

服務(wù)版本

我們有這個(gè)功能,這個(gè)功能在前面的文章也討論過(guò)了。服務(wù)包括名字和版本,注冊(cè)在服務(wù)發(fā)現(xiàn)系統(tǒng)。當(dāng)一個(gè)服務(wù)從注冊(cè)器中查詢出來(lái)時(shí),它的節(jié)點(diǎn)是按照版本分組的。這樣一樣,selector 就可以根據(jù)版本,進(jìn)行流量負(fù)載。

image.png

為什么版本很重要

當(dāng)我們發(fā)布新版本時(shí),這非常重要,它可以確保所有事情運(yùn)作正常,這樣才能把所有服務(wù)進(jìn)行升級(jí)。新版本可以被部署到一個(gè)小型的節(jié)點(diǎn)上,客戶端會(huì)自動(dòng)的分發(fā)一定比例的請(qǐng)求到這個(gè)新的節(jié)點(diǎn)。通過(guò)結(jié)合一些編排系統(tǒng)比如 Kubernetes,你可以非常有信心的部署,一旦有任何問(wèn)題也可以回滾。

過(guò)濾

我們也有,selector 是非常強(qiáng)大的,它有能力把過(guò)濾條件傳遞進(jìn)去,對(duì)節(jié)點(diǎn)進(jìn)行過(guò)濾。這在 client 端調(diào)用時(shí)可以傳遞參數(shù)。一些已經(jīng)存在的過(guò)濾可以在這里看到,比如 metadata,endpoint 和版本過(guò)濾。

為什么過(guò)濾重要

你也許有一些功能只在某些特定版本的服務(wù)上存在。需要將這些請(qǐng)求分發(fā)到這些特定版本的服務(wù)上。這是非常好的功能,特別是多個(gè)不同版本的服務(wù)在同時(shí)運(yùn)行時(shí)。

另外一個(gè)有用的地方是,你想要根據(jù)地區(qū)對(duì)服務(wù)進(jìn)行路由。通過(guò)設(shè)置數(shù)據(jù)中心的標(biāo)簽在服務(wù)上,你可以過(guò)濾出本地的節(jié)點(diǎn)。根據(jù) metadata 進(jìn)行過(guò)濾是非常強(qiáng)大的,希望有更多的應(yīng)用能夠把這個(gè)功能使用起來(lái)。

插件化的架構(gòu)

Micro 原生的插件化架構(gòu)是你一次又一次聽(tīng)到的。這從設(shè)計(jì)的第一天就已經(jīng)確定了。這是非常重要的,Micro 提供模塊來(lái)構(gòu)建整個(gè)系統(tǒng)。有時(shí)候的運(yùn)行會(huì)超出控制,但這些都可以改善。

為什么插件化很重要?

每個(gè)人對(duì)怎樣構(gòu)建分布式系統(tǒng)都有自己的想法,我們實(shí)際上是提供了一個(gè)方式,讓人們能設(shè)計(jì)他們想要的解決方案。不僅如此,現(xiàn)在也有很多經(jīng)過(guò)嚴(yán)格測(cè)試的工具,我們可以直接使用,而不是自己重寫(xiě)任何東西。

技術(shù)始終在進(jìn)化,全新的、更好的工具每天都在出現(xiàn)。我們?cè)鯓颖苊庵共讲磺?,插件化的架?gòu)意味著我們可以使用目前的組件,未來(lái)也可以使用更好的組件進(jìn)行替代。

插件

每個(gè) go-micro 的特性都被設(shè)計(jì)成 golang 中的接口,通過(guò)這樣做,我們可以實(shí)際上替換底層的實(shí)現(xiàn),這幾乎不需要進(jìn)行代碼改動(dòng)。在大部分情況下,只需要簡(jiǎn)單的引用這個(gè)包,然后在啟動(dòng)時(shí)加入?yún)?shù)就可以了。

go-plugins 有很多現(xiàn)成的插件可以使用。

go-micro 目前提供了默認(rèn)的 consul 作為服務(wù)發(fā)現(xiàn)系統(tǒng),http 作為 transport,你也許會(huì)想要使用一些別的東西,或者實(shí)現(xiàn)自己的插件。我們已經(jīng)有社區(qū)的貢獻(xiàn)者分享了 Kubernetes 的注冊(cè)插件和 Zookeeper 的注冊(cè)插件。

怎樣使用插件

大部分時(shí)候,插件的使用類(lèi)似這樣:

# Import the plugin
import _ "github.com/micro/go-plugins/registry/etcd"
go run main.go --registry=etcd --registry_address=10.0.0.1:2379

Wrappers 中間件

客戶端和服務(wù)端都支持中間件的概念,稱為 wrapper。通過(guò)支持中間件,我們可以增加在請(qǐng)求和返回的業(yè)務(wù)邏輯前面或者后面,添加自定義的邏輯。

中間件是很容易理解的概念,數(shù)以千計(jì)的庫(kù)在使用它。在處理崩潰、限制并發(fā)、認(rèn)證、日志、記錄等場(chǎng)景下,很容易發(fā)現(xiàn)它的妙處。

# Client Wrappers
type Wrapper func(Client) Client
type StreamWrapper func(Streamer) Streamer

# Server Wrappers
type HandlerWrapper func(HandlerFunc) HandlerFunc
type SubscriberWrapper func(SubscriberFunc) SubscriberFunc
type StreamerWrapper func(Streamer) Streamer

怎樣使用 Wrapper

這里是一個(gè)很直接的插件

import (
    "github.com/micro/go-micro"
    "github.com/micro/go-plugins/wrapper/breaker/hystrix"
)

func main() {
    service := micro.NewService(
        micro.Name("myservice"),
        micro.WrapClient(hystrix.NewClientWrapper()),
    )
}

很容易對(duì)不對(duì),我們發(fā)現(xiàn)很多公司在 Micro 上層,創(chuàng)建了自己的層級(jí),用于初始化大部分默認(rèn)的 wrapper,所以所有的 wrapper 可以在同一個(gè)地方進(jìn)行添加。

現(xiàn)在我們看看 wrapper 怎樣讓?xiě)?yīng)用更有彈性,更能容錯(cuò)。

circuit breaker 斷路器

在SOA或者微服務(wù)世界,一個(gè)單獨(dú)的請(qǐng)求可能會(huì)調(diào)用多個(gè)服務(wù)。大部分情況下,聚合許多信息返回給調(diào)用者。在成功的情況下,它運(yùn)行的很好,但一旦發(fā)生錯(cuò)誤,很容易觸發(fā)雪崩式的錯(cuò)誤,除了重啟整個(gè)系統(tǒng),很難恢復(fù)。

我們部分的解決了這個(gè)問(wèn)題,通過(guò)在客戶端使用重試機(jī)制和黑名單。但在一些情況下,我們需要組織客戶端發(fā)起這個(gè)請(qǐng)求。

這里是 circuit breaker 怎樣起作用的

image.png

circuit breakers 的理念非常直接,方法的執(zhí)行是根據(jù)對(duì)失敗的情況進(jìn)行監(jiān)控而進(jìn)行封裝的。當(dāng)失敗的情況達(dá)到一個(gè)閾值時(shí),breaker 開(kāi)始起作用,任何未來(lái)的調(diào)用嘗試都會(huì)返回錯(cuò)誤,而不會(huì)調(diào)用實(shí)際的業(yè)務(wù)函數(shù)。在超時(shí)時(shí)間過(guò)了以后,進(jìn)入一個(gè)半開(kāi)狀態(tài)。如果某個(gè)請(qǐng)求失敗了,breaker 會(huì)再次生效,如果成功了就會(huì)恢復(fù)到正常。

雖然內(nèi)部的 Micro 客戶端有一些容錯(cuò)特性,但我們不應(yīng)該依賴它來(lái)解決所有問(wèn)題。在 wrapper 中使用 circuit breakers 讓我們受益很多。

Rate Limiting 速率限制 限流

如果我們非常輕松的能響應(yīng)世界上所有的請(qǐng)求,那就太好了,不過(guò)是在夢(mèng)里。真實(shí)的世界不是這樣工作的,執(zhí)行一個(gè)查詢需要消耗時(shí)間,資源的限制讓我們只能響應(yīng)一定數(shù)量的請(qǐng)求。

我們需要考慮限制發(fā)起請(qǐng)求的數(shù)量,或者限制并發(fā)響應(yīng)的數(shù)量。這就是 rate limiting 發(fā)揮作用的地方。如果沒(méi)有 rate limiting,很容易會(huì)把資源耗盡,或者完全的讓系統(tǒng)崩潰,讓系統(tǒng)不能響應(yīng)未來(lái)的任何請(qǐng)求。這經(jīng)常是 DDOS 攻擊的常見(jiàn)做法。

每個(gè)人都聽(tīng)說(shuō)過(guò),使用過(guò)或者實(shí)現(xiàn)過(guò)一些類(lèi)型的 rate limiting。這里有很多不同的算法,其中一種是 Leaky Bucket 算法,我們不會(huì)在這里展開(kāi),但值得一讀。

我們可以使用 Micro Wrapper 和已經(jīng)存在的庫(kù)來(lái)使用這個(gè)函數(shù),一個(gè)已經(jīng)存在的庫(kù)在這里。

我們實(shí)際上對(duì) YouTube 實(shí)現(xiàn)的 Doorman 算法很感興趣,一個(gè)全局的客戶端 rate limiter,我們也在尋求社區(qū)的其他實(shí)現(xiàn)。


服務(wù)端

前面介紹了很多客戶端的很多特性和使用方式,那么服務(wù)端呢,第一件事需要注意的是 Microgo-microAPI、CLI、Sidecar 等等都使用了客戶端,客戶端的特性讓整個(gè)架構(gòu)都收益,但我們?nèi)匀恍枰诜?wù)端解決一些問(wèn)題。

在客戶端,register 用于發(fā)現(xiàn)服務(wù),服務(wù)端進(jìn)行注冊(cè)。當(dāng)一個(gè)服務(wù)的實(shí)例運(yùn)行起來(lái)時(shí),它在服務(wù)發(fā)現(xiàn)系統(tǒng)進(jìn)行注冊(cè),在退出時(shí)進(jìn)行注銷(xiāo),關(guān)鍵詞是『gracefully』。

image.png

處理錯(cuò)誤

在分布式環(huán)境中,我們都需要處理錯(cuò)誤,我們需要容忍錯(cuò)誤。register 支持通過(guò)ttl來(lái)進(jìn)行過(guò)期檢查,一旦過(guò)期節(jié)點(diǎn)就是不健康的,底層的服務(wù)發(fā)現(xiàn)機(jī)制類(lèi)型 consul 都支持這些功能。同時(shí)服務(wù)端也支持重新注冊(cè)。這兩者的結(jié)合意味著,節(jié)點(diǎn)可以在間隔時(shí)間內(nèi)會(huì)重新注冊(cè),如果節(jié)點(diǎn)因?yàn)檫\(yùn)行失敗等等沒(méi)有重新注冊(cè),register 就會(huì)因?yàn)槌瑫r(shí)而認(rèn)為節(jié)點(diǎn)不健康,將節(jié)點(diǎn)從 register 刪除。

這種容錯(cuò)設(shè)計(jì)最先沒(méi)有出現(xiàn)在 go-micro 中,但我們很快發(fā)現(xiàn),在真實(shí)的世界中,因?yàn)榉?wù)的崩潰或其他原因程序退出時(shí),并沒(méi)有注銷(xiāo)自己,所以需要這種 ttl 健康監(jiān)測(cè)。

帶來(lái)的影響就是,客戶端需要處理一系列污染的請(qǐng)求??蛻舳艘残枰蒎e(cuò)性,我們認(rèn)為這樣的功能設(shè)計(jì)排除了許多明顯的問(wèn)題。

增加更多功能設(shè)計(jì)

另一件需要注意的事情是,服務(wù)端也提供了能力來(lái)使用 Wrapper 和中間件,這意味著我們也可以做 circuit breakingrate limiting 等其他一些特性。

服務(wù)端的這個(gè)功能故意的設(shè)計(jì)的簡(jiǎn)單,但插件化的特性可以讓你自由擴(kuò)展。

客戶端與Sidecar

大部分我們討論的都是存在于 go-micro 庫(kù)中,這對(duì)所有的 golang 使用者是很好的,但其他人在想,我怎樣從這里收益呢。

在最開(kāi)始,Micro 就包含了 Sidecar 的設(shè)計(jì)理念,這是一個(gè) HTTP 的代理,所有的 go-micro 的功能都內(nèi)置其中,所以不管你用哪種語(yǔ)言構(gòu)建你的應(yīng)用,你都可以收益于我們?cè)谏厦娴挠懻摗?/p>

image.png

sidecar 的設(shè)計(jì)模式并不是新東西,NetflixOSS 有一個(gè)叫做 Prana 的項(xiàng)目。Buoyant 有一個(gè)叫 Linkerd 的項(xiàng)目。

Micro Sidecar 使用了默認(rèn)的 go-micro 客戶端,如果你想使用其他功能,你可以添加參數(shù),很容易的重新編譯。我們會(huì)想辦法在未來(lái)簡(jiǎn)化這個(gè)程序。

還有更多

這里討論了許多 go-micro 的包和相關(guān)的工具,這些工具是很好的開(kāi)始,但他們還不夠。當(dāng)你想要運(yùn)行一個(gè)可擴(kuò)展的、數(shù)以百計(jì)的微服務(wù),處理數(shù)百萬(wàn)請(qǐng)求,仍然有許多問(wèn)題需要解決。

Platform

這是 go-platformplatform 發(fā)揮作用的地方了,micro 解決了基礎(chǔ)的組件,Platform 則更進(jìn)一步,解決運(yùn)行可擴(kuò)展的服務(wù)的更多問(wèn)題。比如認(rèn)證、分布式 trace、同步鎖、健康檢查等等。

分布式系統(tǒng)需要一系列的工具用于提高容錯(cuò)性,Platform 看起來(lái)會(huì)有幫助。通過(guò)提供一個(gè)分層的架構(gòu),我們可以在原始的核心工具上,構(gòu)建任何自己需要的功能。

Platform 仍然在早期,但 Platform 會(huì)解決大部分公司構(gòu)建分布式平臺(tái)時(shí)會(huì)遇到的問(wèn)題。

總結(jié)

科技在快速的進(jìn)化,云計(jì)算給了我們不受限制的擴(kuò)展能力。設(shè)法與變化保持同步很難,構(gòu)建一個(gè)可擴(kuò)展的,高容錯(cuò)的系統(tǒng)在今天仍然具有很大的挑戰(zhàn)。

但不應(yīng)該用以前的方式解決問(wèn)題,作為一個(gè)社區(qū),我們可以互相幫助,適應(yīng)這個(gè)新的環(huán)境,構(gòu)建隨著不斷增長(zhǎng)的需求而不斷擴(kuò)張的系統(tǒng)。

Micro 在這個(gè)過(guò)程中看起來(lái)提供了一些幫助,通過(guò)提供工具,簡(jiǎn)化了構(gòu)建和管理分布式系統(tǒng)。希望這個(gè)文章能示范我們處理這些問(wèn)題的方式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,069評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,873評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,635評(píng)論 6 408
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,128評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,365評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,733評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,935評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,172評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,582評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,821評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,595評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,908評(píng)論 2 372

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