日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

f12控制台如何查看consul_基于 Consul 的 Go Micro 客户端服务发现是如何实现的

發布時間:2023/12/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 f12控制台如何查看consul_基于 Consul 的 Go Micro 客户端服务发现是如何实现的 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基于 Consul 的 Go Micro 客戶端服務發現是如何實現的

由 學院君 創建于1年前, 最后更新于 1年前

版本號 #1

上篇分享我們介紹了基于 Consul 作為注冊中心的 Go Micro 服務注冊底層實現原理,今天我們來看看 Go Micro 中客戶端服務發現是如何實現的。

客戶端服務發現要復雜一些,涉及到服務發現 Registry 和節點選擇 Selector 兩部分。

所謂服務發現指的是當我們從客戶端向指定服務發起請求時,可以通過名字識別服務,然后通過服務發現獲取到包含 IP 地址和端口號的對應遠程服務實例,遠程服務會在啟動時向注冊中心注冊,退出時注銷,客戶端無需關心這些細節,由 Go Micro 的 Registry 組件統一處理服務注冊與發現邏輯(這里,我們基于 Consul 作為 Registry 的具體實現插件)。

而節點選擇指的是,遠程服務實例通常部署在多個節點上,通過指定的服務名稱可以獲取到一個地址列表,節點選擇要做的事情是通過某種策略從列表中獲取指定的 IP 進行訪問,這就是 Go Micro 中 Selector 組件發揮作用的地方,它基于 Registry 組件實現,提供了負載均衡策略,比如輪詢或隨機,以及過濾、緩存和黑名單的功能。

下面我們還是通過分析客戶端調用底層源碼來看下 Go Micro 框架中服務發現與節點選擇的具體實現。首先打開 ~/go/hello/src/hello/client.go 文件,在 main 函數中,通過一系列的初始化操作后,真正發起服務調用的代碼是 greeter.Hello 函數調用:

func main() {

// Create a new service. Optionally include some options here.

service := micro.NewService(micro.Name("go.micro.cli.greeter"))

service.Init()

// Create new greeter client

greeter := proto.NewGreeterService("go.micro.srv.greeter", service.Client())

// Call the greeter

rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "學院君"})

if err != nil {

fmt.Println(err)

}

// Print response

fmt.Println(rsp.Greeting)

}

greeter.Hello 函數定義在 ~/go/hello/src/hello/proto/hello.micro.go 中:

func (c *greeterService) Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {

req := c.c.NewRequest(c.name, "Greeter.Hello", in)

out := new(HelloResponse)

err := c.c.Call(ctx, req, out, opts...)

if err != nil {

return nil, err

}

return out, nil

}

在這個函數中,通過 NewRequest 初始化了請求實例,包含服務名稱及請求端點、參數信息,然后初始化了響應實例,接下來是調用 Client 的 Call 函數,所有請求調用處理的核心邏輯(服務發現、節點選擇、請求處理、超時、重試、編碼)都在這個函數里,最終源碼對應 ~/go/hello/src/github.com/micro/go-micro/client/rpc_client.go 的 Call 函數,這個函數代碼量較大,我們選取一些關鍵片段進行解讀。

首先會通過 rpcClient 類的 next 方法獲取遠程服務節點,在未設置系統環境變量 MICRO_PROXY_ADDRESS 的情況下會執行 Selector 的 Select 方法獲取服務節點,默認的 Selector 初始化操作位于 ~/go/hello/src/github.com/micro/go-micro/client/options.go 的 newOptions 方法(該方法會在 client.go 的初始化操作中調用):

if opts.Selector == nil {

opts.Selector = selector.NewSelector(

selector.Registry(opts.Registry),

)

}

這里我們可以看到 Selector 依賴于 Registry 組件,如果沒有額外設置的話,基于系統默認的 Registry 實現(這里是 Consul),NewSelector 方法源碼如下:

func NewSelector(opts ...Option) Selector {

sopts := Options{

Strategy: Random,

}

for _, opt := range opts {

opt(&sopts)

}

if sopts.Registry == nil {

sopts.Registry = registry.DefaultRegistry

}

s := &registrySelector{

so: sopts,

}

s.rc = s.newCache()

return s

}

Selector 默認的負載均衡策略使用的是隨機算法(關于 Selector 支持的所有負載均衡算法后面我們還會單獨介紹),并且會在本地對節點選擇結果進行緩存。

回到 Selector 的 Select 函數,該函數源碼定義在 ~/go/hello/src/github.com/micro/go-micro/selector/default.go 中:

func (c *registrySelector) Select(service string, opts ...SelectOption) (Next, error) {

sopts := SelectOptions{

Strategy: c.so.Strategy,

}

for _, opt := range opts {

opt(&sopts)

}

// get the service

// try the cache first

// if that fails go directly to the registry

services, err := c.rc.GetService(service)

if err != nil {

return nil, err

}

// apply the filters

for _, filter := range sopts.Filters {

services = filter(services)

}

// if there's nothing left, return

if len(services) == 0 {

return nil, ErrNoneAvailable

}

return sopts.Strategy(services), nil

}

通過 c.rc.GetService(service) 傳入指定服務名稱,再通過默認 Registry 實現 Consul 獲取對應的服務實例列表并緩存(如果已緩存則直接返回提高性能,在通過 Registry 獲取服務節點列表時還會單獨跑一個協程去監聽服務注冊,如果有新節點注冊進來,則加到緩存中,如果有節點故障則刪除緩存中的節點信息,具體源碼位于 ~/go/hello/src/github.com/micro/go-micro/registry/cache/rcache.go),應用過濾器后最后通過默認負載均衡實現(這里是 Random 算法)返回指定節點,獲取到遠程服務實例節點后,就可以發起遠程服務請求了,回到 rpc_client.go 的 Call 函數,對應的遠程調用代碼邏輯實現片段如下:

call := func(i int) error {

...

// select next node

node, err := next()

if err != nil && err == selector.ErrNotFound {

return errors.NotFound("go.micro.client", "service %s: %v", request.Service(), err.Error())

} else if err != nil {

return errors.InternalServerError("go.micro.client", "error getting next %s node: %v", request.Service(), err.Error())

}

// make the call

err = rcall(ctx, node, request, response, callOpts)

r.opts.Selector.Mark(request.Service(), node, err)

return err

...

}

上述調用 rpcClient 的 next 函數返回的并不是真正的節點而是一個匿名函數,到 node, err := next() 這里才真正調用對應的函數返回遠程服務節點信息,如果返回節點成功則調用 rcall 函數(即 rpcClient 的 call 函數)發起遠程網絡請求(通過協程實現),如果請求處理出錯則返回相應錯誤信息,然后對服務調用成功與否通過 Selector 的 Mark 函數進行標記(以便后續對服務進行監控和治理),最后在 Call 函數中,也是通過協程發起對上述 call 匿名函數的調用:

...

for i := 0; i <= callOpts.Retries; i++ {

go func(i int) {

ch

}(i)

select {

case

return errors.Timeout("go.micro.client", fmt.Sprintf("call timeout: %v", ctx.Err()))

case err :=

// if the call succeeded lets bail early

if err == nil {

return nil

}

retry, rerr := callOpts.Retry(ctx, request, i, err)

if rerr != nil {

return rerr

}

if !retry {

return err

}

gerr = err

}

}

...

如果服務調用失敗,則進行重試或報錯處理。

以上就是在 Go Micro 體系內客戶端請求服務發現與節點選擇的底層實現,如果是以 HTTP 方式從外部通過 Micro API 網關形式對遠程服務發起請求,則 API 網關會將 HTTP 請求解析并轉化為默認的服務形式,比如 /greeter/say/hello 請求會被轉化為服務名為 go.micro.api.greeter,方法名為 Say.Hello 的請求,然后調用 go.micro.srv.greeter 遠程服務,后續處理邏輯與上面完全一致。請求處理完成后,返回處理結果給 API 網關,API 網關將其轉化為 HTTP 響應返回給調用客戶端。

總結

以上是生活随笔為你收集整理的f12控制台如何查看consul_基于 Consul 的 Go Micro 客户端服务发现是如何实现的的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。