GRPC源碼解讀

GRPC源碼解讀

使用的protobuf文件

syntax = "proto3";

package servers;

// The greeter service definition.
service Greeter {
    // Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
    string name = 1;
}

// The response message containing the greetings
message HelloReply {
    string message = 1;
}

Client

鏈接

conn, err := grpc.Dial("localhost:8080", grpc.WithInsecure())

建立一個 ClientConn 並將傳入的 DialOption 應用到 ClientConndopts (dialOptions) 字段上。 設置默認的編解碼類 protoCodec, backoff配置,負載均衡策略(roundRobin)。服務器

從負載均衡器中拿到地址列表,啓動goroutine鏈接各個地址(看下面的<鏈接address>),主協程設置超時時間(根據 dopts.timeout)),在超時時間內等待鏈接完成。負載均衡

若是有地址列表監控Watcher(當負載均衡設置了naming.Resolver時會有),異步監控地址列表的變更(變更時更新 ClientConn的鏈接列表 conns)。異步

鏈接address

若是 dopts.insecure 爲false,檢查證書相關信息。編碼

將建立的 addrConn 放入到 ClientConnconns map中,並銷燬被替換的 addrConncode

重置 Transport:server

鏈接地址,一旦出錯,重試,重試間隔時間由 dopts.bs 指定。協程

若是沒出錯則調用負載均衡的Up方法(標記一下這個地址已經鏈接了而已)。rpc

監控 Transport: 若是有錯誤發生就重置 Transport(關閉以前的,從新鏈接一個)。源碼

調用方法

c := servers.NewGreeterClient(conn)
reply, err := c.SayHello(context.Background(), &servers.HelloRequest{"person"})

建立Client沒有什麼東西。string

調用 SayHello 時主要代碼就下面這句:

grpc.Invoke(ctx, "/servers.Greeter/SayHello", in, out, c.cc, opts...)

ClientConn 中獲取 Transport

利用獲取到的transport 建立一個 Stream, Stream的id每次遞增2,將 Stream 保存在transport的activeStreams中。設置各類 header 字段。將 header 按照 frame 發送給服務端以開啓一個stream,frame最大16KB。

HelloRequest 編碼寫到 stream 中。

等待讀取服務器的相應到 HelloReply

最後關閉 stream

roundRobin

Start

默認是沒有指定 naming.Resolver 的,因此 Start 只是將地址放入到 addrs 字段中。

若是指定了 naming.Resolver, 會調用它返回一個 Watcher,而後啓動 goroutine,循環從 Watcher 中獲取地址變更的信息(增長或刪除地址),一旦地址列表變更了,就將新的地址列表發給 addrCh 這個channel。

Up

標記地址是已經鏈接的了。

Get

獲取上一次調用時拿到的地址的下一個地址。

若是獲取不到地址,就建立 waitCh 而後等待有人關閉這個 waitChUpClose 方法都會檢測並關閉 waitCh

相關文章
相關標籤/搜索