Introduction
If you're only using gRPC at the application layer, I believe studying the examples on the gRPC official website is sufficient. However, when planning to extensively use gRPC within a team, you will face many challenges, such as authentication schemes between services, routing solutions for multi-region services, and compatibility solutions with existing RESTful services.
I recently realized that applying a technology stack requires mastering a wealth of information about that stack to ensure its stability in production use. This article starts with the most basic packet capturing and provides a simple introduction to the data flow of a gRPC call.
Tools and Source Code
- Wireshark: a packet capture tool
- grpc-go/examples/helloworld: gRPC official Golang version of helloworld, used in this article for gRPC calls
Packet Capturing Details
Firstly, it's important to understand that gRPC is a combination of HTTP/2 and Protocol Buffers(protobuf). Recognizing these two points makes packet capturing much more straightforward. For instance, when using Wireshark to capture packets, manually set unrecognized HTTP/2 protocols as HTTP/2 (otherwise, it will only interpret binary in TCP mode). Also, when viewing HTTP/2, do not expect the data to be displayed in the JSON format(protobuf uses its own compression algorithm).
Overview of a Single gRPC Call
From the above image, you can roughly see that in the gRPC helloworld example, when calling the server from the client side, there are multiple HTTP/2 requests. Broadly, they can be categorized as: Magic -> Settings -> Headers -> Data -> Settings -> Window-update, Ping -> Ping -> Headers, Data, Headers -> Window_update, ping -> Ping.
Settings
From the overview of the gRPC call, it can be observed that there are two sets of Settings, but both instances of Settings have the same data. The specific data is as follows:
A screenshot of the headers sent by gRPC for the request is shown below, revealing some details:
1. HTTP/2 header data is compressed.
2. The header includes details such as method (POST), scheme (http), path (/helloworld.Greeter/SayHello), content-type (application/grpc), and more.
Data
The Headers section mainly consists of data related to the client sending the request to the server. In the Data section, the server sends data to the client.
Another Settings
The second set of Settings is essentially the same as the first, except that the ACK flag is set to True
.
Window_update, Ping
It can be seen below that in a single HTTP/2 request, two stream blocks can be included.
Ping (Pong)
When the client sends a ping request to the server, the server responds with a pong. The above ping is initiated by the client, while the ping below is initiated by the server.
The data here represents the data sent from the server to the client (including header and body). The specific screenshot is shown below.
Window_update, Ping
It is noteworthy that not only can the client initiate a ping to the server, but the server can also initiate a ping to the client, as illustrated in the screenshot below.
Another Ping (Pong)
Of course, after the server initiates a ping operation, the client will initiate a pong operation.
Context Data in gRPC
If some data is added to the context when calling a server-side service from the client in gRPC, how is this data transmitted to the server? In reality, the data in these contexts is transmitted in the form of headers. For example, in the code shown in the image above, the key-value pair abc: ccc
is added to the context.
By capturing packets, it can be observed that the key-value pair abc: ccc
is written into the header, as shown in the image below:
Conclusion
This article captured packets from the gRPC helloworld example, tracing the potential data flow in a gRPC call. After studying the theoretical knowledge of gRPC and combining it with the content of this article, one should have a better understanding of gRPC, with a focus on HTTP/2 technology.
Reference: 抓包gRPC的细节及分析 - 敬维 (jingwei.link)