Service定義
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
客戶端代碼
...
func main() {
conn, ... := grpc.Dial(address, ...)
c := pb.NewGreeterClient(conn)
c.SayHello(..., &pb.HelloRequest{Name: name})
}
grpc.Dial()
返回了一個grpc.ClientConn
對象(一個抽象的網絡連接)conn
,然后將conn
注入到helloworld.greeterClient
對象(由proto文件生成)c
,最終通過c
發起一次RPC調用SayHello
。
一次RPC調用經過了哪些代碼層次?
helloworld.greeterClient.SayHello()
只是對grpc.ClientConn.Invoke()
的簡單包裝,指定了HelloRequest
,HelloReply
為輸入輸出參數。
每次的grpc.ClientConn.Invoke()
調用,過程中會創建一個臨時的grpc.clientStream
對象,然后依次調用grpc.clientStream.SendMsg()
、grpc.clientStream.RecvMsg()
便完成了一次RPC調用,隨后grpc.clientStream
對象的生命周期結束。
grpc.ClientConn
層次之下是grpc.csAttempt
,含義為一次RPC調用的“意圖”,grpc.csAttempt
這一層次的封裝主要負責RPC的失敗重試。每次通過grpc.csAttempt
對象發起RPC通信,如若RPC通信失敗,則會重新構建grpc.csAttempt
(重新獲取下層網絡連接),然后進行重試。
grpc.clientStream.SendMsg()
實際上是調用grpc.csAttempt.sendMsg()
,外加失敗重試處理。近似的grpc.clientStream.RecvMsg()
對應grpc.csAttempt.recvMsg()
。
grpc.csAttempt
層次之下是transport.http2Client
和transport.Stream
,transport.Stream
負責對transport.http2Client
的分流處理。transport.http2Client
可被多個RPC Client復用,讀寫數據依據stream id分發到不同的transport.Stream
。
最后transport.http2Client
之下是http2協議http2.Framer
這里不做贅述。
調用層次樹狀圖
helloworld.greeterClient.SayHello()
grpc.ClientConn.Invoke()
grpc.clientStream = grpc.newClientStream()
grpc.csAttempt = grpc.clientStream.newAttemptLocked()
transport.http2Client = transport.newHTTP2Client()
http2.Framer = http2.NewFramer()
transport.Stream = transport.http2Client.NewStream()
grpc.clientStream.SendMsg()
grpc.csAttempt.sendMsg()
transport.http2Client.Write(transport.Stream)
http2.Framer.w.Write()
grpc.clientStream.RecvMsg()
grpc.csAttempt.recvMsg()
transport.Stream.Read()
http2.Framer.r.Read()