grpc 源碼閱讀 —— 客戶端


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()的簡單包裝,指定了HelloRequestHelloReply為輸入輸出參數。

每次的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.http2Clienttransport.Streamtransport.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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM